dockapps/AlsaMixer.app/Mixer.cc

600 lines
16 KiB
C++
Raw Normal View History

//
Clarify project copyright and license, use SPDX Changes/additions in AlsaMixer.app over Mixer.app were lacking a copyright information and and license specifications. Add the missing bits, using a SPDX-License-Identifier. Documentation for the change follows. --------------------------------------------------- From petr.hlavka@avast.com Wed May 2 10:57:44 2018 Delivery-date: Wed, 02 May 2018 08:57:44 +0000 Received: from muffat.debian.org ([209.87.16.33]) by vsrv21575.customer.vlinux.de with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.91) (envelope-from <petr.hlavka@avast.com>) id 1fDna2-0005LT-O4 for ametzler@bebt.de; Wed, 02 May 2018 08:57:44 +0000 Received: from mail-qk0-x235.google.com ([2607:f8b0:400d:c09::235]) by muffat.debian.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from <petr.hlavka@avast.com>) id 1fDna0-0001VT-VK for ametzler@bebt.de; Wed, 02 May 2018 08:57:41 +0000 Received: by mail-qk0-x235.google.com with SMTP id c70so10628010qkg.0 for <ametzler@debian.org>; Wed, 02 May 2018 01:57:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=avast.com; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=todeyYOMQgF5NFi+g8Ch3ff7DLqVyjdpO1jnkiSCnwQ=; b=dTOhJ1+p5j29A0wiZExWtmDgNHdAYz4TBYldVuTScFHsdG2sEnQQJ0jhLcdJBZWtB/ f9zbg70xN2O++EiXmWzHO///LWZQVvmqxRfWe9e9NinQiftLvebLt0qhNDqGurm0XGuR ElxIv7xaik7A76zuy4RiWLBQPJImsdbkj8w8o= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=todeyYOMQgF5NFi+g8Ch3ff7DLqVyjdpO1jnkiSCnwQ=; b=QruIZh5tAR6Ob3A5x4497372oBuHE3qBVI4pMDCb11By/sgVj7VWrzFcEzBKa+sZak J5y4nddBXL7usk4ULNYROXWym6dbjgcqqCX7nEdIQvze9FW7+bM/JMR+a69dxP2MFmVr v2P9F0xCyiU8MLXlvMQqgwmTPuyNAQgHledmWGWFzBjbKgJb7LDwM7Hs3aU7fTyRJm+1 Ue4obJVABrLq398pXAlqupNDMb4F4Ss6/HcBxKhFKugxv5dRNCJFB0VPWl+/L/8qA6Dm 1rUSVtcpoLdD1Tv+wZY9+rnzR4WVj/u/0JPhWIiH4UK4oeq0cLLEiUlVx3z5ZW4/xnlb cmmw== X-Gm-Message-State: ALQs6tCW+VHY1vjrOxqi926/NtpVquOr/uyKzag66grdOQjv2d3QOHcx ITgzzFb/gW/K1WQYcwUDIpKXhav0rQUGhXagXfLCYjezYz8= X-Google-Smtp-Source: AB8JxZrk2YDpWABvmBchDvRP6pMGHcJOS47obZEdkq/pZa72T3z10UOShV65Z5FzTjgF7CmqxSk2hmMpKTIzLbef3mA= X-Received: by 10.55.120.68 with SMTP id t65mr15084912qkc.56.1525251456867; Wed, 02 May 2018 01:57:36 -0700 (PDT) MIME-Version: 1.0 Received: by 10.12.152.219 with HTTP; Wed, 2 May 2018 01:57:36 -0700 (PDT) In-Reply-To: <20180430125042.GA1331@argenau.bebt.de> References: <20180430125042.GA1331@argenau.bebt.de> From: =?UTF-8?Q?Hl=C3=A1vka=2C_Petr?= <petr.hlavka@avast.com> Date: Wed, 2 May 2018 10:57:36 +0200 Message-ID: <CACiAdzoA3hsfNG_5Xm-2wYJyZaEYH=xhK=8BrUq5YWVZRYncDg@mail.gmail.com> Subject: Re: AlsaMixer.app - license? To: Andreas Metzler <ametzler@debian.org> Content-Type: multipart/alternative; boundary="94eb2c0a95da487efd056b354749" Status: RO X-Status: A Content-Length: 3528 --94eb2c0a95da487efd056b354749 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello Andreas, yes, I'm the author of modification to original Mixer.app (AlsaMixer.app). They should be licensed under the same license as Mixer.app, some info is available in http://repo.or.cz/dockapps.git/blob_plain/HEAD:/AlsaMixer.app/README , section Copyright. Regards, Petr Hlavka. On Mon, Apr 30, 2018 at 2:50 PM, Andreas Metzler <ametzler@debian.org> wrote: > Dear Mr Hl=C3=A1vka, > > I guess that you are the original author of AlsaMixer.app > <https://www.dockapps.net/alsamixerapp>. If that is not case I am > sorry for bothering you unnecessaly but would appreciate if you told > me. - Thanks in advance > > On the other hand if you are the author it would be helpful if you could > clarify the question of licensing. AlsaMixer.app is based on Mixer.app > which is licensed under GNU General Public License version 2 or later. > The modifications and additions for AlsaMixer.app only a carry a > copyright info but no licensing info: > > Copyright > -------------------------------------------------------------- > AlsaMixer.app, 2004, Petr Hlavka > [...] > // AChannel.cc, Petr Hlavka, 2004 > > I guess that your contributions are also available under GPL v2 or > later. Could you confirm this? > > Thanks in advance, kind Regards > > Andreas Metzler > --94eb2c0a95da487efd056b354749 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">Hello Andreas,<div><br></div><div>yes, I&#39;m the author = of modification to original Mixer.app (AlsaMixer.app). They should be licen= sed under the same license as Mixer.app, some info is available in=C2=A0<a = href=3D"http://repo.or.cz/dockapps.git/blob_plain/HEAD:/AlsaMixer.app/READM= E">http://repo.or.cz/dockapps.git/blob_plain/HEAD:/AlsaMixer.app/README</a>= , section Copyright.</div><div><br></div><div>=C2=A0 Regards, Petr Hlavka.= </div></div><div class=3D"gmail_extra"><br><div class=3D"gmail_quote">On Mo= n, Apr 30, 2018 at 2:50 PM, Andreas Metzler <span dir=3D"ltr">&lt;<a href= =3D"mailto:ametzler@debian.org" target=3D"_blank">ametzler@debian.org</a>&g= t;</span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0= .8ex;border-left:1px #ccc solid;padding-left:1ex">Dear Mr Hl=C3=A1vka,<br> <br> I guess that you are the original author of AlsaMixer.app<br> &lt;<a href=3D"https://www.dockapps.net/alsamixerapp" rel=3D"noreferrer" ta= rget=3D"_blank">https://www.dockapps.net/<wbr>alsamixerapp</a>&gt;. If that= is not case I am <br> sorry for bothering you unnecessaly but would appreciate if you told<br> me. - Thanks in advance<br> <br> On the other hand if you are the author it would be helpful if you could<br= > clarify the question of licensing. AlsaMixer.app is based on Mixer.app<br> which is licensed under GNU General Public License version 2 or later.<br> The modifications and additions for AlsaMixer.app only a carry a<br> copyright info but no licensing info:<br> <br> Copyright<br> ------------------------------<wbr>------------------------------<wbr>--<br= > AlsaMixer.app, 2004, Petr Hlavka<br> [...]<br> // AChannel.cc, Petr Hlavka, 2004<br> <br> I guess that your contributions are also available under GPL v2 or<br> later. Could you confirm this?<br> <br> Thanks in advance, kind Regards<br> <span class=3D"HOEnZb"><font color=3D"#888888"><br> Andreas Metzler<br> </font></span></blockquote></div><br></div>
2018-05-10 10:35:57 +00:00
// Mixer.app / AlsaMixer.app
2014-10-05 15:29:59 +00:00
//
// Copyright (c) 1998-2002 Per Liden
Clarify project copyright and license, use SPDX Changes/additions in AlsaMixer.app over Mixer.app were lacking a copyright information and and license specifications. Add the missing bits, using a SPDX-License-Identifier. Documentation for the change follows. --------------------------------------------------- From petr.hlavka@avast.com Wed May 2 10:57:44 2018 Delivery-date: Wed, 02 May 2018 08:57:44 +0000 Received: from muffat.debian.org ([209.87.16.33]) by vsrv21575.customer.vlinux.de with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.91) (envelope-from <petr.hlavka@avast.com>) id 1fDna2-0005LT-O4 for ametzler@bebt.de; Wed, 02 May 2018 08:57:44 +0000 Received: from mail-qk0-x235.google.com ([2607:f8b0:400d:c09::235]) by muffat.debian.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from <petr.hlavka@avast.com>) id 1fDna0-0001VT-VK for ametzler@bebt.de; Wed, 02 May 2018 08:57:41 +0000 Received: by mail-qk0-x235.google.com with SMTP id c70so10628010qkg.0 for <ametzler@debian.org>; Wed, 02 May 2018 01:57:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=avast.com; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=todeyYOMQgF5NFi+g8Ch3ff7DLqVyjdpO1jnkiSCnwQ=; b=dTOhJ1+p5j29A0wiZExWtmDgNHdAYz4TBYldVuTScFHsdG2sEnQQJ0jhLcdJBZWtB/ f9zbg70xN2O++EiXmWzHO///LWZQVvmqxRfWe9e9NinQiftLvebLt0qhNDqGurm0XGuR ElxIv7xaik7A76zuy4RiWLBQPJImsdbkj8w8o= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=todeyYOMQgF5NFi+g8Ch3ff7DLqVyjdpO1jnkiSCnwQ=; b=QruIZh5tAR6Ob3A5x4497372oBuHE3qBVI4pMDCb11By/sgVj7VWrzFcEzBKa+sZak J5y4nddBXL7usk4ULNYROXWym6dbjgcqqCX7nEdIQvze9FW7+bM/JMR+a69dxP2MFmVr v2P9F0xCyiU8MLXlvMQqgwmTPuyNAQgHledmWGWFzBjbKgJb7LDwM7Hs3aU7fTyRJm+1 Ue4obJVABrLq398pXAlqupNDMb4F4Ss6/HcBxKhFKugxv5dRNCJFB0VPWl+/L/8qA6Dm 1rUSVtcpoLdD1Tv+wZY9+rnzR4WVj/u/0JPhWIiH4UK4oeq0cLLEiUlVx3z5ZW4/xnlb cmmw== X-Gm-Message-State: ALQs6tCW+VHY1vjrOxqi926/NtpVquOr/uyKzag66grdOQjv2d3QOHcx ITgzzFb/gW/K1WQYcwUDIpKXhav0rQUGhXagXfLCYjezYz8= X-Google-Smtp-Source: AB8JxZrk2YDpWABvmBchDvRP6pMGHcJOS47obZEdkq/pZa72T3z10UOShV65Z5FzTjgF7CmqxSk2hmMpKTIzLbef3mA= X-Received: by 10.55.120.68 with SMTP id t65mr15084912qkc.56.1525251456867; Wed, 02 May 2018 01:57:36 -0700 (PDT) MIME-Version: 1.0 Received: by 10.12.152.219 with HTTP; Wed, 2 May 2018 01:57:36 -0700 (PDT) In-Reply-To: <20180430125042.GA1331@argenau.bebt.de> References: <20180430125042.GA1331@argenau.bebt.de> From: =?UTF-8?Q?Hl=C3=A1vka=2C_Petr?= <petr.hlavka@avast.com> Date: Wed, 2 May 2018 10:57:36 +0200 Message-ID: <CACiAdzoA3hsfNG_5Xm-2wYJyZaEYH=xhK=8BrUq5YWVZRYncDg@mail.gmail.com> Subject: Re: AlsaMixer.app - license? To: Andreas Metzler <ametzler@debian.org> Content-Type: multipart/alternative; boundary="94eb2c0a95da487efd056b354749" Status: RO X-Status: A Content-Length: 3528 --94eb2c0a95da487efd056b354749 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello Andreas, yes, I'm the author of modification to original Mixer.app (AlsaMixer.app). They should be licensed under the same license as Mixer.app, some info is available in http://repo.or.cz/dockapps.git/blob_plain/HEAD:/AlsaMixer.app/README , section Copyright. Regards, Petr Hlavka. On Mon, Apr 30, 2018 at 2:50 PM, Andreas Metzler <ametzler@debian.org> wrote: > Dear Mr Hl=C3=A1vka, > > I guess that you are the original author of AlsaMixer.app > <https://www.dockapps.net/alsamixerapp>. If that is not case I am > sorry for bothering you unnecessaly but would appreciate if you told > me. - Thanks in advance > > On the other hand if you are the author it would be helpful if you could > clarify the question of licensing. AlsaMixer.app is based on Mixer.app > which is licensed under GNU General Public License version 2 or later. > The modifications and additions for AlsaMixer.app only a carry a > copyright info but no licensing info: > > Copyright > -------------------------------------------------------------- > AlsaMixer.app, 2004, Petr Hlavka > [...] > // AChannel.cc, Petr Hlavka, 2004 > > I guess that your contributions are also available under GPL v2 or > later. Could you confirm this? > > Thanks in advance, kind Regards > > Andreas Metzler > --94eb2c0a95da487efd056b354749 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">Hello Andreas,<div><br></div><div>yes, I&#39;m the author = of modification to original Mixer.app (AlsaMixer.app). They should be licen= sed under the same license as Mixer.app, some info is available in=C2=A0<a = href=3D"http://repo.or.cz/dockapps.git/blob_plain/HEAD:/AlsaMixer.app/READM= E">http://repo.or.cz/dockapps.git/blob_plain/HEAD:/AlsaMixer.app/README</a>= , section Copyright.</div><div><br></div><div>=C2=A0 Regards, Petr Hlavka.= </div></div><div class=3D"gmail_extra"><br><div class=3D"gmail_quote">On Mo= n, Apr 30, 2018 at 2:50 PM, Andreas Metzler <span dir=3D"ltr">&lt;<a href= =3D"mailto:ametzler@debian.org" target=3D"_blank">ametzler@debian.org</a>&g= t;</span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0= .8ex;border-left:1px #ccc solid;padding-left:1ex">Dear Mr Hl=C3=A1vka,<br> <br> I guess that you are the original author of AlsaMixer.app<br> &lt;<a href=3D"https://www.dockapps.net/alsamixerapp" rel=3D"noreferrer" ta= rget=3D"_blank">https://www.dockapps.net/<wbr>alsamixerapp</a>&gt;. If that= is not case I am <br> sorry for bothering you unnecessaly but would appreciate if you told<br> me. - Thanks in advance<br> <br> On the other hand if you are the author it would be helpful if you could<br= > clarify the question of licensing. AlsaMixer.app is based on Mixer.app<br> which is licensed under GNU General Public License version 2 or later.<br> The modifications and additions for AlsaMixer.app only a carry a<br> copyright info but no licensing info:<br> <br> Copyright<br> ------------------------------<wbr>------------------------------<wbr>--<br= > AlsaMixer.app, 2004, Petr Hlavka<br> [...]<br> // AChannel.cc, Petr Hlavka, 2004<br> <br> I guess that your contributions are also available under GPL v2 or<br> later. Could you confirm this?<br> <br> Thanks in advance, kind Regards<br> <span class=3D"HOEnZb"><font color=3D"#888888"><br> Andreas Metzler<br> </font></span></blockquote></div><br></div>
2018-05-10 10:35:57 +00:00
// Copyright (C) 2004, Petr Hlavka
2014-10-05 15:29:59 +00:00
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
2014-10-05 15:29:59 +00:00
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307,
// USA.
//
#include <X11/Xlib.h>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <csignal>
#include "Xpm.h"
#include "Mixer.h"
#include "AMixer/AMixer.h"
#include "pixmaps/main.xpm"
#include "pixmaps/button.xpm"
#include "pixmaps/mutebutton.xpm"
#include "pixmaps/redlight.xpm"
#define ROUND_POS(x) (int ((x) + 0.5) > int (x)) ? (int) ((x) + 1) : (int) (x)
using namespace std;
static const int ButtonX[] = {6, 24, 42};
static const char* MixerSources[] = { "Master", "PCM", "CD" };
extern Mixer* app;
2014-10-05 15:29:59 +00:00
void catchBrokenPipe(int sig)
{
app->saveVolumeSettings();
exit(0);
}
int positionToPercent(int position) {
return ROUND_POS(100 - (((position - BUTTON_MAX) * 100.0) / (BUTTON_MIN - BUTTON_MAX)));
}
int percentToPosition(int percent) {
return ROUND_POS(BUTTON_MIN - (percent * (BUTTON_MIN - BUTTON_MAX)) / 100.0);
}
2014-10-05 15:29:59 +00:00
Mixer::Mixer(int argc, char** argv)
{
XClassHint classHint;
XSizeHints sizeHints;
XWMHints wmHints;
Atom deleteWindow;
Xpm* image;
char* displayName = NULL;
char* card = "default";
mError = 0;
mInstanceName = INSTANCENAME;
mVolumeSource[0] = -1;
mVolumeSource[1] = -1;
mVolumeSource[2] = -1;
mVolumeMute[0] = 0;
mVolumeMute[1] = 0;
mVolumeMute[2] = 0;
mWheelButton = 1;
mLabelText = 0;
mSettingsFile = 0;
mSaveSettings = false;
mLoadSettings = false;
mCommand = NULL;
// Parse command line
if (argc>1) {
for (int i=1; i<argc; i++) {
// Display
if (!strcmp(argv[i], "-d")) {
checkArgument(argv, argc, i);
displayName = argv[i+1];
i++;
}
// Sound source
else if (!strcmp(argv[i], "-1") || !strcmp(argv[i], "-2") || !strcmp(argv[i], "-3")) {
checkArgument(argv, argc, i);
MixerSources[argv[i][1] - '1'] = argv[i + 1];
i++;
}
// Wheel binding
else if (!strcmp(argv[i], "-w")) {
checkArgument(argv, argc, i);
mWheelButton = atoi(argv[i+1]);
if (mWheelButton < 1 || mWheelButton > 3) {
cerr << APPNAME << ": invalid wheel binding, must be 1, 2 or 3, not " << argv[i+1] << endl;
tryHelp(argv[0]);
exit(0);
}
i++;
}
// Label text
else if (!strcmp(argv[i], "-l")) {
checkArgument(argv, argc, i);
mLabelText = argv[i+1];
i++;
}
// Save settings on exit
else if (!strcmp(argv[i], "-S")) {
mSaveSettings = true;
}
// Load settings on startup
else if (!strcmp(argv[i], "-L")) {
mLoadSettings = true;
}
// Load/Save settings file
else if (!strcmp(argv[i], "-f")) {
checkArgument(argv, argc, i);
mSettingsFile = argv[i+1];
i++;
}
// Execute command on middle click
else if (!strcmp(argv[i], "-e")) {
checkArgument(argv, argc, i);
mCommand = argv[i + 1];
i++;
}
// Instance name
else if (!strcmp(argv[i], "-n")) {
checkArgument(argv, argc, i);
mInstanceName = argv[i+1];
i++;
}
// Version
else if (!strcmp(argv[i], "-v")) {
cerr << APPNAME << " version " << VERSION << endl;
exit(0);
}
// Help
else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
showHelp();
exit(0);
}
// card
else if (!strcmp(argv[i], "--card")) {
card = AMixer::convertIDToCard(argv[i + 1]);
if (!card) {
cerr << APPNAME << ": invalid card number '" << argv[i + 1] << "'" << endl;
tryHelp(argv[0]);
exit(0);
}
i++;
}
// device
else if (!strcmp(argv[i], "--device")) {
card = argv[i + 1];
i++;
}
// Unknown option
else {
cerr << APPNAME << ": invalid option '" << argv[i] << "'" << endl;
tryHelp(argv[0]);
exit(0);
}
}
}
// default settings file
if (!mSettingsFile) {
char* home = getenv("HOME");
if (home) {
mSettingsFile = new char[strlen(home) + strlen(SETTINGS) + 1];
strcpy(mSettingsFile, home);
strcat(mSettingsFile, SETTINGS);
} else {
cerr << APPNAME << ": $HOME not set, could not find saved settings" << endl;
}
}
// init mixer
aMixer = new AMixer(card);
if (!aMixer->opened()) {
cerr << APPNAME << ": could not open mixer device for card '" << card << "'" << endl;
exit(0);
}
// open mixer sources
for (int i = 0; i < 3; i++) {
aMixer->attachItem(i, MixerSources[i]);
if (!aMixer->itemOK(i))
cerr << APPNAME << ": could not select mixer source '" << MixerSources[i] << "'" << endl;
}
// Open display
if ((mDisplay = XOpenDisplay(displayName)) == NULL) {
cerr << APPNAME << ": could not open display " << displayName << endl;
exit(0);
}
2014-10-05 15:29:59 +00:00
// Get root window
mRoot = RootWindow(mDisplay, DefaultScreen(mDisplay));
// Create windows
mAppWin = XCreateSimpleWindow(mDisplay, mRoot, 1, 1, 64, 64, 0, 0, 0);
mIconWin = XCreateSimpleWindow(mDisplay, mAppWin, 0, 0, 64, 64, 0, 0, 0);
// Set classhint
classHint.res_name = mInstanceName;
classHint.res_class = CLASSNAME;
XSetClassHint(mDisplay, mAppWin, &classHint);
// Create delete atom
deleteWindow = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False);
XSetWMProtocols(mDisplay, mAppWin, &deleteWindow, 1);
XSetWMProtocols(mDisplay, mIconWin, &deleteWindow, 1);
// Set windowname
XStoreName(mDisplay, mAppWin, APPNAME);
XSetIconName(mDisplay, mAppWin, APPNAME);
// Set sizehints
sizeHints.flags= USPosition;
sizeHints.x = 0;
sizeHints.y = 0;
XSetWMNormalHints(mDisplay, mAppWin, &sizeHints);
// Set wmhints
wmHints.initial_state = WithdrawnState;
wmHints.icon_window = mIconWin;
wmHints.icon_x = 0;
wmHints.icon_y = 0;
wmHints.window_group = mAppWin;
wmHints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
XSetWMHints(mDisplay, mAppWin, &wmHints);
// Set command
XSetCommand(mDisplay, mAppWin, argv, argc);
// Set background image
image = new Xpm(mDisplay, mRoot, main_xpm);
if (mLabelText) {
image->drawString(LABEL_X, LABEL_Y, mLabelText);
}
image->setWindowPixmapShaped(mIconWin);
delete image;
// Create buttons
mButton[0] = XCreateSimpleWindow(mDisplay, mIconWin, ButtonX[0], BUTTON_MIN, 5, 5, 0, 0, 0);
mButton[1] = XCreateSimpleWindow(mDisplay, mIconWin, ButtonX[1], BUTTON_MIN, 5, 5, 0, 0, 0);
mButton[2] = XCreateSimpleWindow(mDisplay, mIconWin, ButtonX[2], BUTTON_MIN, 5, 5, 0, 0, 0);
image = new Xpm(mDisplay, mRoot, button_xpm);
image->setWindowPixmap(mButton[0]);
image->setWindowPixmap(mButton[1]);
image->setWindowPixmap(mButton[2]);
delete image;
XSelectInput(mDisplay, mButton[0], ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
XSelectInput(mDisplay, mButton[1], ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
XSelectInput(mDisplay, mButton[2], ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
XSelectInput(mDisplay, mIconWin, ButtonPressMask);
XMapWindow(mDisplay, mButton[0]);
XMapWindow(mDisplay, mButton[1]);
XMapWindow(mDisplay, mButton[2]);
XMapWindow(mDisplay, mIconWin);
XMapWindow(mDisplay, mAppWin);
XSync(mDisplay, False);
// Catch broker pipe signal
signal(SIGPIPE, catchBrokenPipe);
// Check if error
if (mError) {
showErrorLed();
} else {
getVolume();
if (mLoadSettings)
loadVolumeSettings();
}
}
void Mixer::tryHelp(char* appname)
{
cerr << "Try `" << appname << " --help' for more information" << endl;
}
2014-10-05 15:29:59 +00:00
void Mixer::showHelp()
{
cerr << APPNAME << " Copyright (c) 1998-2002 by Per Liden (per@fukt.bth.se), Petr Hlavka (xhlavk00@stud.fit.vutbr.cz)" << endl << endl
<< "options:" << endl
<< " -1 <source> set sound source for control 1 (default is Master)" << endl
<< " -2 <source> set sound source for control 2 (default is PCM)" << endl
<< " -3 <source> set sound source for control 3 (default is CD)" << endl
<< " -w 1|2|3 bind a control button to the mouse wheel (default is 1)" << endl
<< " -l <text> set label text" << endl
<< " -S save volume settings on exit" << endl
<< " -L load volume settings on start up" << endl
<< " -f <file> use setting <file> instead of ~/GNUstep/Defaults/AlsaMixer" << endl
<< " --card <id> select card" << endl
<< " --device <dev> select device, default 'default'" << endl
<< " -e <command> execute <command> on middle click" << endl
<< " -n <name> set client instance name" << endl
<< " -d <disp> set display" << endl
<< " -v print version and exit" << endl
<< " -h, --help display this help and exit" << endl << endl;
}
void Mixer::checkArgument(char** argv, int argc, int index)
{
if (argc-1 < index+1) {
cerr << APPNAME << ": option '" << argv[index] << "' requires an argument" << endl;
tryHelp(argv[0]);
exit(0);
}
}
2014-10-05 15:29:59 +00:00
void Mixer::showErrorLed()
{
Window led;
Xpm* image;
led = XCreateSimpleWindow(mDisplay, mIconWin, LED_X, LED_Y, 3, 2, 0, 0, 0);
// Set background image
image = new Xpm(mDisplay, mRoot, redlight_xpm);
image->setWindowPixmap(led);
delete image;
// Show window
XMapWindow(mDisplay, led);
mError = 1;
}
void Mixer::loadVolumeSettings()
{
if (mSettingsFile) {
ifstream file(mSettingsFile);
if (file) {
// This could fail if the user has edited the file by hand and destroyed the structure
char dummy[1024];
file >> dummy; // {
file >> dummy; // Volume1
file >> dummy; // =
file >> mVolume[0];
file >> dummy; // ;
file >> dummy; // Volume2
file >> dummy; // =
file >> mVolume[1];
file >> dummy; // ;
file >> dummy; // Volume3
file >> dummy; // =
file >> mVolume[2];
file.close();
for (int i = 0; i < 3; i++) {
setVolume(i, mVolume[i]);
setButtonPosition(i, percentToPosition(mVolume[i]));
}
}
}
}
void Mixer::saveVolumeSettings()
{
if (mSaveSettings) {
ofstream file(mSettingsFile);
if (file) {
// Files in ~/GNUstep/Defaults/ should follow the property list format
2014-10-05 15:29:59 +00:00
file << "{" << endl
<< " Volume1 = " << mVolumePos[0] << ";" << endl
<< " Volume2 = " << mVolumePos[1] << ";" << endl
<< " Volume3 = " << mVolumePos[2] << ";" << endl
<< "}" << endl;
file.close();
} else {
cerr << APPNAME << ": failed to save volume settings in " << mSettingsFile << endl;
}
}
}
2014-10-05 15:29:59 +00:00
void Mixer::getVolume()
{
static int lastVolume[3] = {-1, -1, -1};
static int lastVolumeMute[3] = {-1, -1, -1};
if (mError) {
return;
}
// Read from device
for (int i=0; i<3; i++) {
mVolume[i] = aMixer->itemGetVolume(i);
mVolumeMute[i] = aMixer->itemIsMuted(i);
if (lastVolume[i] != mVolume[i]) {
int y;
// Set button position
if (mError) {
y = BUTTON_MIN;
} else {
y = percentToPosition(mVolume[i]);
}
setButtonPosition(i, y);
lastVolume[i] = mVolume[i];
}
// set buttom type muted/unmuted
if (lastVolumeMute[i] != mVolumeMute[i]) {
setButtonType(i);
lastVolumeMute[i] = mVolumeMute[i];
}
}
if (mError) {
cerr << APPNAME << ": unable to read from " << mMixerDevice << endl;
showErrorLed();
return;
}
}
2014-10-05 15:29:59 +00:00
void Mixer::setVolume(int button, int volume)
{
if (mError) {
return;
}
// Store volume
mVolume[button] = volume;
// Write to device
aMixer->itemSetVolume(button, mVolume[button]);
}
void Mixer::toggleMute(int button)
{
aMixer->itemToggleMute(button);
mVolumeMute[button] = aMixer->itemIsMuted(button);
setButtonType(button);
}
2014-10-05 15:29:59 +00:00
void Mixer::setButtonType(int button)
{
Xpm* image;
if (mVolumeMute[button] == 1) { // muted
image = new Xpm(mDisplay, mRoot, mutebutton_xpm);
image->setWindowPixmap(mButton[button]);
delete image;
XClearWindow(mDisplay, mButton[button]);
} else {
image = new Xpm(mDisplay, mRoot, button_xpm);
image->setWindowPixmap(mButton[button]);
delete image;
XClearWindow(mDisplay, mButton[button]);
}
}
void Mixer::setButtonPosition(int button, int position) {
if (position > BUTTON_MIN) {
position = BUTTON_MIN;
} else if (position < BUTTON_MAX) {
position = BUTTON_MAX;
}
XMoveWindow(mDisplay, mButton[button], ButtonX[button], position);
mVolumePos[button] = position;
}
2014-10-05 15:29:59 +00:00
void Mixer::setButtonPositionRelative(int button, int relativePosition)
{
int y;
2014-10-05 15:29:59 +00:00
// Calc new button position
y = mVolumePos[button] + relativePosition;
if (y > BUTTON_MIN) {
y = BUTTON_MIN;
} else if (y < BUTTON_MAX) {
y = BUTTON_MAX;
}
2014-10-05 15:29:59 +00:00
// Set button position and volume
XMoveWindow(mDisplay, mButton[button], ButtonX[button], y);
mVolumePos[button] = y;
2014-10-05 15:29:59 +00:00
// set volume
setVolume(button, positionToPercent(y));
}
2014-10-05 15:29:59 +00:00
void Mixer::run()
{
XEvent event;
int buttonDown = 0;
int buttonDownPosition = 0;
// Start handling events
while(1) {
while(XPending(mDisplay) || buttonDown) {
XNextEvent(mDisplay, &event);
2014-10-05 15:29:59 +00:00
switch(event.type) {
case ButtonPress:
if (event.xbutton.button == Button4 || event.xbutton.button == Button5) {
// Wheel scroll
setButtonPositionRelative(mWheelButton - 1, event.xbutton.button == Button5? 3: -3);
} else if (event.xbutton.button == Button1 && event.xbutton.window != mIconWin) {
// Volume change
buttonDown = 1;
buttonDownPosition = event.xbutton.y;
} else if (event.xbutton.button == Button3 && buttonDown == 0 && event.xbutton.window != mIconWin) {
// Mute
for (int i=0; i<3; i++) {
if (mButton[i] == event.xbutton.window) {
toggleMute(i);
break;
}
}
} else if (event.xbutton.button == Button2) {
// Load defaults or execute command
if (mCommand) {
char command[512];
snprintf(command, 512, "%s &", mCommand);
system(command);
}
else
loadVolumeSettings();
}
break;
2014-10-05 15:29:59 +00:00
case ButtonRelease:
if (event.xbutton.button == Button1) {
buttonDown = 0;
}
break;
2014-10-05 15:29:59 +00:00
case MotionNotify:
if (buttonDown) {
// Find button
for (int i=0; i<3; i++) {
if (mButton[i] == event.xmotion.window) {
setButtonPositionRelative(i, event.xmotion.y - buttonDownPosition);
break;
}
}
}
break;
}
}
// Idle for a moment
usleep(100000);
// Update volume status
aMixer->handleEvents();
if (AMixer::mixerChanged())
aMixer->reInit();
else if (AMixer::mixerElemsChanged())
getVolume();
XSync(mDisplay, False);
}
}