summaryrefslogtreecommitdiffstats
path: root/kmix
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commite2de64d6f1beb9e492daf5b886e19933c1fa41dd (patch)
tree9047cf9e6b5c43878d5bf82660adae77ceee097a /kmix
downloadtdemultimedia-e2de64d6f1beb9e492daf5b886e19933c1fa41dd.tar.gz
tdemultimedia-e2de64d6f1beb9e492daf5b886e19933c1fa41dd.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdemultimedia@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kmix')
-rw-r--r--kmix/AUTHORS11
-rw-r--r--kmix/ChangeLog10
-rw-r--r--kmix/KMixApp.cpp71
-rw-r--r--kmix/KMixApp.h26
-rw-r--r--kmix/Makefile.am63
-rw-r--r--kmix/TODO47
-rw-r--r--kmix/TestCases36
-rw-r--r--kmix/colorwidget.ui276
-rw-r--r--kmix/configure.in.in0
-rw-r--r--kmix/dialogselectmaster.cpp197
-rw-r--r--kmix/dialogselectmaster.h43
-rw-r--r--kmix/dialogviewconfiguration.cpp102
-rw-r--r--kmix/dialogviewconfiguration.h30
-rw-r--r--kmix/doc/ControlNames.txt84
-rw-r--r--kmix/kledbutton.cpp79
-rw-r--r--kmix/kledbutton.h53
-rw-r--r--kmix/kmix-platforms.cpp149
-rw-r--r--kmix/kmix.cpp648
-rw-r--r--kmix/kmix.desktop92
-rw-r--r--kmix/kmix.h135
-rw-r--r--kmix/kmixapplet.cpp566
-rw-r--r--kmix/kmixapplet.desktop110
-rw-r--r--kmix/kmixapplet.h131
-rw-r--r--kmix/kmixctrl.cpp90
-rw-r--r--kmix/kmixctrl_restore.desktop70
-rw-r--r--kmix/kmixdockwidget.cpp391
-rw-r--r--kmix/kmixdockwidget.h82
-rw-r--r--kmix/kmixerwidget.cpp266
-rw-r--r--kmix/kmixerwidget.h118
-rw-r--r--kmix/kmixprefdlg.cpp132
-rw-r--r--kmix/kmixprefdlg.h67
-rw-r--r--kmix/kmixtoolbox.cpp215
-rw-r--r--kmix/kmixtoolbox.h28
-rw-r--r--kmix/kmixui.rc21
-rw-r--r--kmix/ksmallslider.cpp516
-rw-r--r--kmix/ksmallslider.h119
-rw-r--r--kmix/main.cpp69
-rw-r--r--kmix/mdwenum.cpp206
-rw-r--r--kmix/mdwenum.h77
-rw-r--r--kmix/mdwslider.cpp974
-rw-r--r--kmix/mdwslider.h128
-rw-r--r--kmix/mdwswitch.cpp231
-rw-r--r--kmix/mdwswitch.h88
-rw-r--r--kmix/mixdevice.cpp221
-rw-r--r--kmix/mixdevice.h114
-rw-r--r--kmix/mixdevicewidget.cpp120
-rw-r--r--kmix/mixdevicewidget.h115
-rw-r--r--kmix/mixer.cpp753
-rw-r--r--kmix/mixer.h174
-rw-r--r--kmix/mixerIface.h135
-rw-r--r--kmix/mixer_alsa.h53
-rw-r--r--kmix/mixer_alsa9.cpp828
-rw-r--r--kmix/mixer_backend.cpp147
-rw-r--r--kmix/mixer_backend.h104
-rw-r--r--kmix/mixer_hpux.cpp257
-rw-r--r--kmix/mixer_hpux.h36
-rw-r--r--kmix/mixer_irix.cpp133
-rw-r--r--kmix/mixer_irix.h28
-rw-r--r--kmix/mixer_none.cpp78
-rw-r--r--kmix/mixer_none.h22
-rw-r--r--kmix/mixer_oss.cpp330
-rw-r--r--kmix/mixer_oss.h33
-rw-r--r--kmix/mixer_oss4.cpp670
-rw-r--r--kmix/mixer_oss4.h42
-rw-r--r--kmix/mixer_sun.cpp473
-rw-r--r--kmix/mixer_sun.h52
-rw-r--r--kmix/mixertoolbox.cpp226
-rw-r--r--kmix/mixertoolbox.h22
-rw-r--r--kmix/mixset.cpp71
-rw-r--r--kmix/mixset.h21
-rw-r--r--kmix/pics/Listener.pngbin0 -> 1914 bytes
-rw-r--r--kmix/pics/Makefile.am14
-rw-r--r--kmix/pics/SpeakerFrontLeft.pngbin0 -> 1491 bytes
-rw-r--r--kmix/pics/SpeakerFrontRight.pngbin0 -> 1602 bytes
-rw-r--r--kmix/pics/SpeakerRearLeft.pngbin0 -> 1613 bytes
-rw-r--r--kmix/pics/SpeakerRearRight.pngbin0 -> 1663 bytes
-rw-r--r--kmix/pics/hi128-app-kmix.pngbin0 -> 12886 bytes
-rw-r--r--kmix/pics/hi16-app-kmix.pngbin0 -> 1043 bytes
-rw-r--r--kmix/pics/hi32-app-kmix.pngbin0 -> 2207 bytes
-rw-r--r--kmix/pics/hi48-app-kmix.pngbin0 -> 3703 bytes
-rw-r--r--kmix/pics/hi64-app-kmix.pngbin0 -> 5084 bytes
-rw-r--r--kmix/pics/kmixdocked.pngbin0 -> 1236 bytes
-rw-r--r--kmix/pics/kmixdocked_error.pngbin0 -> 1234 bytes
-rw-r--r--kmix/pics/kmixdocked_mute.pngbin0 -> 654 bytes
-rw-r--r--kmix/pics/mix_ac97.pngbin0 -> 517 bytes
-rw-r--r--kmix/pics/mix_audio.pngbin0 -> 323 bytes
-rw-r--r--kmix/pics/mix_bass.pngbin0 -> 334 bytes
-rw-r--r--kmix/pics/mix_cd.pngbin0 -> 489 bytes
-rw-r--r--kmix/pics/mix_digital.pngbin0 -> 206 bytes
-rw-r--r--kmix/pics/mix_ext.pngbin0 -> 331 bytes
-rw-r--r--kmix/pics/mix_headphone.pngbin0 -> 302 bytes
-rw-r--r--kmix/pics/mix_microphone.pngbin0 -> 350 bytes
-rw-r--r--kmix/pics/mix_midi.pngbin0 -> 337 bytes
-rw-r--r--kmix/pics/mix_recmon.pngbin0 -> 344 bytes
-rw-r--r--kmix/pics/mix_record.pngbin0 -> 983 bytes
-rw-r--r--kmix/pics/mix_surround.pngbin0 -> 265 bytes
-rw-r--r--kmix/pics/mix_toslink.pngbin0 -> 366 bytes
-rw-r--r--kmix/pics/mix_treble.pngbin0 -> 350 bytes
-rw-r--r--kmix/pics/mix_unknown.pngbin0 -> 340 bytes
-rw-r--r--kmix/pics/mix_video.pngbin0 -> 164 bytes
-rw-r--r--kmix/pics/mix_volume.pngbin0 -> 323 bytes
-rw-r--r--kmix/resource.h30
-rw-r--r--kmix/restore_kmix_volumes.desktop58
-rw-r--r--kmix/version.h21
-rw-r--r--kmix/verticaltext.cpp57
-rw-r--r--kmix/verticaltext.h19
-rw-r--r--kmix/viewapplet.cpp242
-rw-r--r--kmix/viewapplet.h47
-rw-r--r--kmix/viewbase.cpp187
-rw-r--r--kmix/viewbase.h121
-rw-r--r--kmix/viewdockareapopup.cpp206
-rw-r--r--kmix/viewdockareapopup.h57
-rw-r--r--kmix/viewgrid.cpp212
-rw-r--r--kmix/viewgrid.h42
-rw-r--r--kmix/viewinput.cpp50
-rw-r--r--kmix/viewinput.h19
-rw-r--r--kmix/viewoutput.cpp50
-rw-r--r--kmix/viewoutput.h19
-rw-r--r--kmix/viewsliders.cpp140
-rw-r--r--kmix/viewsliders.h33
-rw-r--r--kmix/viewsurround.cpp270
-rw-r--r--kmix/viewsurround.h42
-rw-r--r--kmix/viewswitches.cpp189
-rw-r--r--kmix/viewswitches.h36
-rw-r--r--kmix/volume.cpp266
-rw-r--r--kmix/volume.h80
126 files changed, 14612 insertions, 0 deletions
diff --git a/kmix/AUTHORS b/kmix/AUTHORS
new file mode 100644
index 00000000..8f72f47d
--- /dev/null
+++ b/kmix/AUTHORS
@@ -0,0 +1,11 @@
+kmix
+Written by Christian Esken (esken@kde.org)
+and Stefan Schimanski (1Stein@gmx.de)
+SGI port done Paul Kendall (paul@orion.co.nz)
+Fixes for FreeBSD Sebestyen Zoltan (szoli@digo.inf.elte.hu)
+Solaris fixes Faraut Jean-Louis <jlf@essi.fr>
+ALSA port Nick Lopez <kimo_sabe@usa.net>
+ALSA 0.9.x port Helio Chissini de Castro <helio@conectiva.com>
+HP-UX port Helge Deller <deller@gmx.de>
+
+The package is maintained by Christian Esken (esken@kde.org)
diff --git a/kmix/ChangeLog b/kmix/ChangeLog
new file mode 100644
index 00000000..df5588b3
--- /dev/null
+++ b/kmix/ChangeLog
@@ -0,0 +1,10 @@
+V1.90
+Version shipped with KDE3.1
+
+V1.91
+- Multiple soundcards on ALSA are now supported
+- Mixer device names are now shown with a vertical label (saves space and looks nice)
+- MixerDevice categories. Allows to distribute devices on "New Mixer Tab...". It is used
+ in the panel applet to show only important devices initally.
+- Much nicer "New Mixer Tab..." dialog
+
diff --git a/kmix/KMixApp.cpp b/kmix/KMixApp.cpp
new file mode 100644
index 00000000..74b84f43
--- /dev/null
+++ b/kmix/KMixApp.cpp
@@ -0,0 +1,71 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ * Copyright (C) 2000 Stefan Schimanski <schimmi@kde.org>
+ * Copyright (C) 2001 Preston Brown <pbrown@kde.org>
+ * Copyright (C) 2003 Sven Leiber <s.leiber@web.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "KMixApp.h"
+#include "kmix.h"
+#include <kdebug.h>
+
+
+KMixApp::KMixApp()
+ : KUniqueApplication(), m_kmix( 0 )
+{
+}
+
+
+KMixApp::~KMixApp()
+{
+ delete m_kmix;
+}
+
+
+int
+KMixApp::newInstance()
+{
+ if ( m_kmix )
+ {
+ m_kmix->show();
+ }
+ else
+ {
+ m_kmix = new KMixWindow;
+ connect(this, SIGNAL(stopUpdatesOnVisibility()), m_kmix, SLOT(stopVisibilityUpdates()));
+ if ( isRestored() && KMainWindow::canBeRestored(0) )
+ {
+ m_kmix->restore(0, FALSE);
+ }
+ }
+
+ return 0;
+}
+
+
+void
+KMixApp::quitExtended()
+{
+ // This method is here for quiting from the dock icon: When directly calling
+ // quit(), the main window will be hidden before saving the configuration.
+ // isVisible() would return on quit always false (which would be bad).
+ emit stopUpdatesOnVisibility();
+ quit();
+}
+
+#include "KMixApp.moc"
diff --git a/kmix/KMixApp.h b/kmix/KMixApp.h
new file mode 100644
index 00000000..79e4fc4e
--- /dev/null
+++ b/kmix/KMixApp.h
@@ -0,0 +1,26 @@
+#ifndef KMixApp_h
+#define KMixApp_h
+
+#include <kuniqueapplication.h>
+
+class KMixWindow;
+
+class KMixApp : public KUniqueApplication
+{
+Q_OBJECT
+ public:
+ KMixApp();
+ ~KMixApp();
+ int newInstance ();
+
+ public slots:
+ void quitExtended(); // For a hack on visibility()
+
+ signals:
+ void stopUpdatesOnVisibility();
+
+ private:
+ KMixWindow *m_kmix;
+};
+
+#endif
diff --git a/kmix/Makefile.am b/kmix/Makefile.am
new file mode 100644
index 00000000..307c8168
--- /dev/null
+++ b/kmix/Makefile.am
@@ -0,0 +1,63 @@
+SUBDIRS = pics
+INCLUDES= $(all_includes)
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = kmix.la kmixctrl.la
+kde_module_LTLIBRARIES = kmix_panelapplet.la
+
+
+noinst_HEADERS = kmix.h kmixdockwidget.h kmixprefdlg.h kmixerwidget.h \
+ viewbase.h viewoutput.h viewinput.h viewsliders.h viewswitches.h viewsurround.h viewdockareapopup.h viewgrid.h \
+ mixdevicewidget.h mdwslider.h mdwswitch.h mdwenum.h \
+ mixer.h mixset.h mixdevice.h mixer_backend.h volume.h kledbutton.h version.h kmixtoolbox.h \
+ ksmallslider.h kmixapplet.h mixerIface.h verticaltext.h \
+ KMixApp.h dialogviewconfiguration.h kmixtoolbox.h mixertoolbox.h dialogselectmaster.h
+
+
+METASOURCES = AUTO
+
+kmix_la_SOURCES = main.cpp kmix.cpp kmixdockwidget.cpp kmixprefdlg.cpp \
+ viewbase.cpp viewoutput.cpp viewinput.cpp viewswitches.cpp viewsurround.cpp viewdockareapopup.cpp \
+ viewsliders.cpp viewgrid.cpp \
+ mixdevicewidget.cpp mdwslider.cpp mdwswitch.cpp mdwenum.cpp \
+ kmixerwidget.cpp mixer.cpp mixset.cpp mixdevice.cpp mixer_backend.cpp ksmallslider.cpp \
+ volume.cpp kledbutton.cpp verticaltext.cpp mixerIface.skel \
+ kmixtoolbox.cpp mixertoolbox.cpp dialogviewconfiguration.cpp KMixApp.cpp dialogselectmaster.cpp
+
+kmix_la_LIBADD = $(LIB_KDEUI) $(LIB_KUTILS) $(LIBALIB) $(LIBOSSAUDIO) $(LIBASOUND)
+kmix_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -avoid-version
+
+kmixctrl_la_SOURCES = kmixctrl.cpp mixer.cpp mixset.cpp mixdevice.cpp volume.cpp mixerIface.skel \
+ mixertoolbox.cpp mixer_backend.cpp
+
+kmixctrl_la_LIBADD = $(LIB_KDECORE) $(LIBALIB) $(LIBOSSAUDIO) $(LIBASOUND)
+kmixctrl_la_LDFLAGS = $(all_libraries) -module -avoid-version
+
+kmix_panelapplet_la_SOURCES = kmixapplet.cpp \
+ viewbase.cpp viewapplet.cpp \
+ mixdevicewidget.cpp mdwslider.cpp \
+ mixer.cpp mixset.cpp mixdevice.cpp mixer_backend.cpp ksmallslider.cpp volume.cpp kledbutton.cpp \
+ verticaltext.cpp mixerIface.skel colorwidget.ui dialogviewconfiguration.cpp \
+ kmixtoolbox.cpp mixertoolbox.cpp dialogselectmaster.cpp
+
+kmix_panelapplet_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+kmix_panelapplet_la_LIBADD = $(LIB_KDEUI) $(LIB_KUTILS) $(LIBALIB) $(LIBOSSAUDIO) $(LIBASOUND)
+
+xdg_apps_DATA = kmix.desktop
+
+rcdir = $(kde_datadir)/kmix
+rc_DATA = kmixui.rc
+
+autostart_DATA = restore_kmix_volumes.desktop
+autostartdir = $(datadir)/autostart
+
+lnkdir = $(kde_datadir)/kicker/applets
+lnk_DATA = kmixapplet.desktop
+
+servicesdir = $(kde_servicesdir)
+services_DATA = kmixctrl_restore.desktop
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kmix.pot
+
diff --git a/kmix/TODO b/kmix/TODO
new file mode 100644
index 00000000..c48ea54c
--- /dev/null
+++ b/kmix/TODO
@@ -0,0 +1,47 @@
+TODO list
+
+Bug2 in KMix2.1pre:
+- Keys not saved/restored (pending)
+- DockApplet shows "show/hide menubar" (DONE)
+- "reversed" in panelapplet is broken. Remove it for now (DONE)
+- Initial paint of sliders in KMixApplet is broken. (DONE)
+- PanelApplet width wrong. (DONE)
+
+IMPORTANT:
+1) Get Switches working
+MUTE-LED's : Read: OK, Click: OK , Saved/Restored: no (was not in KMix2.0 and is shifted)
+Record-LED's: Read: OK, Click: OK , Saved/Restored: yes
+Switches : Read: OK, Click: OK , Saved/Restored: yes
+Dockarea : Read: OK, Click: OK , Saved/Restored: n/a (its a view, not HW)
+
+2a) Splitted sliders and balance
+OK
+Splitted sliders: Read: OK, Click: OK, Drag: OK, Wheel: OK
+Balance slider : OK (works like in KMix2.0)
+
+3) Mouse wheel
+OK
+
+4) Make Volume Tip work (is currently always "0%")
+OK
+
+5) Switches MUST be restored properly
+OK
+
+6) kmixapplet restoring and working
+OK
+
+7) Keys are not saved
+Pending
+
+
+14.6.2004 Christian Esken
+I believe Mixer_IRIX is broken.
+This is due to the old "writeVolumeToHW" and "readVolumeFromHW" interface.
+
+14 december 2002 - Helio Chissini de Castro
+- Figure out devices like SBLive with external Live Drives and their multiple in/outs. As a sample, using headphone output from live drive, mute switch not work as they must, but we need mutting the headphone lfe and center channel to really mute headphone output.
+
+- Introduce a new widget to enable route control in pro's ( Turtle ) and pro like ( Audigy, Live ) cards.
+
+
diff --git a/kmix/TestCases b/kmix/TestCases
new file mode 100644
index 00000000..edca34e0
--- /dev/null
+++ b/kmix/TestCases
@@ -0,0 +1,36 @@
+These are the recommended test cases for KMix.
+They should be tested before a new KDE version is being shipped.
+
+01: Basic: Start KMix with existing profile (kmixrc)
+02: Basic: Close KMix -> Dock
+03: Basic: Close KMix -> Exit
+04: Show/Hide Labels
+05: Show/Hide Tickmarks
+06: New Mixer Tab ("distribute" and "no distribute")
+07: System tray volume control
+08: Start KMix with no Mixer Hardware/Drivers available
+09: Basic: Start KMix with NO existing profile (kmixrc)
+10: Basic: KMix KControl module
+11: kmixctrl --restore (with existing .kmixctrlrc) must restore volumes
+12: kmixctrl --restore (without existing .kmixctrlrc) must NOT change volumes
+
+
+-----------+----+----+----+----+----+----+----+----+----+----+----+----+
+TestCase> | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
+Version | | | | | | | | | | | | |
+-----------+----+----+----+----+----+----+----+----+----+----+----+----+
+CVS20030502| OK | OK | OK | OK | OK | OK | OK | | | | | |
+-----------+----+----+----+----+----+----+----+ | +----+ | |
+CVS20031102| | | | | | na | | | | OK | | |
+-----------+----+----+----+----+----+----+----+ | +----+ | |
+KDE3.2 | OK | | | | | na | | | | | | |
+-----------+----+----+----+----+----+----+----+----+----+----+----+----+
+KDE3.4 | OK | OK | OK | OK | OK | na | OK | OK | OK | na | OK | OK |
+-----------+----+----+----+----+----+----+----+----+----+----+----+----+
+
+Test case results:
+OK : Fully OK
+ : Not tested
+xx : Failure
+na : not applicable (Feature discontinued)
+
diff --git a/kmix/colorwidget.ui b/kmix/colorwidget.ui
new file mode 100644
index 00000000..56f1d60e
--- /dev/null
+++ b/kmix/colorwidget.ui
@@ -0,0 +1,276 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ColorWidget</class>
+<author>Stefan Schimanski &lt;1Stein@gmx.de&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ColorWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>272</width>
+ <height>305</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>customColors</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Use custom colors</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>activeColors</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Active</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>activeBack</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Silent:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>activeLow</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>activeLow</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>activeHigh</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelLoad</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Loud:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>activeHigh</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Background:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>activeBack</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>mutedColors</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Muted</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Lou&amp;d:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mutedHigh</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel8</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Backgrou&amp;nd:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mutedBack</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Silen&amp;t:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mutedLow</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>mutedHigh</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>mutedLow</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>mutedBack</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>customColors</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>activeColors</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>customColors</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>mutedColors</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>customColors</tabstop>
+ <tabstop>activeHigh</tabstop>
+ <tabstop>activeLow</tabstop>
+ <tabstop>activeBack</tabstop>
+ <tabstop>mutedHigh</tabstop>
+ <tabstop>mutedLow</tabstop>
+ <tabstop>mutedBack</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in declaration">klocale.h</include>
+ <include location="global" impldecl="in declaration">kseparator.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmix/configure.in.in b/kmix/configure.in.in
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/kmix/configure.in.in
diff --git a/kmix/dialogselectmaster.cpp b/kmix/dialogselectmaster.cpp
new file mode 100644
index 00000000..44f38626
--- /dev/null
+++ b/kmix/dialogselectmaster.cpp
@@ -0,0 +1,197 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <qbuttongroup.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qptrlist.h>
+#include <qradiobutton.h>
+#include <qscrollview.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <klocale.h>
+
+#include "dialogselectmaster.h"
+#include "mixdevice.h"
+#include "mixer.h"
+
+DialogSelectMaster::DialogSelectMaster( Mixer *mixer )
+ : KDialogBase( Plain, i18n( "Select Master Channel" ), Ok|Cancel, Ok )
+{
+ _layout = 0;
+ m_vboxForScrollView = 0;
+ createWidgets(mixer); // Open with Mixer Hardware #0
+
+}
+
+DialogSelectMaster::~DialogSelectMaster()
+{
+ delete _layout;
+ delete m_vboxForScrollView;
+}
+
+/**
+ * Create basic widgets of the Dialog.
+ */
+void DialogSelectMaster::createWidgets(Mixer *ptr_mixer)
+{
+ QFrame *m_mainFrame = plainPage();
+ _layout = new QVBoxLayout(m_mainFrame,0,-1, "_layout" );
+
+ if ( Mixer::mixers().count() > 1 ) {
+ //kdDebug(67100) << "DialogSelectMaster::createPage count()>1" << "\n";
+ // More than one Mixer => show Combo-Box to select Mixer
+ // Mixer widget line
+ QHBoxLayout* mixerNameLayout = new QHBoxLayout( _layout );
+ //widgetsLayout->setStretchFactor( mixerNameLayout, 0 );
+ //QSizePolicy qsp( QSizePolicy::Ignored, QSizePolicy::Maximum);
+ //mixerNameLayout->setSizePolicy(qsp);
+ mixerNameLayout->setSpacing(KDialog::spacingHint());
+
+ QLabel *qlbl = new QLabel( i18n("Current Mixer"), m_mainFrame );
+ mixerNameLayout->addWidget(qlbl);
+ qlbl->setFixedHeight(qlbl->sizeHint().height());
+
+ m_cMixer = new KComboBox( FALSE, m_mainFrame, "mixerCombo" );
+ m_cMixer->setFixedHeight(m_cMixer->sizeHint().height());
+ connect( m_cMixer, SIGNAL( activated( int ) ), this, SLOT( createPageByID( int ) ) );
+
+ //int id=1;
+ for ( Mixer *mixer = Mixer::mixers().first(); mixer !=0; mixer = Mixer::mixers().next() ) {
+ m_cMixer->insertItem( mixer->mixerName() );
+ if ( ptr_mixer == mixer ) {
+ // Make the current Mixer the current item in the ComboBos
+ m_cMixer->setCurrentItem( m_cMixer->count()-1 );
+ }
+ //id++;
+ } // end for all_Mixers
+
+ QToolTip::add( m_cMixer, i18n("Current mixer" ) );
+ mixerNameLayout->addWidget(m_cMixer);
+
+ } // end if (more_than_1_Mixer)
+
+ QLabel *qlbl = new QLabel( i18n("Select the channel representing the master volume:"), m_mainFrame );
+ _layout->addWidget(qlbl);
+
+ m_scrollableChannelSelector = new QScrollView(m_mainFrame, "scrollableChannelSelector");
+ m_scrollableChannelSelector->viewport()->setBackgroundMode(Qt::PaletteBackground);
+ _layout->add(m_scrollableChannelSelector);
+
+ m_buttonGroupForScrollView = new QButtonGroup(this); // invisible QButtonGroup
+ m_buttonGroupForScrollView->hide();
+
+ createPage(ptr_mixer);
+ connect( this, SIGNAL(okClicked()) , this, SLOT(apply()) );
+}
+
+/**
+ * Create RadioButton's for the Mixer with number 'mixerId'.
+ * @par mixerId The Mixer, for which the RadioButton's should be created.
+ */
+void DialogSelectMaster::createPageByID(int mixerId)
+{
+ //kdDebug(67100) << "DialogSelectMaster::createPage()" << endl;
+ Mixer *mixer = Mixer::mixers().at(mixerId);
+ if ( mixer == 0 ) {
+ kdError(67100) << "DialogSelectMaster::createPage(): Invalid Mixer (mixerID=" << mixerId << ")" << endl;
+ return; // can not happen
+ }
+ createPage(mixer);
+}
+
+/**
+ * Create RadioButton's for the Mixer with number 'mixerId'.
+ * @par mixerId The Mixer, for which the RadioButton's should be created.
+ */
+void DialogSelectMaster::createPage(Mixer* mixer)
+{
+
+ /** --- Reset page -----------------------------------------------
+ * In case the user selected a new Mixer via m_cMixer, we need
+ * to remove the stuff created on the last call.
+ */
+ // delete the VBox. This should automatically remove all contained QRadioButton's.
+ delete m_vboxForScrollView;
+ m_mixerPKs.clear();
+ /** Reset page end -------------------------------------------------- */
+
+ m_vboxForScrollView = new QVBox(m_scrollableChannelSelector->viewport());
+ m_scrollableChannelSelector->addChild(m_vboxForScrollView);
+
+ QString masterKey = "----noMaster---"; // Use a non-matching name as default
+ MixDevice* master = mixer->masterDevice();
+ if ( master != 0 ) masterKey = master->getPK();
+
+ const MixSet& mixset = mixer->getMixSet();
+ MixSet& mset = const_cast<MixSet&>(mixset);
+ for( MixDevice* md = mset.first(); md != 0; md = mset.next() )
+ {
+ // Create a RadioButton for each MixDevice (excluding Enum's)
+ if ( ! md->isEnum() && ! md->isSwitch() ) {
+ //kdDebug(67100) << "DialogSelectMaster::createPage() mset append qrb" << endl;
+ QString mdName = md->name();
+ mdName.replace('&', "&&"); // Quoting the '&' needed, to prevent QRadioButton creating an accelerator
+ QRadioButton* qrb = new QRadioButton( mdName, m_vboxForScrollView);
+ m_buttonGroupForScrollView->insert(qrb); //(qrb, md->num());
+ //_qEnabledCB.append(qrb);
+ m_mixerPKs.push_back(md->getPK());
+ if ( md->getPK() == masterKey ) {
+ qrb->setChecked(true); // preselect the current master
+ }
+ else {
+ qrb->setChecked(false);
+ }
+ }
+ }
+
+ m_vboxForScrollView->show(); // show() is neccesary starting with the second call to createPage()
+}
+
+
+void DialogSelectMaster::apply()
+{
+ int soundcard_id = 0;
+ if ( Mixer::mixers().count() > 1 ) {
+ soundcard_id = m_cMixer->currentItem();
+ }
+ int channel_id = m_buttonGroupForScrollView->selectedId();
+ if ( channel_id != -1 ) {
+ // A channel was selected by the user => emit the "newMasterSelected()" signal
+ //kdDebug(67100) << "DialogSelectMaster::apply(): card=" << soundcard_id << ", channel=" << channel_id << endl;
+ Mixer *mixer = Mixer::mixers().at(soundcard_id);
+ if ( mixer == 0 ) {
+ kdError(67100) << "DialogSelectMaster::createPage(): Invalid Mixer (mixerID=" << soundcard_id << ")" << endl;
+ return; // can not happen
+ }
+ else {
+ mixer->setMasterDevice( m_mixerPKs[channel_id] );
+ emit newMasterSelected(soundcard_id, m_mixerPKs[channel_id] );
+ }
+ }
+}
+
+#include "dialogselectmaster.moc"
+
diff --git a/kmix/dialogselectmaster.h b/kmix/dialogselectmaster.h
new file mode 100644
index 00000000..912d870d
--- /dev/null
+++ b/kmix/dialogselectmaster.h
@@ -0,0 +1,43 @@
+#ifndef DIALOGSELECTMASTER_H
+#define DIALOGSELECTMASTER_H
+
+class QButtonGroup;
+#include <qradiobutton.h>
+class QScrollView;
+#include <qstringlist.h>
+class QVBox;
+class QVBoxLayout;
+
+class KComboBox;
+#include <kdialogbase.h>
+
+class Mixer;
+
+class DialogSelectMaster : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ DialogSelectMaster(Mixer *);
+ ~DialogSelectMaster();
+
+ signals:
+ void newMasterSelected(int, QString& );
+
+ public slots:
+ void apply();
+
+ private:
+ void createWidgets(Mixer*);
+ void createPage(Mixer*);
+ QVBoxLayout* _layout;
+ KComboBox* m_cMixer;
+ QScrollView* m_scrollableChannelSelector;
+ QVBox *m_vboxForScrollView;
+ QButtonGroup *m_buttonGroupForScrollView;
+ QStringList m_mixerPKs;
+
+ private slots:
+ void createPageByID(int mixerId);
+};
+
+#endif
diff --git a/kmix/dialogviewconfiguration.cpp b/kmix/dialogviewconfiguration.cpp
new file mode 100644
index 00000000..1c94ccf7
--- /dev/null
+++ b/kmix/dialogviewconfiguration.cpp
@@ -0,0 +1,102 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qptrlist.h>
+
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <klocale.h>
+
+#include "dialogviewconfiguration.h"
+#include "mixdevicewidget.h"
+#include "mixdevice.h"
+
+
+DialogViewConfiguration::DialogViewConfiguration( QWidget*, ViewBase& view)
+ : KDialogBase( Plain, i18n( "Configure" ), Ok|Cancel, Ok ),
+ _view(view)
+{
+ QPtrList<QWidget> &mdws = view._mdws;
+ _layout = new QVBoxLayout(plainPage(),0,-1, "_layout" );
+
+ // kdDebug(67100) << "DialogViewConfiguration::DialogViewConfiguration add header" << "\n";
+ QLabel* qlb = new QLabel( i18n("Configure"), plainPage() );
+ //QLabel* qlb = new QLabel( i18n("Show"), plainPage() );
+ _layout->addWidget(qlb);
+
+ for ( QWidget *qw = mdws.first(); qw != 0; qw = mdws.next())
+ {
+ if ( qw->inherits("MixDeviceWidget") ) {
+ MixDeviceWidget *mdw = static_cast<MixDeviceWidget*>(qw);
+ QString mdName = mdw->mixDevice()->name();
+ mdName.replace('&', "&&"); // Quoting the '&' needed, to prevent QCheckBox creating an accelerator
+ QCheckBox* cb = new QCheckBox( mdName, plainPage() );
+ _qEnabledCB.append(cb);
+ cb->setChecked( !mdw->isDisabled() ); //mdw->isVisible() );
+ _layout->addWidget(cb);
+ }
+ }
+ _layout->activate();
+ resize(_layout->sizeHint() );
+ connect( this, SIGNAL(okClicked()) , this, SLOT(apply()) );
+}
+
+DialogViewConfiguration::~DialogViewConfiguration()
+{
+}
+
+void DialogViewConfiguration::apply()
+{
+ QPtrList<QWidget> &mdws = _view._mdws;
+
+ // --- 2-Step Apply ---
+
+ // --- Step 1: Show and Hide Widgets ---
+ QCheckBox *cb = _qEnabledCB.first();
+ for ( QWidget *qw = mdws.first(); qw != 0; qw = mdws.next())
+ {
+ if ( qw->inherits("MixDeviceWidget") ) {
+ MixDeviceWidget *mdw = static_cast<MixDeviceWidget*>(qw);
+ if ( cb->isChecked() ) {
+ mdw->setDisabled(false);
+ }
+ else {
+ mdw->setDisabled(true);
+ }
+
+ cb = _qEnabledCB.next();
+ }
+ }
+
+ // --- Step 2: Tell the view, that it has changed (probably it needs some "polishing" ---
+ _view.configurationUpdate();
+}
+
+QSize DialogViewConfiguration::sizeHint() const {
+ // kdDebug(67100) << "DialogViewConfiguration::sizeHint() is (100,500)\n";
+ return _layout->sizeHint();
+}
+
+#include "dialogviewconfiguration.moc"
+
diff --git a/kmix/dialogviewconfiguration.h b/kmix/dialogviewconfiguration.h
new file mode 100644
index 00000000..d63d1031
--- /dev/null
+++ b/kmix/dialogviewconfiguration.h
@@ -0,0 +1,30 @@
+#ifndef DIALOGVIEWCONFIGURATION_H
+#define DIALOGVIEWCONFIGURATION_H
+
+#include <qcheckbox.h>
+#include <qptrlist.h>
+class QVBoxLayout;
+
+#include <kdialogbase.h>
+
+#include "viewbase.h"
+
+
+class DialogViewConfiguration : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ DialogViewConfiguration(QWidget* parent, ViewBase& view);
+ ~DialogViewConfiguration();
+
+ QSize sizeHint() const;
+ public slots:
+ void apply();
+
+ private:
+ QVBoxLayout* _layout;
+ ViewBase& _view;
+ QPtrList<QCheckBox> _qEnabledCB;
+};
+
+#endif
diff --git a/kmix/doc/ControlNames.txt b/kmix/doc/ControlNames.txt
new file mode 100644
index 00000000..5b18298e
--- /dev/null
+++ b/kmix/doc/ControlNames.txt
@@ -0,0 +1,84 @@
+This document describes standard names of mixer controls.
+
+Syntax: SOURCE [DIRECTION] FUNCTION
+
+DIRECTION:
+ <nothing> (both directions)
+ Playback
+ Capture
+ Bypass Playback
+ Bypass Capture
+
+FUNCTION:
+ Switch (on/off switch)
+ Volume
+ Route (route control, hardware specific)
+
+SOURCE:
+ Master
+ Master Mono
+ Hardware Master
+ Headphone
+ PC Speaker
+ Phone
+ Phone Input
+ Phone Output
+ Synth
+ FM
+ Mic
+ Line
+ CD
+ Video
+ Zoom Video
+ Aux
+ PCM
+ PCM Front
+ PCM Rear
+ PCM Pan
+ Loopback
+ Analog Loopback (D/A -> A/D loopback)
+ Digital Loopback (playback -> capture loopback - without analog path)
+ Mono
+ Mono Output
+ Multi
+ ADC
+ Wave
+ Music
+ I2S
+ IEC958
+
+Exceptions:
+ [Digital] Capture Source
+ [Digital] Capture Switch (aka input gain switch)
+ [Digital] Capture Volume (aka input gain volume)
+ [Digital] Playback Switch (aka output gain switch)
+ [Digital] Playback Volume (aka output gain volume)
+ Tone Control - Switch
+ Tone Control - Bass
+ Tone Control - Treble
+ 3D Control - Switch
+ 3D Control - Center
+ 3D Control - Depth
+ 3D Control - Wide
+ 3D Control - Space
+ 3D Control - Level
+ Mic Boost [(?dB)]
+
+PCM interface:
+
+ Sample Clock Source { "Word", "Internal", "AutoSync" }
+ Clock Sync Status { "Lock", "Sync", "No Lock" }
+ External Rate /* external capture rate */
+ Capture Rate /* capture rate taken from external source */
+
+IEC958 (S/PDIF) interface:
+
+ IEC958 [...] [Playback|Capture] Switch /* turn on/off the IEC958 interface */
+ IEC958 [...] [Playback|Capture] Volume /* digital volume control */
+ IEC958 [...] [Playback|Capture] Default /* default or global value - read/write */
+ IEC958 [...] [Playback|Capture] Mask /* consumer and professional mask */
+ IEC958 [...] [Playback|Capture] Con Mask /* consumer mask */
+ IEC958 [...] [Playback|Capture] Pro Mask /* professional mask */
+ IEC958 [...] [Playback|Capture] PCM Stream /* the settings assigned to a PCM stream */
+ IEC958 Q-subcode [Playback|Capture] Default /* Q-subcode bits */
+ IEC958 Preamble [Playback|Capture] Default /* burst preamble words (4*16bits) */
diff --git a/kmix/kledbutton.cpp b/kmix/kledbutton.cpp
new file mode 100644
index 00000000..1cddb148
--- /dev/null
+++ b/kmix/kledbutton.cpp
@@ -0,0 +1,79 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <qsizepolicy.h>
+
+#include "kledbutton.h"
+
+
+KLedButton::KLedButton(const QColor &col, QWidget *parent, const char *name)
+ : KLed( col, parent, name )
+{
+ // KLed and thus KLedButtung does not do proper positioning in QLayout's.
+ // Thus I will do a dirty trick here
+ installEventFilter(parent);
+}
+
+KLedButton::KLedButton(const QColor& col, KLed::State st, KLed::Look look,
+ KLed::Shape shape, QWidget *parent, const char *name)
+ : KLed( col, st, look, shape, parent, name )
+{
+}
+
+KLedButton::~KLedButton()
+{
+}
+
+void KLedButton::mousePressEvent( QMouseEvent *e )
+{
+ if (e->button() == LeftButton)
+ {
+ toggle();
+ emit stateChanged( state() );
+ }
+}
+
+bool KLedButton::eventFilter( QObject* /*obj*/ , QEvent* /*ev*/ ) {
+ // KLed and thus KLedButtung does not do proper positioning in QLayout's.
+ // Thus I listen to my parents resize events and do it here ... OUCH, that's ugly
+ /* No, this cannot work !
+ if ( ev->type() == QEvent::Resize ) {
+ QResizeEvent* qre = (QResizeEvent*)ev;
+ this->move( qre->size().width() - width()/2,
+ qre->size().height() - height()/2 );
+ }
+ */
+ return false;
+ // KLed::eventFilter(obj, ev);
+
+}
+
+QSize KLedButton::sizeHint() const
+{
+ return size();
+}
+
+QSizePolicy KLedButton::sizePolicy () const
+{
+ return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+}
+
+#include "kledbutton.moc"
diff --git a/kmix/kledbutton.h b/kmix/kledbutton.h
new file mode 100644
index 00000000..261f829c
--- /dev/null
+++ b/kmix/kledbutton.h
@@ -0,0 +1,53 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KLEDBUTTON_H
+#define KLEDBUTTON_H
+
+#include <qwidget.h>
+
+#include <kled.h>
+
+/**
+ *@author Stefan Schimanski
+ */
+
+class KLedButton : public KLed {
+ Q_OBJECT
+ public:
+ KLedButton(const QColor &col=Qt::green, QWidget *parent=0, const char *name=0);
+ KLedButton(const QColor& col, KLed::State st, KLed::Look look, KLed::Shape shape,
+ QWidget *parent=0, const char *name=0);
+ ~KLedButton();
+
+ QSize sizeHint () const;
+ QSizePolicy sizePolicy () const;
+ signals:
+ void stateChanged( bool newState );
+
+ protected:
+ void mousePressEvent ( QMouseEvent *e );
+
+ private:
+ bool eventFilter( QObject*, QEvent* );
+};
+
+#endif
diff --git a/kmix/kmix-platforms.cpp b/kmix/kmix-platforms.cpp
new file mode 100644
index 00000000..7947043b
--- /dev/null
+++ b/kmix/kmix-platforms.cpp
@@ -0,0 +1,149 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2000 Christian Esken
+ * esken@kde.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This code is being #include'd from mixer.cpp */
+
+#include <config.h>
+
+#include <qstring.h>
+
+#include "mixer_backend.h"
+
+#if defined(sun) || defined(__sun__)
+#define SUN_MIXER
+#endif
+
+#ifdef sgi
+#include <sys/fcntl.h>
+#define IRIX_MIXER
+#endif
+
+#ifdef __linux__
+
+#ifdef HAVE_LIBASOUND2
+#define ALSA_MIXER
+#endif
+
+#define OSS_MIXER
+#endif
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(_UNIXWARE) || defined(__DragonFly__)
+#define OSS_MIXER
+#endif
+
+#if defined(hpux)
+# if defined(HAVE_ALIB_H)
+# define HPUX_MIXER
+# else
+# warning ** YOU NEED to have libAlib installed to use the HP-UX-Mixer **
+# endif // HAVE_ALIB_H
+#endif // hpux
+
+// PORTING: add #ifdef PLATFORM , commands , #endif, add your new mixer below
+#if defined(NAS_MIXER)
+#include "mixer_nas.cpp"
+#endif
+
+#if defined(SUN_MIXER)
+#include "mixer_sun.cpp"
+#endif
+
+#if defined(IRIX_MIXER)
+#include "mixer_irix.cpp"
+#endif
+
+// Alsa API's
+#if defined(ALSA_MIXER)
+#include "mixer_alsa9.cpp"
+#endif
+
+#if defined(OSS_MIXER)
+#include "mixer_oss.cpp"
+
+#if !defined(__NetBSD__) && !defined(__OpenBSD__)
+#include <sys/soundcard.h>
+#else
+#include <soundcard.h>
+#endif
+#if SOUND_VERSION >= 0x040000
+#define OSS4_MIXER
+#endif
+
+#endif
+
+#if defined(OSS4_MIXER)
+#include "mixer_oss4.cpp"
+#endif
+
+#if defined(HPUX_MIXER)
+#include "mixer_hpux.cpp"
+#endif
+
+/*
+#else
+// We cannot handle this! I install a dummy mixer instead.
+#define NO_MIXER
+#include "mixer_none.cpp"
+#endif
+*/
+
+typedef Mixer_Backend *getMixerFunc( int device );
+typedef QString getDriverNameFunc( );
+
+struct MixerFactory {
+ getMixerFunc *getMixer;
+ getDriverNameFunc *getDriverName;
+};
+
+MixerFactory g_mixerFactories[] = {
+
+#if defined(NAS_MIXER)
+ { NAS_getMixer, 0 },
+#endif
+
+#if defined(SUN_MIXER)
+ { SUN_getMixer, SUN_getDriverName },
+#endif
+
+#if defined(IRIX_MIXER)
+ { IRIX_getMixer, IRIX_getDriverName },
+#endif
+
+#if defined(ALSA_MIXER)
+ { ALSA_getMixer, ALSA_getDriverName },
+#endif
+
+#if defined(OSS4_MIXER)
+ { OSS4_getMixer, OSS4_getDriverName },
+#endif
+
+#if defined(OSS_MIXER)
+ { OSS_getMixer, OSS_getDriverName },
+#endif
+
+#if defined(HPUX_MIXER)
+ { HPUX_getMixer, HPUX_getDriverName },
+#endif
+
+ { 0, 0 }
+};
+
diff --git a/kmix/kmix.cpp b/kmix/kmix.cpp
new file mode 100644
index 00000000..e4cd68be
--- /dev/null
+++ b/kmix/kmix.cpp
@@ -0,0 +1,648 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ * Copyright (C) 2000 Stefan Schimanski <schimmi@kde.org>
+ * Copyright (C) 2001 Preston Brown <pbrown@kde.org>
+ * Copyright (C) 2003 Sven Leiber <s.leiber@web.de>
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+// include files for QT
+#include <qmap.h>
+#include <qhbox.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qwidgetstack.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+
+// include files for KDE
+#include <kcombobox.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kmenubar.h>
+#include <klineeditdlg.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kstdaction.h>
+#include <kpanelapplet.h>
+#include <kpopupmenu.h>
+#include <khelpmenu.h>
+#include <kdebug.h>
+#include <kaccel.h>
+#include <kglobalaccel.h>
+#include <kkeydialog.h>
+#include <kpopupmenu.h>
+
+// application specific includes
+#include "mixertoolbox.h"
+#include "kmix.h"
+#include "kmixerwidget.h"
+#include "kmixprefdlg.h"
+#include "kmixdockwidget.h"
+#include "kmixtoolbox.h"
+
+
+/**
+ * Constructs a mixer window (KMix main window)
+ */
+KMixWindow::KMixWindow()
+ : KMainWindow(0, 0, 0, 0), m_showTicks( true ),
+ m_dockWidget( 0L )
+{
+ m_visibilityUpdateAllowed = true;
+ m_multiDriverMode = false; // -<- I never-ever want the multi-drivermode to be activated by accident
+ m_surroundView = false; // -<- Also the experimental surround View (3D)
+ m_gridView = false; // -<- Also the experimental Grid View
+ // As long as we do not know better, we assume to start hidden. We need
+ // to initialize this variable here, as we don't trigger a hideEvent().
+ m_isVisible = false;
+ m_mixerWidgets.setAutoDelete(true);
+ loadConfig(); // Need to load config before initMixer(), due to "MultiDriver" keyword
+ MixerToolBox::initMixer(Mixer::mixers(), m_multiDriverMode, m_hwInfoString);
+ initActions();
+ initWidgets();
+ initMixerWidgets();
+
+ initPrefDlg();
+ updateDocking();
+
+ if ( m_startVisible )
+ {
+ /* Started visible: We should do probably do:
+ * m_isVisible = true;
+ * But as a showEvent() is triggered by show() we don't need it.
+ */
+ show();
+ }
+ else
+ {
+ hide();
+ }
+ connect( kapp, SIGNAL( aboutToQuit()), SLOT( saveSettings()) );
+}
+
+
+KMixWindow::~KMixWindow()
+{
+ MixerToolBox::deinitMixer();
+}
+
+
+void
+KMixWindow::initActions()
+{
+ // file menu
+ KStdAction::quit( this, SLOT(quit()), actionCollection());
+
+ // settings menu
+ KStdAction::showMenubar( this, SLOT(toggleMenuBar()), actionCollection());
+ KStdAction::preferences( this, SLOT(showSettings()), actionCollection());
+ new KAction( i18n( "Configure &Global Shortcuts..." ), "configure_shortcuts", 0, this,
+ SLOT( configureGlobalShortcuts() ), actionCollection(), "settings_global" );
+ KStdAction::keyBindings( guiFactory(), SLOT(configureShortcuts()), actionCollection());
+
+ (void) new KAction( i18n( "Hardware &Information" ), 0, this, SLOT( slotHWInfo() ), actionCollection(), "hwinfo" );
+ (void) new KAction( i18n( "Hide Mixer Window" ), Key_Escape, this, SLOT(hide()), actionCollection(), "hide_kmixwindow" );
+
+ m_globalAccel = new KGlobalAccel( this );
+ m_globalAccel->insert( "Increase volume", i18n( "Increase Volume of Master Channel"), QString::null,
+ KShortcut(), KShortcut(), this, SLOT( increaseVolume() ) );
+ m_globalAccel->insert( "Decrease volume", i18n( "Decrease Volume of Master Channel"), QString::null,
+ KShortcut(), KShortcut(), this, SLOT( decreaseVolume() ) );
+ m_globalAccel->insert( "Toggle mute", i18n( "Toggle Mute of Master Channel"), QString::null,
+ KShortcut(), KShortcut(), this, SLOT( toggleMuted() ) );
+ m_globalAccel->readSettings();
+ m_globalAccel->updateConnections();
+
+ createGUI( "kmixui.rc" );
+}
+
+
+void
+KMixWindow::initPrefDlg()
+{
+ m_prefDlg = new KMixPrefDlg( this );
+ connect( m_prefDlg, SIGNAL(signalApplied(KMixPrefDlg *)),
+ this, SLOT(applyPrefs(KMixPrefDlg *)) );
+}
+
+
+void
+KMixWindow::initWidgets()
+{
+ // Main widget and layout
+ setCentralWidget( new QWidget( this, "qt_central_widget" ) );
+
+ // Widgets layout
+ widgetsLayout = new QVBoxLayout( centralWidget(), 0, 0, "widgetsLayout" );
+ widgetsLayout->setResizeMode(QLayout::Minimum); // works fine
+
+
+ // Mixer widget line
+ mixerNameLayout = new QHBox( centralWidget(), "mixerNameLayout" );
+ widgetsLayout->setStretchFactor( mixerNameLayout, 0 );
+ QSizePolicy qsp( QSizePolicy::Ignored, QSizePolicy::Maximum);
+ mixerNameLayout->setSizePolicy(qsp);
+ mixerNameLayout->setSpacing(KDialog::spacingHint());
+ QLabel *qlbl = new QLabel( i18n("Current mixer:"), mixerNameLayout );
+ qlbl->setFixedHeight(qlbl->sizeHint().height());
+ m_cMixer = new KComboBox( FALSE, mixerNameLayout, "mixerCombo" );
+ m_cMixer->setFixedHeight(m_cMixer->sizeHint().height());
+ connect( m_cMixer, SIGNAL( activated( int ) ), this, SLOT( showSelectedMixer( int ) ) );
+ QToolTip::add( m_cMixer, i18n("Current mixer" ) );
+
+ // Add first layout to widgets
+ widgetsLayout->addWidget( mixerNameLayout );
+
+ m_wsMixers = new QWidgetStack( centralWidget(), "MixerWidgetStack" );
+ widgetsLayout->setStretchFactor( m_wsMixers, 10 );
+ widgetsLayout->addWidget( m_wsMixers );
+
+ if ( m_showMenubar )
+ menuBar()->show();
+ else
+ menuBar()->hide();
+
+ widgetsLayout->activate();
+}
+
+
+void
+KMixWindow::updateDocking()
+{
+ // delete old dock widget
+ if (m_dockWidget)
+ {
+ delete m_dockWidget;
+ m_dockWidget = 0L;
+ }
+
+ if (m_showDockWidget)
+ {
+
+ // create dock widget
+ // !! This should be a View in the future
+ m_dockWidget = new KMixDockWidget( Mixer::mixers().first(), this, "mainDockWidget", m_volumeWidget );
+
+/* Belongs in KMixDockWidget
+ // create RMB menu
+ KPopupMenu *menu = m_dockWidget->contextMenu();
+
+ // !! check this
+ KAction *a = actionCollection()->action( "dock_mute" );
+ if ( a ) a->plug( menu );
+*/
+
+ /*
+ * Mail from 31.1.2005: "make sure your features are at least string complete"
+ * Preparation for fixing Bug #55078 - scheduled for KDE3.4.1 .
+ * This text will be plugged into the dock-icon popup menu.
+ */
+ QString selectChannel = i18n("Select Channel"); // This text will be used in KDE3.4.1 !!!
+
+ m_dockWidget->show();
+ }
+}
+
+void
+KMixWindow::saveSettings()
+{
+ saveConfig();
+ saveVolumes();
+}
+
+void
+KMixWindow::saveConfig()
+{
+ KConfig *config = kapp->config();
+ config->setGroup(0);
+
+ // make sure we don't start without any UI
+ // can happen e.g. when not docked and kmix closed via 'X' button
+ bool startVisible = m_isVisible;
+ if ( !m_showDockWidget )
+ startVisible = true;
+
+ config->writeEntry( "Size", size() );
+ config->writeEntry( "Position", pos() );
+ // Cannot use isVisible() here, as in the "aboutToQuit()" case this widget is already hidden.
+ // (Please note that the problem was only there when quitting via Systray - esken).
+ config->writeEntry( "Visible", startVisible );
+ config->writeEntry( "Menubar", m_showMenubar );
+ config->writeEntry( "AllowDocking", m_showDockWidget );
+ config->writeEntry( "TrayVolumeControl", m_volumeWidget );
+ config->writeEntry( "Tickmarks", m_showTicks );
+ config->writeEntry( "Labels", m_showLabels );
+ config->writeEntry( "startkdeRestore", m_onLogin );
+ Mixer* mixerMasterCard = Mixer::masterCard();
+ if ( mixerMasterCard != 0 ) {
+ config->writeEntry( "MasterMixer", mixerMasterCard->id() );
+ }
+ MixDevice* mdMaster = Mixer::masterCardDevice();
+ if ( mdMaster != 0 ) {
+ config->writeEntry( "MasterMixerDevice", mdMaster->getPK() );
+ }
+
+ if ( m_valueStyle == MixDeviceWidget::NABSOLUTE )
+ config->writeEntry( "ValueStyle", "Absolute");
+ else if ( m_valueStyle == MixDeviceWidget::NRELATIVE )
+ config->writeEntry( "ValueStyle", "Relative");
+ else
+ config->writeEntry( "ValueStyle", "None" );
+
+ if ( m_toplevelOrientation == Qt::Vertical )
+ config->writeEntry( "Orientation","Vertical" );
+ else
+ config->writeEntry( "Orientation","Horizontal" );
+
+ // save mixer widgets
+ for ( KMixerWidget *mw = m_mixerWidgets.first(); mw != 0; mw = m_mixerWidgets.next() )
+ {
+ if ( mw->mixer()->isOpen() )
+ { // protect from unplugged devices (better do *not* save them)
+ QString grp;
+ grp.sprintf( "%i", mw->id() );
+ mw->saveConfig( config, grp );
+ }
+ }
+
+ config->setGroup(0);
+}
+
+void
+KMixWindow::loadConfig()
+{
+ KConfig *config = kapp->config();
+ config->setGroup(0);
+
+ m_showDockWidget = config->readBoolEntry("AllowDocking", true);
+ m_volumeWidget = config->readBoolEntry("TrayVolumeControl", true);
+ //hide on close has to stay true for usability. KMixPrefDlg option commented out. nolden
+ m_hideOnClose = config->readBoolEntry("HideOnClose", true);
+ m_showTicks = config->readBoolEntry("Tickmarks", true);
+ m_showLabels = config->readBoolEntry("Labels", true);
+ const QString& valueStyleString = config->readEntry("ValueStyle", "None");
+ m_onLogin = config->readBoolEntry("startkdeRestore", true );
+ m_startVisible = config->readBoolEntry("Visible", true);
+ m_multiDriverMode = config->readBoolEntry("MultiDriver", false);
+ m_surroundView = config->readBoolEntry("Experimental-ViewSurround", false );
+ m_gridView = config->readBoolEntry("Experimental-ViewGrid", false );
+ const QString& orientationString = config->readEntry("Orientation", "Horizontal");
+ QString mixerMasterCard = config->readEntry( "MasterMixer", "" );
+ Mixer::setMasterCard(mixerMasterCard);
+ QString masterDev = config->readEntry( "MasterMixerDevice", "" );
+ Mixer::setMasterCardDevice(masterDev);
+
+ if ( valueStyleString == "Absolute" )
+ m_valueStyle = MixDeviceWidget::NABSOLUTE;
+ else if ( valueStyleString == "Relative" )
+ m_valueStyle = MixDeviceWidget::NRELATIVE;
+ else
+ m_valueStyle = MixDeviceWidget::NNONE;
+
+ if ( orientationString == "Vertical" )
+ m_toplevelOrientation = Qt::Vertical;
+ else
+ m_toplevelOrientation = Qt::Horizontal;
+
+ // show/hide menu bar
+ m_showMenubar = config->readBoolEntry("Menubar", true);
+
+ KToggleAction *a = static_cast<KToggleAction*>(actionCollection()->action("options_show_menubar"));
+ if (a) a->setChecked( m_showMenubar );
+
+ // restore window size and position
+ if ( !kapp->isRestored() ) // done by the session manager otherwise
+ {
+ QSize defSize( minimumWidth(), height() );
+ QSize size = config->readSizeEntry("Size", &defSize );
+ if(!size.isEmpty()) resize(size);
+
+ QPoint defPos = pos();
+ QPoint pos = config->readPointEntry("Position", &defPos);
+ move(pos);
+ }
+}
+
+
+void
+KMixWindow::initMixerWidgets()
+{
+ m_mixerWidgets.clear();
+
+ int id=0;
+ Mixer *mixer;
+
+ // Attention!! If Mixer::mixers() is empty, we behave stupid. We don't show nothing and there
+ // is not even a context menu.
+ for ( mixer=Mixer::mixers().first(),id=0; mixer!=0; mixer=Mixer::mixers().next(),id++ )
+ {
+ //kdDebug(67100) << "Mixer number: " << id << " Name: " << mixer->mixerName() << endl ;
+ ViewBase::ViewFlags vflags = ViewBase::HasMenuBar;
+ if ( m_showMenubar ) {
+ vflags |= ViewBase::MenuBarVisible;
+ }
+ if ( m_surroundView ) {
+ vflags |= ViewBase::Experimental_SurroundView;
+ }
+ if ( m_gridView ) {
+ vflags |= ViewBase::Experimental_GridView;
+ }
+ if ( m_toplevelOrientation == Qt::Vertical ) {
+ vflags |= ViewBase::Vertical;
+ }
+ else {
+ vflags |= ViewBase::Horizontal;
+ }
+
+
+ KMixerWidget *mw = new KMixerWidget( id, mixer, mixer->mixerName(),
+ MixDevice::ALL, this, "KMixerWidget", vflags );
+ m_mixerWidgets.append( mw );
+
+ // Add to Combo and Stack
+ m_cMixer->insertItem( mixer->mixerName() );
+ m_wsMixers->addWidget( mw, id );
+
+ QString grp;
+ grp.sprintf( "%i", mw->id() );
+ mw->loadConfig( kapp->config(), grp );
+
+ mw->setTicks( m_showTicks );
+ mw->setLabels( m_showLabels );
+ mw->setValueStyle ( m_valueStyle );
+ // !! I am still not sure whether this works 100% reliably - chris
+ mw->show();
+ }
+
+ if (id == 1)
+ {
+ // don't show the Current Mixer bit unless we have multiple mixers
+ mixerNameLayout->hide();
+ }
+}
+
+
+
+bool
+KMixWindow::queryClose ( )
+{
+ if ( m_showDockWidget && !kapp->sessionSaving() )
+ {
+ hide();
+ return false;
+ }
+ return true;
+}
+
+
+void
+KMixWindow::quit()
+{
+ kapp->quit();
+}
+
+
+void
+KMixWindow::showSettings()
+{
+ if (!m_prefDlg->isVisible())
+ {
+ m_prefDlg->m_dockingChk->setChecked( m_showDockWidget );
+ m_prefDlg->m_volumeChk->setChecked(m_volumeWidget);
+ m_prefDlg->m_showTicks->setChecked( m_showTicks );
+ m_prefDlg->m_showLabels->setChecked( m_showLabels );
+ m_prefDlg->m_onLogin->setChecked( m_onLogin );
+ m_prefDlg->_rbVertical ->setChecked( m_toplevelOrientation == Qt::Vertical );
+ m_prefDlg->_rbHorizontal->setChecked( m_toplevelOrientation == Qt::Horizontal );
+ m_prefDlg->_rbNone->setChecked( m_valueStyle == MixDeviceWidget::NNONE );
+ m_prefDlg->_rbAbsolute->setChecked( m_valueStyle == MixDeviceWidget::NABSOLUTE );
+ m_prefDlg->_rbRelative->setChecked( m_valueStyle == MixDeviceWidget::NRELATIVE );
+
+ m_prefDlg->show();
+ }
+}
+
+
+void
+KMixWindow::showHelp()
+{
+ actionCollection()->action( "help_contents" )->activate();
+}
+
+
+void
+KMixWindow::showAbout()
+{
+ actionCollection()->action( "help_about_app" )->activate();
+}
+
+/**
+ * Loads the volumes of all mixers from kmixctrlrc.
+ * In other words:
+ * Restores the default voumes as stored via saveVolumes() or the
+ * execution of "kmixctrl --save"
+ */
+/* Currently this is not in use
+void
+KMixWindow::loadVolumes()
+{
+ KConfig *cfg = new KConfig( "kmixctrlrc", true );
+ for (Mixer *mixer=Mixer::mixers().first(); mixer!=0; mixer=Mixer::mixers().next())
+ {
+ mixer->volumeLoad( cfg );
+ }
+ delete cfg;
+}
+*/
+
+/**
+ * Stores the volumes of all mixers Can be restored via loadVolumes() or
+ * the kmixctrl application.
+ */
+void
+KMixWindow::saveVolumes()
+{
+ KConfig *cfg = new KConfig( "kmixctrlrc", false );
+ for (Mixer *mixer=Mixer::mixers().first(); mixer!=0; mixer=Mixer::mixers().next()) {
+ //kdDebug(67100) << "KMixWindow::saveConfig()" << endl;
+ if ( mixer->isOpen() ) { // protect from unplugged devices (better do *not* save them)
+ mixer->volumeSave( cfg );
+ }
+ }
+ delete cfg;
+}
+
+
+void
+KMixWindow::applyPrefs( KMixPrefDlg *prefDlg )
+{
+ m_showDockWidget = prefDlg->m_dockingChk->isChecked();
+ m_volumeWidget = prefDlg->m_volumeChk->isChecked();
+ m_showTicks = prefDlg->m_showTicks->isChecked();
+ m_showLabels = prefDlg->m_showLabels->isChecked();
+ m_onLogin = prefDlg->m_onLogin->isChecked();
+
+ if ( prefDlg->_rbNone->isChecked() ) {
+ m_valueStyle = MixDeviceWidget::NNONE;
+ } else if ( prefDlg->_rbAbsolute->isChecked() ) {
+ m_valueStyle = MixDeviceWidget::NABSOLUTE;
+ } else if ( prefDlg->_rbRelative->isChecked() ) {
+ m_valueStyle = MixDeviceWidget::NRELATIVE;
+ }
+
+ bool toplevelOrientationHasChanged =
+ ( prefDlg->_rbVertical->isChecked() && m_toplevelOrientation == Qt::Horizontal )
+ || ( prefDlg->_rbHorizontal->isChecked() && m_toplevelOrientation == Qt::Vertical );
+ if ( toplevelOrientationHasChanged ) {
+ QString msg = i18n("The change of orientation will be adopted on the next start of KMix.");
+ KMessageBox::information(0,msg);
+ }
+ if ( prefDlg->_rbVertical->isChecked() ) {
+ //QString "For a change of language to take place, quit and restart KDiff3.";
+ //kdDebug(67100) << "KMix should change to Vertical layout\n";
+ m_toplevelOrientation = Qt::Vertical;
+ }
+ else if ( prefDlg->_rbHorizontal->isChecked() ) {
+ //kdDebug(67100) << "KMix should change to Horizontal layout\n";
+ m_toplevelOrientation = Qt::Horizontal;
+ }
+
+
+ this->setUpdatesEnabled(false);
+ updateDocking();
+
+ for (KMixerWidget *mw=m_mixerWidgets.first(); mw!=0; mw=m_mixerWidgets.next())
+ {
+ mw->setTicks( m_showTicks );
+ mw->setLabels( m_showLabels );
+ mw->setValueStyle ( m_valueStyle );
+ mw->mixer()->readSetFromHWforceUpdate(); // needed, as updateDocking() has reconstructed the DockWidget
+ }
+
+ this->setUpdatesEnabled(true);
+
+ // avoid invisible and unaccessible main window
+ if( !m_showDockWidget && !isVisible() )
+ {
+ show();
+ }
+
+ this->repaint(); // make KMix look fast (saveConfig() often uses several seconds)
+ kapp->processEvents();
+ saveConfig();
+}
+
+
+void
+KMixWindow::toggleMenuBar()
+{
+ m_showMenubar = !m_showMenubar;
+ if( m_showMenubar )
+ {
+ menuBar()->show();
+ }
+ else
+ {
+ menuBar()->hide();
+ }
+}
+
+void
+KMixWindow::showEvent( QShowEvent * )
+{
+ if ( m_visibilityUpdateAllowed )
+ m_isVisible = isVisible();
+ // !! could possibly start polling now (idea: use someting like ref() and unref() on Mixer instance
+}
+
+void
+KMixWindow::hideEvent( QHideEvent * )
+{
+ if ( m_visibilityUpdateAllowed )
+ {
+ m_isVisible = isVisible();
+ }
+ // !! could possibly stop polling now (idea: use someting like ref() and unref() on Mixer instance
+ // Update: This is a stupid idea, because now the views are responsible for updating. So it will be done in the Views.
+ // But the dock icon is currently no View, so that must be done first.
+}
+
+
+void
+KMixWindow::stopVisibilityUpdates() {
+ m_visibilityUpdateAllowed = false;
+}
+
+void
+KMixWindow::slotHWInfo() {
+ KMessageBox::information( 0, m_hwInfoString, i18n("Mixer Hardware Information") );
+}
+
+void
+KMixWindow::showSelectedMixer( int mixer )
+{
+ m_wsMixers->raiseWidget( mixer );
+}
+
+void
+KMixWindow::configureGlobalShortcuts()
+{
+ KKeyDialog::configure( m_globalAccel, 0, false ) ;
+ m_globalAccel->writeSettings();
+ m_globalAccel->updateConnections();
+}
+
+void
+KMixWindow::toggleMuted()
+{
+ Mixer* mixerMaster = Mixer::masterCard();
+ if ( mixerMaster != 0 ) {
+ MixDevice* md = mixerMaster->masterDevice();
+ if ( md != 0 && md->hasMute() ) {
+ mixerMaster->toggleMute(md->num());
+ }
+ }
+}
+
+void
+KMixWindow::increaseVolume()
+{
+ Mixer* mixerMaster = Mixer::masterCard();
+ if ( mixerMaster != 0 ) {
+ MixDevice* md = mixerMaster->masterDevice();
+ if ( md != 0 ) {
+ mixerMaster->increaseVolume(md->num());
+ }
+ }
+}
+
+void
+KMixWindow::decreaseVolume()
+{
+ Mixer* mixerMaster = Mixer::masterCard();
+ if ( mixerMaster != 0 ) {
+ MixDevice* md = mixerMaster->masterDevice();
+ if ( md != 0 ) {
+ mixerMaster->decreaseVolume(md->num());
+ }
+ }
+}
+
+#include "kmix.moc"
+
diff --git a/kmix/kmix.desktop b/kmix/kmix.desktop
new file mode 100644
index 00000000..4cb25f7a
--- /dev/null
+++ b/kmix/kmix.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+Exec=kmix -caption "%c" %i %m
+DocPath=kmix/index.html
+OnlyShowIn=KDE;
+Path=
+Type=Application
+MimeType=
+Terminal=false
+Icon=kmix
+GenericName=Sound Mixer
+GenericName[af]=Klank Menger
+GenericName[ar]=مازج الصوت
+GenericName[bg]=Аудио миксер
+GenericName[br]=Mesker ar Son
+GenericName[bs]=Zvučni mikser
+GenericName[ca]=Mesclador de so
+GenericName[cs]=Zvukový směšovač
+GenericName[cy]=Cymysgydd Sŵn
+GenericName[da]=Lydmikser
+GenericName[de]=Lautstärkeregler
+GenericName[el]=Μείκτης ήχου
+GenericName[eo]=Sonormiksilo
+GenericName[es]=Un mezclador audio
+GenericName[et]=Helimikser
+GenericName[eu]=Soinu nahasgailua
+GenericName[fa]=مخلوط‌کن صدا
+GenericName[fi]=Äänimikseri
+GenericName[fr]=Console de mixage
+GenericName[ga]=Meascthóir Fuaime
+GenericName[gl]=Mesturador de Son
+GenericName[he]=מערבל צליל
+GenericName[hi]=ध्वनि मिक्सर
+GenericName[hr]=Mikser zvuka
+GenericName[hu]=Hangkeverő
+GenericName[is]=Hljóðblöndun
+GenericName[it]=Mixer audio
+GenericName[ja]=サウンドミキサー
+GenericName[kk]=Дыбыс микшері
+GenericName[km]=កម្មវិធី​លាយ​សំឡេង
+GenericName[ko]=소리 믹서
+GenericName[lt]=Garsų maišiklis
+GenericName[lv]=Skaņas Mikšeris
+GenericName[mk]=Миксета за звук
+GenericName[ms]=Pengadun Bunyi
+GenericName[nb]=Lydmikser
+GenericName[nds]=Klangmischer
+GenericName[ne]=ध्वनि मिक्सर
+GenericName[nl]=Geluidsmixer
+GenericName[nn]=Lydmiksar
+GenericName[pa]=ਧੁਨੀ ਮਿਕਸਰ
+GenericName[pl]=Ustawienia głośności
+GenericName[pt]=Mesa de Mistura de Áudio
+GenericName[pt_BR]=Mixagem de som
+GenericName[ro]=Mixer de sunet
+GenericName[ru]=Звуковой микшер
+GenericName[se]=Jietnamixer
+GenericName[sk]=Zvukový mixér
+GenericName[sl]=Mešalnik zvoka
+GenericName[sr]=Звучна миксета
+GenericName[sr@Latn]=Zvučna mikseta
+GenericName[sv]=Ljudmixer
+GenericName[ta]=ஒலி ஒன்றுசேர்ப்பான்
+GenericName[tg]=Омехтакунаки Овоз
+GenericName[th]=โปรแกรมผสมเสียง
+GenericName[tr]=Ses Denetimleri
+GenericName[uk]=Аудіомікшер
+GenericName[uz]=Audio mikser
+GenericName[uz@cyrillic]=Аудио миксер
+GenericName[ven]=Tshitanganisi tsha mubvumo
+GenericName[wa]=Maxheu d' sons
+GenericName[xh]=Umxubi WokuvakalayoU
+GenericName[zh_CN]=混音器
+GenericName[zh_HK]=聲音混音器
+GenericName[zh_TW]=音效混音器
+GenericName[zu]=Umxubi Womsindo
+Name=KMix
+Name[af]=Kmix
+Name[bn]=কে-মিক্স
+Name[ca]=Kmix
+Name[eo]=Miksilo
+Name[hi]=के-मिक्स
+Name[lv]=KMiks
+Name[ne]=केडीई मिक्स
+Name[pa]=ਕੇ-ਮਿਕਸ
+Name[sv]=Kmix
+Name[ta]=கேமிக்ஸ்
+Name[tg]=KОмезиш
+Name[ven]=U tanganisa ha K
+Name[zh_TW]=KMix 混音器
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Unique
+Categories=Qt;KDE;AudioVideo;Audio;Mixer;
diff --git a/kmix/kmix.h b/kmix/kmix.h
new file mode 100644
index 00000000..4805d4d1
--- /dev/null
+++ b/kmix/kmix.h
@@ -0,0 +1,135 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KMIX_H
+#define KMIX_H
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// include files for Qt
+#include <qstring.h>
+#include <qmap.h>
+
+class QHBox;
+class QWidgetStack;
+
+// include files for KDE
+#include <kmainwindow.h>
+
+class KAccel;
+class KGlobalAccel;
+class KComboBox;
+class KMixerWidget;
+class KMixerPrefWidget;
+class KMixPrefDlg;
+class KMixDockWidget;
+class KMixWindow;
+class Mixer;
+
+#include "mixer.h"
+#include "mixdevicewidget.h"
+
+
+class
+KMixWindow : public KMainWindow
+{
+ Q_OBJECT
+
+ public:
+ KMixWindow();
+ ~KMixWindow();
+
+ protected slots:
+ void saveSettings();
+
+ protected:
+ void saveConfig();
+ void loadConfig();
+
+ void initPrefDlg();
+ void initActions();
+ void initWidgets();
+ void initMixerWidgets();
+
+ void updateDocking();
+
+ bool queryClose();
+ void showEvent( QShowEvent * );
+ void hideEvent( QHideEvent * );
+
+ public slots:
+ void quit();
+ void showSettings();
+ void showHelp();
+ void showAbout();
+ void toggleMenuBar();
+ //void loadVolumes();
+ void saveVolumes();
+ virtual void applyPrefs( KMixPrefDlg *prefDlg );
+ void stopVisibilityUpdates();
+
+ private:
+ KAccel *m_keyAccel;
+ KGlobalAccel *m_globalAccel;
+ QPopupMenu *m_fileMenu;
+ QPopupMenu *m_viewMenu;
+ QPopupMenu *m_helpMenu;
+
+ bool m_showDockWidget;
+ bool m_volumeWidget;
+ bool m_hideOnClose;
+ bool m_showTicks;
+ bool m_showLabels;
+ MixDeviceWidget::ValueStyle m_valueStyle; // No numbers by default
+ bool m_onLogin;
+ bool m_startVisible;
+ bool m_showMenubar;
+ bool m_isVisible;
+ bool m_visibilityUpdateAllowed;
+ bool m_multiDriverMode; // Not officially supported.
+ bool m_surroundView; // Experimental. Off by defualt
+ bool m_gridView; // Experimental. Off by default
+ Qt::Orientation m_toplevelOrientation;
+
+ QPtrList<KMixerWidget> m_mixerWidgets;
+
+ QHBox* mixerNameLayout;
+ KComboBox *m_cMixer;
+ QWidgetStack *m_wsMixers;
+ KMixPrefDlg *m_prefDlg;
+ KMixDockWidget *m_dockWidget;
+ QString m_hwInfoString;
+ QVBoxLayout *widgetsLayout;
+
+ private slots:
+ //void removeMixerWidget( KMixerWidget *mw );
+ void slotHWInfo();
+ void showSelectedMixer( int mixer );
+ void configureGlobalShortcuts();
+ void toggleMuted();
+ void increaseVolume();
+ void decreaseVolume();
+};
+
+#endif // KMIX_H
diff --git a/kmix/kmixapplet.cpp b/kmix/kmixapplet.cpp
new file mode 100644
index 00000000..7ab8c00b
--- /dev/null
+++ b/kmix/kmixapplet.cpp
@@ -0,0 +1,566 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <schimmi@kde.org>
+ * Copyright (C) 2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+// System
+#include <stdlib.h>
+
+// QT
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qwmatrix.h>
+
+
+// KDE
+#include <kaboutapplication.h>
+#include <kaboutdata.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kbugreport.h>
+#include <kcolorbutton.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalaccel.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+
+// // KMix
+#include "colorwidget.h"
+#include "mixertoolbox.h"
+#include "kmixapplet.h"
+#include "kmixtoolbox.h"
+#include "mdwslider.h"
+#include "mixdevicewidget.h"
+#include "mixer.h"
+#include "version.h"
+#include "viewapplet.h"
+
+
+extern "C"
+{
+ KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile)
+ {
+ KGlobal::locale()->insertCatalogue("kmix");
+ return new KMixApplet(configFile, KPanelApplet::Normal,
+ parent, "kmixapplet");
+ }
+}
+
+int KMixApplet::s_instCount = 0;
+//<Mixer> KMixApplet::Mixer::mixers();
+
+static const QColor highColor = KGlobalSettings::baseColor();
+static const QColor lowColor = KGlobalSettings::highlightColor();
+static const QColor backColor = "#000000";
+static const QColor mutedHighColor = "#FFFFFF";
+static const QColor mutedLowColor = "#808080";
+static const QColor mutedBackColor = "#000000";
+
+AppletConfigDialog::AppletConfigDialog( QWidget * parent, const char * name )
+ : KDialogBase( KDialogBase::Plain, QString::null,
+ KDialogBase::Ok | KDialogBase::Apply | KDialogBase::Cancel,
+ KDialogBase::Ok, parent, name, false, true)
+{
+ setPlainCaption(i18n("Configure - Mixer Applet"));
+ QFrame* page = plainPage();
+ QVBoxLayout *topLayout = new QVBoxLayout(page);
+ colorWidget = new ColorWidget(page);
+ topLayout->addWidget(colorWidget);
+ setUseCustomColors(false);
+}
+
+void AppletConfigDialog::slotOk()
+{
+ slotApply();
+ KDialogBase::slotOk();
+}
+
+void AppletConfigDialog::slotApply()
+{
+ emit applied();
+}
+
+void AppletConfigDialog::setActiveColors(const QColor& high, const QColor& low, const QColor& back)
+{
+ colorWidget->activeHigh->setColor(high);
+ colorWidget->activeLow->setColor(low);
+ colorWidget->activeBack->setColor(back);
+}
+
+void AppletConfigDialog::activeColors(QColor& high, QColor& low, QColor& back) const
+{
+ high = colorWidget->activeHigh->color();
+ low = colorWidget->activeLow->color();
+ back = colorWidget->activeBack->color();
+}
+
+void AppletConfigDialog::setMutedColors(const QColor& high, const QColor& low, const QColor& back)
+{
+ colorWidget->mutedHigh->setColor(high);
+ colorWidget->mutedLow->setColor(low);
+ colorWidget->mutedBack->setColor(back);
+}
+
+void AppletConfigDialog::mutedColors(QColor& high, QColor& low, QColor& back) const
+{
+ high = colorWidget->mutedHigh->color();
+ low = colorWidget->mutedLow->color();
+ back = colorWidget->mutedBack->color();
+}
+
+void AppletConfigDialog::setUseCustomColors(bool custom)
+{
+ colorWidget->customColors->setChecked(custom);
+ colorWidget->activeColors->setEnabled(custom);
+ colorWidget->mutedColors->setEnabled(custom);
+}
+
+bool AppletConfigDialog::useCustomColors() const
+{
+ return colorWidget->customColors->isChecked();
+}
+
+
+KMixApplet::KMixApplet( const QString& configFile, Type t,
+ QWidget *parent, const char *name )
+
+ : KPanelApplet( configFile, t, KPanelApplet::Preferences | KPanelApplet::ReportBug | KPanelApplet::About, parent, name ),
+ m_mixerWidget(0), m_errorLabel(0), m_pref(0),
+ m_aboutData( "kmix", I18N_NOOP("KMix Panel Applet"),
+ APP_VERSION, "Mini Sound Mixer Applet", KAboutData::License_GPL,
+ I18N_NOOP( "(c) 1996-2000 Christian Esken\n(c) 2000-2003 Christian Esken, Stefan Schimanski") )
+{
+ setBackgroundOrigin(AncestorOrigin);
+ kdDebug(67100) << "KMixApplet::KMixApplet instancing Applet. Old s_instCount="<< s_instCount << " configfile=" << configFile << endl;
+ //kdDebug(67100) << "KMixApplet::KMixApplet()" << endl;
+ _layout = new QHBoxLayout(this); // it will always only be one item in it, so we don't care whether it is HBox or VBox
+
+ // init static vars
+ if ( s_instCount == 0) {
+ Mixer::mixers().setAutoDelete( TRUE );
+ QString dummyStringHwinfo;
+ MixerToolBox::initMixer(Mixer::mixers(), false, dummyStringHwinfo);
+ }
+ s_instCount++;
+ kdDebug(67100) << "KMixApplet::KMixApplet instancing Applet, s_instCount="<< s_instCount << endl;
+
+ KGlobal::dirs()->addResourceType( "appicon", KStandardDirs::kde_default("data") + "kmix/pics" );
+
+ loadConfig();
+
+
+ /********** find out to use which mixer ****************************************/
+ _mixer = 0;
+ for (_mixer= Mixer::mixers().first(); _mixer!=0; _mixer=Mixer::mixers().next())
+ {
+ if ( _mixer->id() == _mixerId ) break;
+ }
+ if ( _mixer == 0 ) {
+ /* Until KMix V3.4-0 the mixerNumber (int) was stored. This was too complicated to handle, so we use an
+ * unique ID (_mixer->mixerId(). But in case when the user changes soundcards (or when upgrading from
+ * KMix 3.4-0 to a 3.4-1 or newer), we scan also for the soundcard name */
+ for (_mixer= Mixer::mixers().first(); _mixer!=0; _mixer=Mixer::mixers().next())
+ {
+ if ( _mixer->mixerName() == _mixerName ) break;
+ }
+ }
+
+ // don't prompt for a mixer if there is just one available
+ if ( !_mixer && Mixer::mixers().count() == 1 ) {
+ _mixer = Mixer::mixers().first();
+ }
+
+
+
+ if ( _mixer == 0 )
+ {
+ // No mixer set by user (kmixappletrc_*) and more than one to choose
+ // We do NOT know which mixer to use => ask the User
+ m_errorLabel = new QPushButton( i18n("Select Mixer"), this );
+ m_errorLabel->setGeometry(0, 0, m_errorLabel->sizeHint().width(), m_errorLabel->sizeHint().height() );
+ resize( m_errorLabel->sizeHint() );
+ connect( m_errorLabel, SIGNAL(clicked()), this, SLOT(selectMixer()) );
+ }
+ else {
+ // We know which mixer to use: Call positionChange(), which does all the creating
+ positionChange(position());
+ }
+ m_aboutData.addCredit( I18N_NOOP( "For detailed credits, please refer to the About information of the KMix program" ) );
+}
+
+KMixApplet::~KMixApplet()
+{
+ saveConfig();
+
+ /* !!! no cleanup for now: I get strange crashes on exiting
+ // destroy static vars
+ s_instCount--;
+ if ( s_instCount == 0)
+ {
+ MixerToolBox::deinitMixer();
+ }
+ */
+}
+
+void KMixApplet::saveConfig()
+{
+ kdDebug(67100) << "KMixApplet::saveConfig()" << endl;
+ if ( m_mixerWidget != 0) {
+ //kdDebug(67100) << "KMixApplet::saveConfig() save" << endl;
+ KConfig *cfg = this->config();
+ //kdDebug(67100) << "KMixApplet::saveConfig() save cfg=" << cfg << endl;
+ cfg->setGroup( 0 );
+ cfg->writeEntry( "Mixer", _mixer->id() );
+ cfg->writeEntry( "MixerName", _mixer->mixerName() );
+
+ cfg->writeEntry( "ColorCustom", _customColors );
+
+ cfg->writeEntry( "ColorHigh", _colors.high.name() );
+ cfg->writeEntry( "ColorLow", _colors.low.name() );
+ cfg->writeEntry( "ColorBack", _colors.back.name() );
+
+ cfg->writeEntry( "ColorMutedHigh", _colors.mutedHigh.name() );
+ cfg->writeEntry( "ColorMutedLow", _colors.mutedLow.name() );
+ cfg->writeEntry( "ColorMutedBack", _colors.mutedBack.name() );
+
+ //cfg->writeEntry( "ReversedDirection", reversedDir );
+
+ saveConfig( cfg, "Widget" );
+ cfg->sync();
+ }
+}
+
+
+void KMixApplet::loadConfig()
+{
+ kdDebug(67100) << "KMixApplet::loadConfig()" << endl;
+ KConfig *cfg = this->config();
+ cfg->setGroup(0);
+
+ _mixerId = cfg->readEntry( "Mixer", "undef" );
+ _mixerName = cfg->readEntry( "MixerName", QString::null );
+
+ _customColors = cfg->readBoolEntry( "ColorCustom", false );
+
+ _colors.high = cfg->readColorEntry("ColorHigh", &highColor);
+ _colors.low = cfg->readColorEntry("ColorLow", &lowColor);
+ _colors.back = cfg->readColorEntry("ColorBack", &backColor);
+
+ _colors.mutedHigh = cfg->readColorEntry("ColorMutedHigh", &mutedHighColor);
+ _colors.mutedLow = cfg->readColorEntry("ColorMutedLow", &mutedLowColor);
+ _colors.mutedBack = cfg->readColorEntry("ColorMutedBack", &mutedBackColor);
+
+ loadConfig( cfg, "Widget");
+}
+
+
+void KMixApplet::loadConfig( KConfig *config, const QString &grp )
+{
+ if ( m_mixerWidget ) {
+ //config->setGroup( grp );
+ KMixToolBox::loadConfig(m_mixerWidget->_mdws, config, grp, "PanelApplet" );
+ }
+}
+
+
+void KMixApplet::saveConfig( KConfig *config, const QString &grp )
+{
+ if ( m_mixerWidget ) {
+ config->setGroup( grp );
+ // Write mixer name. It cannot be changed in the Mixer instance,
+ // it is only saved for diagnostical purposes (analyzing the config file).
+ config->writeEntry("Mixer_Name_Key", _mixer->mixerName());
+ KMixToolBox::saveConfig(m_mixerWidget->_mdws, config, grp, "PanelApplet" );
+ }
+}
+
+/**
+ * Opens a dialog box with all available mixers and let the user choose one.
+ * If the user selects a mixer, "_mixer" will be set and positionChange() is called.
+ */
+void KMixApplet::selectMixer()
+{
+ QStringList lst;
+
+ int n=1;
+ for (Mixer *mixer=Mixer::mixers().first(); mixer!=0; mixer=Mixer::mixers().next())
+ {
+ QString s;
+ s.sprintf("%i. %s", n, mixer->mixerName().ascii());
+ lst << s;
+ n++;
+ }
+
+ bool ok = FALSE;
+ QString res = KInputDialog::getItem( i18n("Mixers"),
+ i18n("Available mixers:"),
+ lst, 1, FALSE, &ok, this );
+ if ( ok )
+ {
+ Mixer *mixer = Mixer::mixers().at( lst.findIndex( res ) );
+ if (!mixer)
+ KMessageBox::sorry( this, i18n("Invalid mixer entered.") );
+ else
+ {
+ delete m_errorLabel;
+ m_errorLabel = 0;
+
+ _mixer = mixer;
+ // Create the ViewApplet by calling positionChange() ... :)
+ // To take over reversedDir and (more important) to create the mixer widget
+ // if necessary!
+ positionChange(position());
+ }
+ }
+}
+
+
+void KMixApplet::about()
+{
+ KAboutApplication aboutDlg(&m_aboutData);
+ aboutDlg.exec();
+}
+
+void KMixApplet::help()
+{
+}
+
+
+void KMixApplet::positionChange(Position pos) {
+ orientationChange( orientation() );
+ QResizeEvent e( size(), size() ); // from KPanelApplet::positionChange
+ resizeEvent( &e ); // from KPanelApplet::positionChange
+
+ if ( m_errorLabel == 0) {
+ // do this only after we deleted the error label
+ if (m_mixerWidget) {
+ saveConfig(); // save the applet before recreating it
+ _layout->remove(m_mixerWidget);
+ delete m_mixerWidget;
+ }
+ m_mixerWidget = new ViewApplet( this, _mixer->name(), _mixer, 0, pos );
+ connect ( m_mixerWidget, SIGNAL(appletContentChanged()), this, SLOT(updateGeometrySlot()) );
+ m_mixerWidget->createDeviceWidgets();
+ _layout->add(m_mixerWidget);
+ _layout->activate();
+
+ loadConfig();
+ setColors();
+
+ const QSize panelAppletConstrainedSize = sizeHint();
+ m_mixerWidget->setGeometry( 0, 0, panelAppletConstrainedSize.width(), panelAppletConstrainedSize.height() );
+ resize( panelAppletConstrainedSize.width(), panelAppletConstrainedSize.height() );
+ //setFixedSize(panelAppletConstrainedSize.width(), panelAppletConstrainedSize.height() );
+ //kdDebug(67100) << "KMixApplet::positionChange(). New MDW is at " << panelAppletConstrainedSize << endl;
+ m_mixerWidget->show();
+ //connect( _mixer, SIGNAL(newVolumeLevels()), m_mixerWidget, SLOT(refreshVolumeLevels()) );
+ }
+}
+
+
+/************* GEOMETRY STUFF START ********************************/
+void KMixApplet::resizeEvent(QResizeEvent *e)
+{
+ //kdDebug(67100) << "KMixApplet::resizeEvent(). New MDW is at " << e->size() << endl;
+
+ if ( position() == KPanelApplet::pLeft || position() == KPanelApplet::pRight ) {
+ if ( m_mixerWidget ) m_mixerWidget->resize(e->size().width(),m_mixerWidget->height());
+ if ( m_errorLabel ) m_errorLabel ->resize(e->size().width(),m_errorLabel ->height());
+ }
+ else {
+ if ( m_mixerWidget ) m_mixerWidget->resize(m_mixerWidget->width(), e->size().height());
+ if ( m_errorLabel ) m_errorLabel ->resize(m_errorLabel ->width() ,e->size().height());
+ }
+
+
+ // resizing changes our own sizeHint(), because we must take the new PanelSize in account.
+ // So updateGeometry() is amust for us.
+ //kdDebug(67100) << "KMixApplet::resizeEvent(). UPDATE GEOMETRY" << endl;
+ updateGeometry();
+ //kdDebug(67100) << "KMixApplet::resizeEvent(). EMIT UPDATE LAYOUT" << endl;
+ emit updateLayout();
+}
+
+void KMixApplet::updateGeometrySlot() {
+ updateGeometry();
+}
+
+
+QSize KMixApplet::sizeHint() const {
+ //kdDebug(67100) << "KMixApplet::sizeHint()\n";
+ QSize qsz;
+ if ( m_errorLabel !=0 ) {
+ qsz = m_errorLabel->sizeHint();
+ }
+ else if ( m_mixerWidget != 0) {
+ qsz = m_mixerWidget->sizeHint();
+ }
+ else {
+ // During construction of m_mixerWidget or if something goes wrong:
+ // Return something that should resemble our former sizeHint().
+ qsz = size();
+ }
+ //kdDebug(67100) << "KMixApplet::sizeHint() leftright =" << qsz << "\n";
+ return qsz;
+}
+
+/**
+ We need widthForHeight() and heigthForWidth() only because KPanelApplet::updateLayout does relayouts
+ using this method. Actually we ignore the passed paramater and just return our preferred size.
+*/
+int KMixApplet::widthForHeight(int) const {
+ //kdDebug(67100) << "KMixApplet::widthForHeight() = " << sizeHint().width() << endl;
+ return sizeHint().width();
+}
+int KMixApplet::heightForWidth(int) const {
+ //kdDebug(67100) << "KMixApplet::heightForWidth() = " << sizeHint().height() << endl;
+ return sizeHint().height();
+}
+
+
+
+
+QSizePolicy KMixApplet::sizePolicy() const {
+ // return QSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
+ if ( orientation() == Qt::Vertical ) {
+ //kdDebug(67100) << "KMixApplet::sizePolicy=(Ignored,Fixed)\n";
+ return QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ }
+ else {
+ //kdDebug(67100) << "KMixApplet::sizePolicy=(Fixed,Ignored)\n";
+ return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ }
+}
+
+/************* GEOMETRY STUFF END ********************************/
+
+
+void KMixApplet::reportBug()
+{
+ KBugReport bugReportDlg(this, true, &m_aboutData);
+ bugReportDlg.exec();
+}
+
+
+/******************* COLOR STUFF START ***********************************/
+
+void KMixApplet::preferences()
+{
+ if ( !m_pref )
+ {
+ m_pref = new AppletConfigDialog( this );
+ connect(m_pref, SIGNAL(finished()), SLOT(preferencesDone()));
+ connect( m_pref, SIGNAL(applied()), SLOT(applyPreferences()) );
+
+ m_pref->setActiveColors(_colors.high , _colors.low , _colors.back);
+ m_pref->setMutedColors (_colors.mutedHigh, _colors.mutedLow, _colors.mutedBack);
+
+ m_pref->setUseCustomColors( _customColors );
+
+ }
+
+ m_pref->show();
+ m_pref->raise();
+}
+
+
+void KMixApplet::preferencesDone()
+{
+ m_pref->delayedDestruct();
+ m_pref = 0;
+}
+
+void KMixApplet::applyPreferences()
+{
+ if (!m_pref)
+ return;
+
+ // copy the colors from the prefs dialog
+ m_pref->activeColors(_colors.high , _colors.low , _colors.back);
+ m_pref->mutedColors (_colors.mutedHigh, _colors.mutedLow, _colors.mutedBack);
+ _customColors = m_pref->useCustomColors();
+ if (!m_mixerWidget)
+ return;
+
+ /*
+ QSize si = m_mixerWidget->size();
+ m_mixerWidget->resize( si );
+ */
+ setColors();
+ saveConfig();
+}
+
+void KMixApplet::paletteChange ( const QPalette &) {
+ if ( ! _customColors ) {
+ // We take over Colors from paletteChange(), if the user has not set custom colors.
+ // ignore the given QPalette and use the values from KGlobalSettings instead
+ _colors.high = KGlobalSettings::highlightColor();
+ _colors.low = KGlobalSettings::baseColor();
+ _colors.back = backColor;
+ setColors( _colors );
+ }
+}
+
+void KMixApplet::setColors()
+{
+ if ( !_customColors ) {
+ KMixApplet::Colors cols;
+ cols.high = highColor;
+ cols.low = lowColor;
+ cols.back = backColor;
+ cols.mutedHigh = mutedHighColor;
+ cols.mutedLow = mutedLowColor;
+ cols.mutedBack = mutedBackColor;
+
+ setColors( cols );
+ } else
+ setColors( _colors );
+}
+
+void KMixApplet::setColors( const Colors &color )
+{
+ if ( m_mixerWidget == 0 ) {
+ // can happen for example after a paletteChange()
+ return;
+ }
+ QPtrList<QWidget> &mdws = m_mixerWidget->_mdws;
+ for ( QWidget* qmdw=mdws.first(); qmdw != 0; qmdw=mdws.next() ) {
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- temporary check. Later we *know* that it is correct
+ static_cast<MixDeviceWidget*>(qmdw)->setColors( color.high, color.low, color.back );
+ static_cast<MixDeviceWidget*>(qmdw)->setMutedColors( color.mutedHigh, color.mutedLow, color.mutedBack );
+ }
+ }
+}
+
+/******************* COLOR STUFF END ***********************************/
+
+#include "kmixapplet.moc"
+
diff --git a/kmix/kmixapplet.desktop b/kmix/kmixapplet.desktop
new file mode 100644
index 00000000..1295ecdd
--- /dev/null
+++ b/kmix/kmixapplet.desktop
@@ -0,0 +1,110 @@
+[Desktop Entry]
+Type=Plugin
+Name=Sound Mixer
+Name[bg]=Аудио миксер
+Name[br]=Mesker ar Son
+Name[bs]=Zvučni mikser
+Name[ca]=Mesclador de so
+Name[cs]=Zvukový směšovač
+Name[cy]=Cymysgydd Sŵn
+Name[da]=Lydmikser
+Name[de]=Lautstärkeregler
+Name[el]=Μείκτης ήχου
+Name[eo]=Sonmiksilo
+Name[es]=Mezclador de audio
+Name[et]=Helimikser
+Name[eu]=Soinu nahasgailua
+Name[fa]=مخلوط‌کن صدا
+Name[fi]=Äänimikseri
+Name[fr]=Console de mixage
+Name[ga]=Meascthóir Fuaime
+Name[gl]=Mesturador de Son
+Name[he]=מערבל צליל
+Name[hi]=ध्वनि मिक्सर
+Name[hr]=Mixer zvuka
+Name[hu]=Hangkeverő
+Name[is]=Hljóðblöndun
+Name[it]=Mixer sonoro
+Name[ja]=サウンドミキサー
+Name[kk]=Дыбыс микшері
+Name[km]=កម្មវិធី​លាយ​សំឡេង
+Name[ko]=소리 믹서
+Name[mk]=Миксета за звук
+Name[ms]=Pengadun Bunyi
+Name[nb]=Lydmikser
+Name[nds]=Klangmischer
+Name[ne]=ध्वनि मिक्सर
+Name[nl]=Geluidsmixer
+Name[nn]=Lydmiksar
+Name[pa]=ਸਾਊਂਡ ਮਿਕਸਰ
+Name[pl]=Mikser dźwięku
+Name[pt]=Mistura de Áudio
+Name[pt_BR]=Mixagem de som
+Name[ro]=Mixer de sunet
+Name[ru]=Микшер
+Name[sk]=Zvukový mixér
+Name[sl]=Mešalnik zvoka
+Name[sr]=Звучна миксета
+Name[sr@Latn]=Zvučna mikseta
+Name[sv]=Ljudmixer
+Name[ta]=ஒலிக் ஒன்றுசேர்ப்பான்
+Name[tg]=Омехтакунаки Овоз
+Name[th]=ปรับแต่งผสมเสียง
+Name[tr]=Ses Karıştırıcı
+Name[uk]=Аудіомікшер
+Name[uz]=Audio mikser
+Name[uz@cyrillic]=Аудио миксер
+Name[wa]=Maxheu d' sons
+Name[zh_CN]=混音器
+Name[zh_HK]=聲音混音器
+Name[zh_TW]=音效混音器
+
+Comment=Volume and sound channel mixer control
+Comment[bg]=Управление на силата на звука и каналите
+Comment[br]=Renadur meskañ kanol ha nerzh
+Comment[bs]=Kontrola miksera kanala glasnoće i zvuka
+Comment[ca]=Control i mesclador de volum i canals de so
+Comment[cs]=Ovládání hlasitosti a zvukových kanálů
+Comment[da]=Mikserkontrol for lydstyrke og lydkanal
+Comment[de]=Kontrolle der Lautstärke
+Comment[el]=Στοιχείο μείκτη ήχων και έντασης καναλιών
+Comment[eo]=Stirado de volumo kaj sonkanalmiksilo
+Comment[es]=Control del volumen y los canales de sonido del mezclador
+Comment[et]=Helitugevuse ja helikanalite seadistamine
+Comment[eu]=Bolumena eta soinu-kanalen nahasketarako kontrola
+Comment[fa]=کنترل مخلوط‌کن مجرای صدا و حجم صدا
+Comment[fi]=Äänenvoimakkuuden ja äänikanavien mikserin hallinta
+Comment[fr]=Contrôle du volume et des canaux de la console de mixage
+Comment[gl]=Control do volume e da canle de son do mesturador
+Comment[he]=שינוי הגדרות עוצמת קול של כרטיס הקול
+Comment[hu]=Hangerőbeállító és keverő
+Comment[is]=Stjórnun á styrk og hljóðrása blöndun
+Comment[it]=Controllo del volume e del mixer sonoro
+Comment[ja]=ボリュームおよびサウンドチャンネルミキサー制御
+Comment[kk]=Дыбыс үнділігі мен арналарды басқару
+Comment[km]=ឧបករណ៍​លាយ​ឆានែល​កម្រិត​សំឡេង និង​សំឡេង​
+Comment[ko]=음량과 사운드 채널 믹서 조정
+Comment[lt]=Garso ir garso kanalų maišyklės valdymas
+Comment[nb]=Miksekontroll for lydnivået og lydkanalene
+Comment[nds]=Kuntrull för den Luutstärk- un Klangkanaalmischer
+Comment[ne]=भोल्युम र ध्वनि च्यानल मिक्सर नियन्त्रण
+Comment[nl]=Bedieningspaneel voor het regelen van het volume en de geluidskanalen
+Comment[nn]=Lydstyrke- og kanalmiksarkontroll
+Comment[pl]=Sterowanie mikserem dźwięku i kanałów
+Comment[pt]=Controlo de volume e canais de som
+Comment[pt_BR]=Controle de volume e mixer de canais de som
+Comment[ru]=Управление громкостью и звуковыми каналами
+Comment[sk]=Riadenie hlasitosti a zvukového kanálu mixéru
+Comment[sl]=Nadzor glasnosti in mešalnik zvočnih kanalov
+Comment[sr]=Контрола јачине и миксета звучних канала
+Comment[sr@Latn]=Kontrola jačine i mikseta zvučnih kanala
+Comment[sv]=Volymkontroll och ljudkanalmixer
+Comment[th]=โปรแกรมควบคุมช่องเสียงและระดับเสียง
+Comment[tr]=Ses düzeyi ve ses kanalı karıştırıcısını kontrol edin
+Comment[uk]=Керування гучністю і міксером звукових каналів
+Comment[zh_CN]=音量和声道混音器控制
+Comment[zh_HK]=音量與聲道混音控制器
+Comment[zh_TW]=音量與聲道混音器控制
+
+Icon=kmix
+X-KDE-Library=kmix_panelapplet
diff --git a/kmix/kmixapplet.h b/kmix/kmixapplet.h
new file mode 100644
index 00000000..11c6225a
--- /dev/null
+++ b/kmix/kmixapplet.h
@@ -0,0 +1,131 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KMIXAPPLET_H
+#define KMIXAPPLET_H
+
+// Qt
+#include <qlayout.h>
+#include <qptrlist.h>
+#include <qwidget.h>
+
+// KDE
+#include <kaboutdata.h>
+#include <kdialogbase.h>
+#include <kpanelapplet.h>
+
+//KMix
+#include "viewapplet.h"
+
+class Mixer;
+class ColorWidget;
+class KMixApplet;
+
+
+class AppletConfigDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ AppletConfigDialog( QWidget * parent=0, const char * name=0 );
+ virtual ~AppletConfigDialog() {};
+
+ void setActiveColors(const QColor& high, const QColor& low, const QColor& back);
+ void activeColors(QColor& high, QColor& low, QColor& back) const;
+
+ void setMutedColors(const QColor& high, const QColor& low, const QColor& back);
+ void mutedColors(QColor& high, QColor& low, QColor& back) const;
+
+ void setUseCustomColors(bool);
+ bool useCustomColors() const;
+
+ protected slots:
+ virtual void slotOk();
+ virtual void slotApply();
+
+ signals:
+ void applied();
+ private:
+ ColorWidget* colorWidget;
+};
+
+
+class KMixApplet : public KPanelApplet
+{
+ Q_OBJECT
+
+public:
+ KMixApplet( const QString& configFile, Type t = Normal,
+ QWidget *parent = 0, const char *name = 0 );
+ virtual ~KMixApplet();
+
+ struct Colors {
+ QColor high, low, back, mutedHigh, mutedLow, mutedBack;
+ };
+
+ void about();
+ void help();
+ void preferences();
+ void reportBug();
+ void paletteChange ( const QPalette & oldPalette );
+
+ QSize sizeHint() const;
+ QSizePolicy sizePolicy() const;
+ int widthForHeight(int) const;
+ int heightForWidth(int) const;
+
+protected slots:
+ void selectMixer();
+ void applyPreferences();
+ void preferencesDone();
+ void updateGeometrySlot();
+
+protected:
+ void resizeEvent( QResizeEvent * );
+ void saveConfig();
+ void saveConfig( KConfig *config, const QString &grp );
+ void loadConfig();
+ void loadConfig( KConfig *config, const QString &grp );
+
+private:
+ void positionChange(Position);
+ void setColors();
+ void setColors( const Colors &color );
+
+ ViewApplet *m_mixerWidget;
+ QPushButton *m_errorLabel;
+ AppletConfigDialog *m_pref;
+
+ static int s_instCount;
+ Mixer *_mixer;
+
+ KMixApplet::Colors _colors;
+ bool _customColors;
+
+ QLayout* _layout;
+
+ QString _mixerId;
+ QString _mixerName;
+
+ KAboutData m_aboutData;
+};
+
+
+#endif
diff --git a/kmix/kmixctrl.cpp b/kmix/kmixctrl.cpp
new file mode 100644
index 00000000..3dbf4f4e
--- /dev/null
+++ b/kmix/kmixctrl.cpp
@@ -0,0 +1,90 @@
+/*
+ * kmixctrl - kmix volume save/restore utility
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mixertoolbox.h"
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <qptrlist.h>
+
+#include "kmixtoolbox.h"
+#include "mixer.h"
+#include "version.h"
+
+static const char description[] =
+I18N_NOOP("kmixctrl - kmix volume save/restore utility");
+
+static KCmdLineOptions options[] =
+{
+ { "s", 0, 0 },
+ { "save", I18N_NOOP("Save current volumes as default"), 0 },
+ { "r", 0, 0 },
+ { "restore", I18N_NOOP("Restore default volumes"), 0 },
+ KCmdLineLastOption
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+};
+
+extern "C" KDE_EXPORT int kdemain(int argc, char *argv[])
+{
+ KLocale::setMainCatalogue("kmix");
+ KAboutData aboutData( "kmixctrl", I18N_NOOP("KMixCtrl"),
+ APP_VERSION, description, KAboutData::License_GPL,
+ "(c) 2000 by Stefan Schimanski");
+
+ aboutData.addAuthor("Stefan Schimanski", 0, "1Stein@gmx.de");
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ KApplication app( false, false );
+
+ // get maximum values
+ KConfig *config= new KConfig("kmixrc", true, false);
+ config->setGroup("Misc");
+ delete config;
+
+ // create mixers
+ QString dummyStringHwinfo;
+ MixerToolBox::initMixer(Mixer::mixers(), false, dummyStringHwinfo);
+
+ // load volumes
+ if ( args->isSet("restore") )
+ {
+ for (Mixer *mixer=Mixer::mixers().first(); mixer!=0; mixer=Mixer::mixers().next()) {
+ mixer->volumeLoad( KGlobal::config() );
+ }
+ }
+
+ // save volumes
+ if ( args->isSet("save") )
+ {
+ for (Mixer *mixer=Mixer::mixers().first(); mixer!=0; mixer=Mixer::mixers().next())
+ mixer->volumeSave( KGlobal::config() );
+ }
+
+ MixerToolBox::deinitMixer();
+
+ return 0;
+}
diff --git a/kmix/kmixctrl_restore.desktop b/kmix/kmixctrl_restore.desktop
new file mode 100644
index 00000000..52e25fc8
--- /dev/null
+++ b/kmix/kmixctrl_restore.desktop
@@ -0,0 +1,70 @@
+[Desktop Entry]
+Type=Service
+Name=Restore Mixer Settings
+Name[af]=Herstel Menger Instellings
+Name[az]=Qarışdırıcı Qurğularını Yenidən Yükle
+Name[bg]=Възстановяване на настройките на миксера
+Name[bn]=মিক্সার সেটিংস পুনঃস্থাপন করে
+Name[br]=Assav kefluniadur ar mesker
+Name[bs]=Vrati postavke miksera
+Name[ca]=Restaura l'arranjament del mesclador
+Name[cs]=Obnovit nastavení směšovače
+Name[cy]=Adfer Gosodiadau Cymysgydd
+Name[da]=Genopret mikseropsætning
+Name[de]=Lautstärkeeinstellungen wiederherstellen
+Name[el]=Αποκατάσταση ρυθμίσεων μείκτη
+Name[eo]=Restarigu Miksilagordon
+Name[es]=Restaurar opciones del mezclador
+Name[et]=Mikseri seadistuste taastamine
+Name[eu]=Nahasgailuaren ezarpenak berreskuratu
+Name[fa]=باز‌گردانی تنظیمات مخلوط‌کن
+Name[fi]=Palauta mikserin asetukset
+Name[fr]=Restaurer la configuration du mixage
+Name[gl]=Restaura-los Parámetros do Mesturador
+Name[he]=שיחזור הגדרות המערבל
+Name[hi]=मिक्सर विन्यास बहाल करें
+Name[hr]=Vrati postavke miksera
+Name[hu]=A hangkeverő beállításainak visszatöltése
+Name[id]=Kembalikan seting Mixer
+Name[is]=Sækja aftur stillingar hljóðrása
+Name[it]=Ripristina le impostazioni del mixer
+Name[ja]=ミキサーの設定を復元
+Name[kk]=Микшер баптауларын қалпына келтіру
+Name[km]=ស្ដារ​ការ​កំណត់​ឧបករណ៍​លាយ​ឡើង​វិញ
+Name[ko]=믹서 설정 복원
+Name[lt]=Gražinti mikšerio parametrus
+Name[lv]=Atjauno Miksera Uzstādījumus
+Name[mk]=Враќање на поставувањата на миксетата
+Name[ms]=Pulihkan Tetapan Pengadun
+Name[mt]=Reġġa' lura setings tal-Mixer
+Name[nb]=Gjennopprett mikserinnstillinger
+Name[nds]=Mischerinstellen wedderherstellen
+Name[ne]=मिक्सर सेटिङ पूर्वावस्थामा ल्याउनुहोस्
+Name[nl]=Mixerinstellingen herstellen
+Name[nn]=Gjenopprett miksarinnstillingar
+Name[pl]=Odtwarzanie ustawień miksera
+Name[pt]=Repor a Configuração do Volume
+Name[pt_BR]=Restaurar preferências do mixer
+Name[ro]=Reface setările mixerului
+Name[ru]=Восстанавливает настройки микшера
+Name[se]=Máhcat mixerheivehusat
+Name[sk]=Obnov Nastavenia Mixéra
+Name[sl]=Obnovi nastavitve mešalnika
+Name[sr]=Поврати поставке миксете
+Name[sr@Latn]=Povrati postavke miksete
+Name[sv]=Återställ mixerinställningar
+Name[ta]=ஒன்றுசேர்க்கும் அமைப்புகளை மீட்கவும்
+Name[tg]=Аз нав захиракунии Гузоришҳои Омехтакунак
+Name[th]=เรียกคืนค่าที่ตั้งไว้ของมิกเซอร์
+Name[tr]=Karıştırıcı Ayarlarını Yeniden Yükle
+Name[uk]=Відновити параметри мікшера
+Name[uz]=Mikserning moslamalarini qayta tiklash
+Name[uz@cyrillic]=Миксернинг мосламаларини қайта тиклаш
+Name[ven]=Vhuedzedzani vhuvha ha tshitanganisi
+Name[wa]=Rimete come divant les apontiaedjes d maxheu d' sons
+Name[xh]=Gcina kwakhona izicwangciso zoMxubi
+Name[zh_CN]=恢复混音器设置
+Name[zh_HK]=回復混音器設置
+Name[zh_TW]=回復混音器設定
+Name[zu]=Gcina futhi izilungiso zoMxubi
+Exec=kmixctrl --restore
diff --git a/kmix/kmixdockwidget.cpp b/kmix/kmixdockwidget.cpp
new file mode 100644
index 00000000..18e19af0
--- /dev/null
+++ b/kmix/kmixdockwidget.cpp
@@ -0,0 +1,391 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ * Copyright (C) 2001 Preston Brown <pbrown@kde.org>
+ * Copyright (C) 2003 Sven Leiber <s.leiber@web.de>
+ * Copyright (C) 2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <kaction.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kpanelapplet.h>
+#include <kpopupmenu.h>
+#include <kglobalsettings.h>
+#include <kdialog.h>
+#include <kaudioplayer.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kwin.h>
+
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qtooltip.h>
+#include <X11/Xlib.h>
+#include <fixx11h.h>
+
+#include "dialogselectmaster.h"
+#include "mixer.h"
+#include "mixdevicewidget.h"
+#include "kmixdockwidget.h"
+#include "kwin.h"
+#include "viewdockareapopup.h"
+
+KMixDockWidget::KMixDockWidget( Mixer *mixer, QWidget *parent, const char *name, bool volumePopup )
+ : KSystemTray( parent, name ),
+ m_mixer(mixer),
+ _dockAreaPopup(0L),
+ _audioPlayer(0L),
+ _playBeepOnVolumeChange(false), // disabled due to triggering a "Bug"
+ _oldToolTipValue(-1),
+ _oldPixmapType('-'),
+ _volumePopup(volumePopup)
+{
+ Mixer* preferredMasterMixer = Mixer::masterCard();
+ if ( preferredMasterMixer != 0 ) {
+ m_mixer = preferredMasterMixer;
+ }
+ MixDevice* mdMaster = Mixer::masterCardDevice();
+ if ( mdMaster != 0 ) {
+ m_mixer->setMasterDevice(mdMaster->getPK()); // !! using both Mixer::masterCard() and m_mixer->masterDevice() is nonsense !!
+ }
+ createActions();
+ createMasterVolWidget();
+ connect(this, SIGNAL(quitSelected()), kapp, SLOT(quitExtended()));
+}
+
+KMixDockWidget::~KMixDockWidget()
+{
+ delete _audioPlayer;
+ delete _dockAreaPopup;
+}
+
+void KMixDockWidget::createActions()
+{
+ // Put "Mute" selector in context menu
+ (void)new KToggleAction( i18n( "M&ute" ), 0, this, SLOT( dockMute() ),
+ actionCollection(), "dock_mute" );
+ KAction *a = actionCollection()->action( "dock_mute" );
+ KPopupMenu *popupMenu = contextMenu();
+ if ( a ) a->plug( popupMenu );
+
+ // Put "Select Master Channel" dialog in context menu
+ if ( m_mixer != 0 ) {
+ (void)new KAction( i18n("Select Master Channel..."), 0, this, SLOT(selectMaster()),
+ actionCollection(), "select_master");
+ KAction *a2 = actionCollection()->action( "select_master" );
+ if (a2) a2->plug( popupMenu );
+ }
+
+ // Setup volume preview
+ if ( _playBeepOnVolumeChange ) {
+ _audioPlayer = new KAudioPlayer("KDE_Beep_Digital_1.ogg");
+ }
+}
+
+
+void
+KMixDockWidget::createMasterVolWidget()
+{
+ // Reset flags, so that the dock icon will be reconstructed
+ _oldToolTipValue = -1;
+ _oldPixmapType = '-';
+
+ if (m_mixer == 0) {
+ // In case that there is no mixer installed, there will be no newVolumeLevels() signal's
+ // Thus we prepare the dock areas manually
+ setVolumeTip();
+ updatePixmap();
+ return;
+ }
+ // create devices
+
+ _dockAreaPopup = new ViewDockAreaPopup(0, "dockArea", m_mixer, 0, this);
+ _dockAreaPopup->createDeviceWidgets();
+ m_mixer->readSetFromHWforceUpdate(); // after changing the master device, make sure to re-read (otherwise no "changed()" signals might get sent by the Mixer
+ /* With the recently introduced QSocketNotifier stuff, we can't rely on regular timer updates
+ any longer. Also the readSetFromHWforceUpdate() won't be enough. As a workaround, we trigger
+ all "repaints" manually here.
+ The call to m_mixer->readSetFromHWforceUpdate() is most likely superfluous, even if we don't use QSocketNotifier (e.g. in backends OSS, Solaris, ...)
+ */
+ setVolumeTip();
+ updatePixmap();
+ /* We are setting up 3 connections:
+ * Refreshig the _dockAreaPopup (not anymore neccesary, because ViewBase already does it)
+ * Refreshing the Tooltip
+ * Refreshing the Icon
+ *
+ */
+ // connect( m_mixer, SIGNAL(newVolumeLevels()), _dockAreaPopup, SLOT(refreshVolumeLevels()) );
+ connect( m_mixer, SIGNAL(newVolumeLevels()), this, SLOT(setVolumeTip() ) );
+ connect( m_mixer, SIGNAL(newVolumeLevels()), this, SLOT(updatePixmap() ) );
+}
+
+
+void KMixDockWidget::selectMaster()
+{
+ DialogSelectMaster* dsm = new DialogSelectMaster(m_mixer);
+ connect ( dsm, SIGNAL(newMasterSelected(int, QString&)), SLOT( handleNewMaster(int,QString&)) );
+ dsm->show();
+ // !! The dialog is modal. Does it delete itself?
+}
+
+
+void KMixDockWidget::handleNewMaster(int soundcard_id, QString& channel_id) // !! @todo rework parameters
+{
+ //kdDebug(67100) << "KMixDockWidget::handleNewMaster() soundcard_id=" << soundcard_id << " , channel_id=" << channel_id << endl;
+ Mixer *mixer = Mixer::mixers().at(soundcard_id);
+ if ( mixer == 0 ) {
+ kdError(67100) << "KMixDockWidget::createPage(): Invalid Mixer (soundcard_id=" << soundcard_id << ")" << endl;
+ return; // can not happen
+ }
+ m_mixer = mixer;
+ Mixer::setMasterCard(mixer->id()); // We must save this information "somewhere".
+ Mixer::setMasterCardDevice( channel_id );
+ createMasterVolWidget();
+}
+
+
+void
+KMixDockWidget::setVolumeTip()
+{
+ MixDevice *md = 0;
+ if ( _dockAreaPopup != 0 ) {
+ md = _dockAreaPopup->dockDevice();
+ }
+ QString tip = "";
+
+ int newToolTipValue = 0;
+ if ( md == 0 )
+ {
+ tip = i18n("Mixer cannot be found"); // !! text could be reworked
+ newToolTipValue = -2;
+ }
+ else
+ {
+ long val = -1;
+ if ( md->maxVolume() != 0 ) {
+ val = (md->getVolume().getAvgVolume(Volume::MMAIN)*100 )/( md->maxVolume() );
+ }
+ newToolTipValue = val + 10000*md->isMuted();
+ if ( _oldToolTipValue != newToolTipValue ) {
+ tip = i18n( "Volume at %1%" ).arg( val );
+ if ( md->isMuted() ) {
+ tip += i18n( " (Muted)" );
+ }
+ }
+ // create a new "virtual" value. With that we see "volume changes" as well as "muted changes"
+ newToolTipValue = val + 10000*md->isMuted();
+ }
+
+ // The actual updating is only done when the "toolTipValue" was changed
+ if ( newToolTipValue != _oldToolTipValue ) {
+ // changed (or completely new tooltip)
+ if ( _oldToolTipValue >= 0 ) {
+ // there was an old Tooltip: remove it
+ QToolTip::remove(this);
+ }
+ QToolTip::add(this, tip);
+ }
+ _oldToolTipValue = newToolTipValue;
+}
+
+void
+KMixDockWidget::updatePixmap()
+{
+ MixDevice *md = 0;
+ if ( _dockAreaPopup != 0 ) {
+ md = _dockAreaPopup->dockDevice();
+ }
+ char newPixmapType;
+ if ( md == 0 )
+ {
+ newPixmapType = 'e';
+ }
+ else if ( md->isMuted() )
+ {
+ newPixmapType = 'm';
+ }
+ else
+ {
+ newPixmapType = 'd';
+ }
+
+
+ if ( newPixmapType != _oldPixmapType ) {
+ // Pixmap must be changed => do so
+ switch ( newPixmapType ) {
+ case 'e': setPixmap( loadIcon( "kmixdocked_error" ) ); break;
+ case 'm': setPixmap( loadIcon( "kmixdocked_mute" ) ); break;
+ case 'd': setPixmap( loadIcon( "kmixdocked" ) ); break;
+ }
+ }
+
+ _oldPixmapType = newPixmapType;
+}
+
+void
+KMixDockWidget::mousePressEvent(QMouseEvent *me)
+{
+ if ( _dockAreaPopup == 0 ) {
+ return KSystemTray::mousePressEvent(me);
+ }
+
+ // esken: Due to overwhelming request, LeftButton shows the ViewDockAreaPopup, if configured
+ // to do so. Otherwise the main window will be shown.
+ if ( me->button() == LeftButton )
+ {
+ if ( ! _volumePopup ) {
+ // Case 1: User wants to show main window => This is the KSystemTray default action
+ return KSystemTray::mousePressEvent(me);
+ }
+
+ // Case 2: User wants to show volume popup
+ if ( _dockAreaPopup->justHidden() )
+ return;
+
+ if ( _dockAreaPopup->isVisible() )
+ {
+ _dockAreaPopup->hide();
+ return;
+ }
+
+ int h = _dockAreaPopup->height();
+ int x = this->mapToGlobal( QPoint( 0, 0 ) ).x() + this->width()/2 - _dockAreaPopup->width()/2;
+ int y = this->mapToGlobal( QPoint( 0, 0 ) ).y() - h;
+ if ( y < 0 )
+ y = y + h + this->height();
+
+ _dockAreaPopup->move(x, y); // so that the mouse is outside of the widget
+
+ // Now handle Multihead displays. And also make sure that the dialog is not
+ // moved out-of-the screen on the right (see Bug 101742).
+ QDesktopWidget* vdesktop = QApplication::desktop();
+ const QRect& vScreenSize = vdesktop->screenGeometry(_dockAreaPopup);
+ if ( (x+_dockAreaPopup->width()) > (vScreenSize.width() + vScreenSize.x()) ) {
+ // move horizontally, so that it is completely visible
+ _dockAreaPopup->move(vScreenSize.width() + vScreenSize.x() - _dockAreaPopup->width() -1 , y);
+ } // horizontally out-of bound
+ else if ( x < vScreenSize.x() ) {
+ _dockAreaPopup->move(vScreenSize.x(), y);
+ }
+ // the above stuff could also be implemented vertically
+
+ _dockAreaPopup->show();
+ KWin::setState(_dockAreaPopup->winId(), NET::StaysOnTop | NET::SkipTaskbar | NET::SkipPager );
+
+ QWidget::mousePressEvent(me); // KSystemTray's shouldn't do the default action for this
+ return;
+ } // LeftMouseButton pressed
+ else if ( me->button() == MidButton ) {
+ toggleActive();
+ return;
+ }
+ else {
+ KSystemTray::mousePressEvent(me);
+ } // Other MouseButton pressed
+
+}
+
+void
+KMixDockWidget::mouseReleaseEvent( QMouseEvent *me )
+{
+
+ KSystemTray::mouseReleaseEvent(me);
+}
+
+void
+KMixDockWidget::wheelEvent(QWheelEvent *e)
+{
+ MixDevice *md = 0;
+ if ( _dockAreaPopup != 0 ) {
+ md = _dockAreaPopup->dockDevice();
+ }
+ if ( md != 0 )
+ {
+ Volume vol = md->getVolume();
+ int inc = vol.maxVolume() / 20;
+
+ if ( inc == 0 ) inc = 1;
+
+ for ( int i = 0; i < vol.count(); i++ ) {
+ int newVal = vol[i] + (inc * (e->delta() / 120));
+ if( newVal < 0 ) newVal = 0;
+ vol.setVolume( (Volume::ChannelID)i, newVal < vol.maxVolume() ? newVal : vol.maxVolume() );
+ }
+
+ if ( _playBeepOnVolumeChange ) {
+ _audioPlayer->play();
+ }
+ md->getVolume().setVolume(vol);
+ m_mixer->commitVolumeChange(md);
+ // refresh the toolTip (Qt removes it on a MouseWheel event)
+ // Mhhh, it doesn't work. Qt does not show it again.
+ setVolumeTip();
+ // Simulate a mouse move to make Qt show the tooltip again
+ QApplication::postEvent( this, new QMouseEvent( QEvent::MouseMove, QCursor::pos(), Qt::NoButton, Qt::NoButton ) );
+
+ }
+}
+
+void
+KMixDockWidget::dockMute()
+{
+ MixDevice *md = 0;
+ if ( _dockAreaPopup != 0 )
+ {
+ md = _dockAreaPopup->dockDevice();
+ if ( md != 0 ) {
+ md->setMuted( !md->isMuted() );
+ m_mixer->commitVolumeChange( md );
+ }
+ }
+}
+
+void
+KMixDockWidget::contextMenuAboutToShow( KPopupMenu* /* menu */ )
+{
+ KAction* showAction = actionCollection()->action("minimizeRestore");
+ if ( parentWidget() && showAction )
+ {
+ if ( parentWidget()->isVisible() )
+ {
+ showAction->setText( i18n("Hide Mixer Window") );
+ }
+ else
+ {
+ showAction->setText( i18n("Show Mixer Window") );
+ }
+ }
+
+ // Enable/Disable "Muted" menu item
+ MixDevice *md = 0;
+ if ( _dockAreaPopup != 0 )
+ {
+ md = _dockAreaPopup->dockDevice();
+ KToggleAction *dockMuteAction = static_cast<KToggleAction*>(actionCollection()->action("dock_mute"));
+ //kdDebug(67100) << "---> md=" << md << "dockMuteAction=" << dockMuteAction << "isMuted=" << md->isMuted() << endl;
+ if ( md != 0 && dockMuteAction != 0 ) {
+ dockMuteAction->setChecked( md->isMuted() );
+ }
+ }
+}
+
+#include "kmixdockwidget.moc"
+
diff --git a/kmix/kmixdockwidget.h b/kmix/kmixdockwidget.h
new file mode 100644
index 00000000..273e8533
--- /dev/null
+++ b/kmix/kmixdockwidget.h
@@ -0,0 +1,82 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ * Copyright (C) 2003 Sven Leiber <s.leiber@web.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KMIXDOCKWIDGET_H
+#define KMIXDOCKWIDGET_H
+
+class QFrame;
+class QString;
+#include <qwidget.h>
+#include <qvbox.h>
+
+#include <ksystemtray.h>
+
+class Mixer;
+class KAudioPlayer;
+class MixDeviceWidget;
+class Mixer;
+class ViewDockAreaPopup;
+class Volume;
+
+class KMixDockWidget : public KSystemTray {
+ Q_OBJECT
+
+ friend class KMixWindow;
+
+ public:
+ KMixDockWidget(Mixer *, QWidget *parent=0, const char *name=0, bool volumePopup=true);
+ ~KMixDockWidget();
+
+ void setErrorPixmap();
+ void ignoreNextEvent();
+ ViewDockAreaPopup* getDockAreaPopup();
+
+ Mixer *m_mixer;
+ ViewDockAreaPopup *_dockAreaPopup;
+ KAudioPlayer *_audioPlayer;
+
+ public slots:
+ void setVolumeTip();
+ void updatePixmap();
+
+ protected:
+ void createMasterVolWidget();
+ void createActions();
+ void mousePressEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void wheelEvent(QWheelEvent *);
+ void contextMenuAboutToShow( KPopupMenu* menu );
+ void toggleMinimizeRestore();
+
+ private:
+ bool _playBeepOnVolumeChange;
+ bool _ignoreNextEvent;
+ int _oldToolTipValue;
+ char _oldPixmapType;
+ bool _volumePopup;
+ private slots:
+ void dockMute();
+ void selectMaster();
+ void handleNewMaster(int soundcard_id, QString& channel_id);
+};
+
+#endif
diff --git a/kmix/kmixerwidget.cpp b/kmix/kmixerwidget.cpp
new file mode 100644
index 00000000..cf597fb4
--- /dev/null
+++ b/kmix/kmixerwidget.cpp
@@ -0,0 +1,266 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ * Copyright (C) 2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+// Qt
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qslider.h>
+#include <qstring.h>
+#include <qtooltip.h>
+#include <qapplication.h> // for QApplication::revsreseLayout()
+
+// KDE
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <ktabwidget.h>
+
+// KMix
+#include "mixdevicewidget.h"
+#include "kmixerwidget.h"
+#include "kmixtoolbox.h"
+#include "mixer.h"
+#include "viewinput.h"
+#include "viewoutput.h"
+#include "viewswitches.h"
+// KMix experimental
+#include "viewgrid.h"
+#include "viewsurround.h"
+
+
+/**
+ This widget is embedded in the KMix Main window. Each Hardware Mixer is visualized by one KMixerWidget.
+ KMixerWidget contains
+ (a) a headline where you can change Mixer's (if you got more than one Mixer)
+ (b) a Tab with 2-4 Tabs (containing View's with sliders, switches and other GUI elements visualizing the Mixer)
+ (c) A balancing slider
+ (d) A label containg the mixer name
+*/
+KMixerWidget::KMixerWidget( int _id, Mixer *mixer, const QString &mixerName,
+ MixDevice::DeviceCategory categoryMask,
+ QWidget * parent, const char * name, ViewBase::ViewFlags vflags )
+ : QWidget( parent, name ), _mixer(mixer), m_balanceSlider(0),
+ m_topLayout(0),
+ m_id( _id ),
+ _iconsEnabled( true ), _labelsEnabled( false ), _ticksEnabled( false ),
+ _valueStyle ( -1 ) // this definitely does not correspond to the 'default value display' style,
+ // so the style will be set by a later call to setValueStyle()
+
+{
+ m_categoryMask = categoryMask;
+
+ if ( _mixer )
+ {
+ createLayout(vflags);
+ }
+ else
+ {
+ // No mixer found
+ // !! Fix this: This is actually never shown!
+ QBoxLayout *layout = new QHBoxLayout( this );
+ QString s = i18n("Invalid mixer");
+ if ( !mixerName.isEmpty() )
+ s.append(" \"").append(mixerName).append("\"");
+ QLabel *errorLabel = new QLabel( s, this );
+ errorLabel->setAlignment( QLabel::AlignCenter | QLabel::WordBreak );
+ layout->addWidget( errorLabel );
+ }
+}
+
+KMixerWidget::~KMixerWidget()
+{
+}
+
+/**
+ * Creates the widgets as described in the KMixerWidget constructor
+ */
+void KMixerWidget::createLayout(ViewBase::ViewFlags vflags)
+{
+ // delete old objects
+ if( m_balanceSlider ) {
+ delete m_balanceSlider;
+ }
+ if( m_topLayout ) {
+ delete m_topLayout;
+ }
+
+ // create main layout
+ m_topLayout = new QVBoxLayout( this, 0, 3, "m_topLayout" );
+
+ // Create tabs of input + output + [...]
+ m_ioTab = new KTabWidget( this, "ioTab" );
+ m_topLayout->add( m_ioTab );
+
+
+ /*******************************************************************
+ * Now the main GUI is created.
+ * 1) Select a (GUI) profile, which defines which controls to show on which Tab
+ * 2a) Create the Tab's and the corresponding Views
+ * 2b) Create device widgets
+ * 2c) Add Views to Tab
+ ********************************************************************/
+ //KMixGUIProfile* prof = MixerToolbox::selectProfile(_mixer);
+
+
+ possiblyAddView(new ViewOutput ( m_ioTab, "output", i18n("Output"), _mixer, vflags ) );
+ possiblyAddView(new ViewInput( m_ioTab, "input", i18n("Input"), _mixer, vflags ) );
+ possiblyAddView(new ViewSwitches( m_ioTab, "switches", i18n("Switches"), _mixer, vflags ) );
+ if ( vflags & ViewBase::Experimental_SurroundView )
+ possiblyAddView( new ViewSurround( m_ioTab, "surround", i18n("Surround"), _mixer, vflags ) );
+ if ( vflags & ViewBase::Experimental_GridView )
+ possiblyAddView( new ViewGrid( m_ioTab, "grid", i18n("Grid"), _mixer, vflags ) );
+
+
+ // *** Lower part: Slider and Mixer Name ************************************************
+ QHBoxLayout *balanceAndDetail = new QHBoxLayout( m_topLayout, 8, "balanceAndDetail");
+ // Create the left-right-slider
+ m_balanceSlider = new QSlider( -100, 100, 25, 0, QSlider::Horizontal, this, "RightLeft" );
+ m_balanceSlider->setTickmarks( QSlider::Below );
+ m_balanceSlider->setTickInterval( 25 );
+ m_balanceSlider->setMinimumSize( m_balanceSlider->sizeHint() );
+ m_balanceSlider->setFixedHeight( m_balanceSlider->sizeHint().height() );
+
+ QLabel *mixerName = new QLabel(this, "mixerName");
+ mixerName->setText( _mixer->mixerName() );
+
+ balanceAndDetail->addSpacing( 10 );
+
+ balanceAndDetail->addWidget( m_balanceSlider );
+ balanceAndDetail->addWidget( mixerName );
+ balanceAndDetail->addSpacing( 10 );
+
+ connect( m_balanceSlider, SIGNAL(valueChanged(int)), this, SLOT(balanceChanged(int)) );
+ QToolTip::add( m_balanceSlider, i18n("Left/Right balancing") );
+
+ // --- "MenuBar" toggling from the various View's ---
+
+
+
+ show();
+ // kdDebug(67100) << "KMixerWidget::createLayout(): EXIT\n";
+}
+
+void KMixerWidget::possiblyAddView(ViewBase* vbase)
+{
+ if ( vbase->count() == 0 )
+ delete vbase;
+ else {
+ _views.push_back(vbase);
+ vbase ->createDeviceWidgets();
+ m_ioTab->addTab( vbase , vbase->caption() );
+ connect( vbase, SIGNAL(toggleMenuBar()), parentWidget(), SLOT(toggleMenuBar()) );
+ }
+}
+
+void KMixerWidget::setIcons( bool on )
+{
+ for ( std::vector<ViewBase*>::iterator it = _views.begin(); it != _views.end(); it++) {
+ ViewBase* mixerWidget = *it;
+ KMixToolBox::setIcons(mixerWidget->_mdws, on);
+ } // for all tabs
+}
+
+void KMixerWidget::setLabels( bool on )
+{
+ if ( _labelsEnabled!=on ) {
+ // value was changed
+ _labelsEnabled = on;
+ for ( std::vector<ViewBase*>::iterator it = _views.begin(); it != _views.end(); it++) {
+ ViewBase* mixerWidget = *it;
+ KMixToolBox::setLabels(mixerWidget->_mdws, on);
+ } // for all tabs
+ }
+}
+
+void KMixerWidget::setTicks( bool on )
+{
+ if ( _ticksEnabled!=on ) {
+ // value was changed
+ _ticksEnabled = on;
+ for ( std::vector<ViewBase*>::iterator it = _views.begin(); it != _views.end(); it++) {
+ ViewBase* mixerWidget = *it;
+ KMixToolBox::setTicks(mixerWidget->_mdws, on);
+ } // for all tabs
+ }
+}
+
+void KMixerWidget::setValueStyle( int vs )
+{
+ if ( _valueStyle!=vs ) {
+ // value was changed
+ _valueStyle = vs;
+ for ( std::vector<ViewBase*>::iterator it = _views.begin(); it != _views.end(); it++) {
+ ViewBase* mixerWidget = *it;
+ KMixToolBox::setValueStyle(mixerWidget->_mdws, vs);
+ } // for all tabs
+ }
+}
+
+
+/**
+ * @todo : Is the view list already filled, when loadConfig() is called?
+ */
+void KMixerWidget::loadConfig( KConfig *config, const QString &grp )
+{
+
+ for ( std::vector<ViewBase*>::iterator it = _views.begin(); it != _views.end(); it++) {
+ ViewBase* mixerWidget = *it;
+ QString viewPrefix = "View.";
+ viewPrefix += mixerWidget->name();
+ KMixToolBox::loadConfig(mixerWidget->_mdws, config, grp, viewPrefix );
+ mixerWidget->configurationUpdate();
+ } // for all tabs
+}
+
+
+
+void KMixerWidget::saveConfig( KConfig *config, const QString &grp )
+{
+ config->setGroup( grp );
+ // Write mixer name. It cannot be changed in the Mixer instance,
+ // it is only saved for diagnostical purposes (analyzing the config file).
+ config->writeEntry("Mixer_Name_Key", _mixer->mixerName());
+
+ for ( std::vector<ViewBase*>::iterator it = _views.begin(); it != _views.end(); it++) {
+ ViewBase* mixerWidget = *it;
+ QString viewPrefix = "View.";
+ viewPrefix += mixerWidget->name();
+ KMixToolBox::saveConfig(mixerWidget->_mdws, config, grp, viewPrefix );
+ } // for all tabs
+}
+
+
+void KMixerWidget::toggleMenuBarSlot() {
+ emit toggleMenuBar();
+}
+
+// in RTL mode, the slider is reversed, we cannot just connect the signal to setBalance()
+// hack arround it before calling _mixer->setBalance()
+void KMixerWidget::balanceChanged(int balance)
+{
+ if (QApplication::reverseLayout())
+ balance = -balance;
+
+ _mixer->setBalance( balance );
+}
+
+#include "kmixerwidget.moc"
diff --git a/kmix/kmixerwidget.h b/kmix/kmixerwidget.h
new file mode 100644
index 00000000..442bded5
--- /dev/null
+++ b/kmix/kmixerwidget.h
@@ -0,0 +1,118 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KMIXERWIDGET_H
+#define KMIXERWIDGET_H
+
+#include <vector>
+
+#include <qwidget.h>
+#include <qptrlist.h>
+class QString;
+class QGridLayout;
+
+#include <kpanelapplet.h>
+class KPopupMenu;
+
+#include "mixer.h"
+#include "mixdevicewidget.h"
+
+// QT
+class QSlider;
+
+
+// KDE
+class KActionCollection;
+class KActionMenu;
+class KConfig;
+class KTabWidget;
+
+// KMix
+class Mixer;
+#include "viewbase.h"
+class ViewInput;
+class ViewOutput;
+class ViewSwitches;
+// KMix experimental
+class ViewGrid;
+class ViewSurround;
+
+
+class KMixerWidget : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ KMixerWidget( int _id, Mixer *mixer, const QString &mixerName,
+ MixDevice::DeviceCategory categoryMask = MixDevice::ALL ,
+ QWidget *parent=0, const char *name=0, ViewBase::ViewFlags vflags=0 );
+ ~KMixerWidget();
+
+ enum KMixerWidgetIO { OUTPUT=0, INPUT };
+
+ const Mixer *mixer() const { return _mixer; };
+
+ int id() const { return m_id; };
+
+ KActionCollection* getActionCollection() const { return 0; /* m_actions; */ }
+
+ signals:
+ void masterMuted( bool );
+ void newMasterVolume(Volume vol);
+ void toggleMenuBar();
+
+ public slots:
+ void setTicks( bool on );
+ void setLabels( bool on );
+ void setIcons( bool on );
+ void setValueStyle( int vs );
+ void toggleMenuBarSlot();
+
+ void saveConfig( KConfig *config, const QString &grp );
+ void loadConfig( KConfig *config, const QString &grp );
+
+ private slots:
+ //void updateBalance();
+ void balanceChanged(int balance);
+
+ private:
+ Mixer *_mixer;
+ QSlider *m_balanceSlider;
+ QVBoxLayout *m_topLayout; // contains the Card selector, TabWidget and balance slider
+
+ KTabWidget* m_ioTab;
+
+ std::vector<ViewBase*> _views;
+ int m_id;
+
+ KActionMenu *m_toggleMixerChannels;
+
+ bool _iconsEnabled;
+ bool _labelsEnabled;
+ bool _ticksEnabled;
+ int _valueStyle;
+ MixDevice::DeviceCategory m_categoryMask;
+
+ void createLayout(ViewBase::ViewFlags vflags);
+ void possiblyAddView(ViewBase* vbase);
+};
+
+#endif
diff --git a/kmix/kmixprefdlg.cpp b/kmix/kmixprefdlg.cpp
new file mode 100644
index 00000000..e2788ceb
--- /dev/null
+++ b/kmix/kmixprefdlg.cpp
@@ -0,0 +1,132 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ * Copyright (C) 2001 Preston Brown <pbrown@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <qbuttongroup.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qradiobutton.h>
+
+#include <klocale.h>
+// For "kapp"
+#include <kapplication.h>
+
+#include "kmix.h"
+#include "kmixprefdlg.h"
+#include "kmixerwidget.h"
+
+
+KMixPrefDlg::KMixPrefDlg( QWidget *parent )
+ : KDialogBase( Plain, i18n( "Configure" ),
+ Ok|Cancel|Apply, Ok, parent )
+{
+ // general buttons
+ m_generalTab = plainPage( /* i18n("&General") */ );
+
+ QBoxLayout *layout = new QVBoxLayout( m_generalTab );
+ layout->setSpacing( KDialog::spacingHint() );
+
+ m_dockingChk = new QCheckBox( i18n("&Dock into panel"), m_generalTab );
+ layout->addWidget( m_dockingChk );
+ QWhatsThis::add(m_dockingChk, i18n("Docks the mixer into the KDE panel"));
+
+ m_volumeChk = new QCheckBox(i18n("Enable system tray &volume control"),
+ m_generalTab);
+ layout->addWidget(m_volumeChk);
+
+ m_showTicks = new QCheckBox( i18n("Show &tickmarks"), m_generalTab );
+ layout->addWidget( m_showTicks );
+ QWhatsThis::add(m_showTicks,
+ i18n("Enable/disable tickmark scales on the sliders"));
+
+ m_showLabels = new QCheckBox( i18n("Show &labels"), m_generalTab );
+ layout->addWidget( m_showLabels );
+ QWhatsThis::add(m_showLabels,
+ i18n("Enables/disables description labels above the sliders"));
+
+
+ m_onLogin = new QCheckBox( i18n("Restore volumes on login"), m_generalTab );
+ layout->addWidget( m_onLogin );
+
+ QBoxLayout *numbersLayout = new QHBoxLayout( layout );
+ QButtonGroup *numbersGroup = new QButtonGroup( 3, Qt::Horizontal, i18n("Numbers"), m_generalTab );
+ numbersGroup->setRadioButtonExclusive(true);
+ QLabel* qlbl = new QLabel( i18n("Volume Values: "), m_generalTab );
+ _rbNone = new QRadioButton( i18n("&None"), m_generalTab );
+ _rbAbsolute = new QRadioButton( i18n("A&bsolute"), m_generalTab );
+ _rbRelative = new QRadioButton( i18n("&Relative"), m_generalTab );
+ numbersGroup->insert(_rbNone);
+ numbersGroup->insert(_rbAbsolute);
+ numbersGroup->insert(_rbRelative);
+ numbersGroup->hide();
+
+ numbersLayout->add(qlbl);
+ numbersLayout->add(_rbNone);
+ numbersLayout->add(_rbAbsolute);
+ numbersLayout->add(_rbRelative);
+ numbersLayout->addStretch();
+
+ QBoxLayout *orientationLayout = new QHBoxLayout( layout );
+ QButtonGroup* orientationGroup = new QButtonGroup( 2, Qt::Horizontal, i18n("Orientation"), m_generalTab );
+ //orientationLayout->add(orientationGroup);
+ orientationGroup->setRadioButtonExclusive(true);
+ QLabel* qlb = new QLabel( i18n("Slider Orientation: "), m_generalTab );
+ _rbHorizontal = new QRadioButton(i18n("&Horizontal"), m_generalTab );
+ _rbVertical = new QRadioButton(i18n("&Vertical" ), m_generalTab );
+ orientationGroup->insert(_rbHorizontal);
+ orientationGroup->insert(_rbVertical);
+ orientationGroup->hide();
+ //orientationLayout->add(qlb);
+ //orientationLayout->add(orientationGroup);
+
+ orientationLayout->add(qlb);
+ orientationLayout->add(_rbHorizontal);
+ orientationLayout->add(_rbVertical);
+
+ orientationLayout->addStretch();
+ layout->addStretch();
+ enableButtonSeparator(true);
+
+ connect( this, SIGNAL(applyClicked()), this, SLOT(apply()) );
+ connect( this, SIGNAL(okClicked()), this, SLOT(apply()) );
+}
+
+KMixPrefDlg::~KMixPrefDlg()
+{
+}
+
+void KMixPrefDlg::apply()
+{
+ // disabling buttons => users sees that we are working
+ enableButtonOK(false);
+ enableButtonCancel(false);
+ enableButtonApply(false);
+ kapp->processEvents();
+ emit signalApplied( this );
+ // re-enable (in case of "Apply")
+ enableButtonOK(true);
+ enableButtonCancel(true);
+ enableButtonApply(true);
+}
+
+#include "kmixprefdlg.moc"
diff --git a/kmix/kmixprefdlg.h b/kmix/kmixprefdlg.h
new file mode 100644
index 00000000..3519d045
--- /dev/null
+++ b/kmix/kmixprefdlg.h
@@ -0,0 +1,67 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KPREFDLG_H
+#define KPREFDLG_H
+
+#include <kdialogbase.h>
+
+class KMixPrefWidget;
+class KMixApp;
+class QCheckBox;
+class QRadioButton;
+
+class
+KMixPrefDlg : public KDialogBase
+{
+ Q_OBJECT
+
+ friend class KMixWindow;
+
+ public:
+ KMixPrefDlg( QWidget *parent );
+ ~KMixPrefDlg();
+
+ signals:
+ void signalApplied( KMixPrefDlg *prefDlg );
+
+ private slots:
+ void apply();
+
+ private:
+ QFrame *m_generalTab;
+ KMixApp *m_mixApp;
+ KMixPrefWidget *m_mixPrefTab;
+
+ QCheckBox *m_dockingChk;
+ QCheckBox *m_volumeChk;
+ QCheckBox *m_hideOnCloseChk;
+ QCheckBox *m_showTicks;
+ QCheckBox *m_showLabels;
+ QCheckBox *m_onLogin;
+ QRadioButton *_rbVertical;
+ QRadioButton *_rbHorizontal;
+ QRadioButton *_rbNone;
+ QRadioButton *_rbAbsolute;
+ QRadioButton *_rbRelative;
+};
+
+#endif
diff --git a/kmix/kmixtoolbox.cpp b/kmix/kmixtoolbox.cpp
new file mode 100644
index 00000000..06a6ed36
--- /dev/null
+++ b/kmix/kmixtoolbox.cpp
@@ -0,0 +1,215 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include "qcolor.h"
+#include "qwidget.h"
+#include "qstring.h"
+
+//#include <kdebug.h>
+#include <kglobalaccel.h>
+#include <klocale.h>
+
+#include "mdwslider.h"
+#include "mdwswitch.h"
+#include "mixdevicewidget.h"
+#include "mixdevice.h"
+#include "mixer.h"
+
+#include "kmixtoolbox.h"
+
+/***********************************************************************************
+ KMixToolbox contains several GUI relevant methods that are shared between the
+ KMix Main Program, and the KMix Applet.
+ kmixctrl - as not non-GUI application - does NOT link to KMixToolBox.
+
+ This means: Shared GUI stuff goes into the KMixToolBox class , non-GUI stuff goes
+ into the MixerToolBox class.
+ ***********************************************************************************/
+void KMixToolBox::setIcons(QPtrList<QWidget> &mdws, bool on ) {
+ for ( QWidget *qmdw=mdws.first(); qmdw!=0; qmdw=mdws.next() ) {
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- play safe here
+ static_cast<MixDeviceWidget*>(qmdw)->setIcons( on );
+ }
+ }
+}
+
+void KMixToolBox::setLabels(QPtrList<QWidget> &mdws, bool on ) {
+ QWidget *qmdw;
+ for ( qmdw=mdws.first(); qmdw != 0; qmdw=mdws.next() ) {
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- play safe here
+ static_cast<MixDeviceWidget*>(qmdw)->setLabeled( on );
+ }
+ }
+}
+
+void KMixToolBox::setTicks(QPtrList<QWidget> &mdws, bool on ) {
+ QWidget *qmdw;
+ for ( qmdw=mdws.first(); qmdw != 0; qmdw=mdws.next() ) {
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- in reality it is only in MDWSlider
+ static_cast<MixDeviceWidget*>(qmdw)->setTicks( on );
+ }
+ }
+}
+
+void KMixToolBox::setValueStyle(QPtrList<QWidget> &mdws, int vs ) {
+ QWidget *qmdw;
+ for ( qmdw=mdws.first(); qmdw != 0; qmdw=mdws.next() ) {
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- in reality it is only in MDWSlider
+ static_cast<MixDeviceWidget*>(qmdw)->setValueStyle( (MixDeviceWidget::ValueStyle) vs );
+ }
+ }
+}
+
+void KMixToolBox::loadConfig(QPtrList<QWidget> &mdws, KConfig *config, const QString &grp, const QString &viewPrefix) {
+ int n = 0;
+ config->setGroup( grp );
+ int num = config->readNumEntry( viewPrefix + ".Devs", 0);
+
+ for ( QWidget *qmdw=mdws.first(); qmdw!=0 && n<num; qmdw=mdws.next() ) {
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- play safe here
+ MixDeviceWidget* mdw = static_cast<MixDeviceWidget*>(qmdw);
+ QString devgrp;
+
+ /*
+ * Compatibility config loader! We use the old config group only, if the
+ * new one does not exist.
+ * The new group system has been introduced, because it accounts much
+ * better for soundcard driver updates (if numbering changes, or semantics
+ * of an ID changes like ALSA changing from "Disable Amplifier" to "External Amplifier").
+ */
+ // !!! check
+ devgrp.sprintf( "%s.%s.Dev%s", viewPrefix.ascii(), grp.ascii(), mdw->mixDevice()->getPK().ascii() );
+
+ /**
+ Find an appropriate group name for capture GUI elements.
+ We try devgrp.append(".Capture")
+ If it doesn't exist, we fall back to devgrp.
+ This is the second compatibility measure, and was introduced for KDE3.5.2.
+ */
+ if ( mdw->mixDevice()->getVolume().isCapture() ) {
+ /* A "capture" GUI element must save its own state. Otherwise playback and capture
+ properties would be written twice under the same name. This would mean, when
+ restoring, both would get the same value. This is bad, because hidden sliders will re-appear
+ after restart of KMix, and a lot of other nasty GUI-related problems.
+ So we add ".Capture" to the group name.
+ See bug 121451 "KMix panel applet shows broken duplicates of bass, treble sliders"
+
+ The name should have been set in the backend class, but we REALLY cannot do this for KDE3.5.x. !!
+ This issue will be fixed in KDE4 by the great config cleanup.
+ */
+ QString devgrpTmp(devgrp);
+ devgrpTmp.append(".Capture");
+ if ( config->hasGroup(devgrpTmp) ) {
+ // Group for capture device exists => take over the name
+ devgrp = devgrpTmp;
+ }
+ else {
+ // do nothing => keep old name (devgrp).
+ // Saving wil autmatically create the group 'devgrp.append(".Capture")'
+ kdDebug(67100) << "KMixToolBox::loadConfig() capture fallback activcated. Fallback group is " << devgrp << endl;
+ }
+ } // isCapture()
+ if ( ! config->hasGroup(devgrp) ) {
+ // fall back to old-Style configuration (KMix2.1 and earlier)
+ devgrp.sprintf( "%s.%s.Dev%i", viewPrefix.ascii(), grp.ascii(), n );
+ // this configuration group will be deleted when config is saved
+ }
+ config->setGroup( devgrp );
+
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- in reality it is only in MDWSlider
+ // only sliders have the ability to split apart in mutliple channels
+ bool splitChannels = config->readBoolEntry("Split", false);
+ mdw->setStereoLinked( !splitChannels );
+ }
+ mdw->setDisabled( !config->readBoolEntry("Show", true) );
+
+ KGlobalAccel *keys=mdw->keys();
+ if ( keys )
+ {
+ QString devgrpkeys;
+ devgrpkeys.sprintf( "%s.%s.Dev%i.keys", viewPrefix.ascii(), grp.ascii(), n );
+ //kdDebug(67100) << "KMixToolBox::loadConfig() load Keys " << devgrpkeys << endl;
+
+ // please see KMixToolBox::saveConfig() for some rambling about saving/loading Keys
+ keys->setConfigGroup(devgrpkeys);
+ keys->readSettings(config);
+ keys->updateConnections();
+ }
+
+ n++;
+ } // if it is a MixDeviceWidget
+ } // for all widgets
+}
+
+
+void KMixToolBox::saveConfig(QPtrList<QWidget> &mdws, KConfig *config, const QString &grp, const QString &viewPrefix) {
+ config->setGroup( grp );
+ config->writeEntry( viewPrefix + ".Devs", mdws.count() );
+
+ int n=0;
+ for ( QWidget *qmdw=mdws.first(); qmdw!=0; qmdw=mdws.next() ) {
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- play safe here
+ MixDeviceWidget* mdw = static_cast<MixDeviceWidget*>(qmdw);
+
+ QString devgrp;
+ devgrp.sprintf( "%s.%s.Dev%i", viewPrefix.ascii(), grp.ascii(), n );
+ if ( ! config->hasGroup(devgrp) ) {
+ // old-Style configuration (KMix2.1 and earlier => remove now unused group
+ config->deleteGroup(devgrp);
+ }
+ devgrp.sprintf( "%s.%s.Dev%s", viewPrefix.ascii(), grp.ascii(), mdw->mixDevice()->getPK().ascii() );
+ //devgrp.sprintf( "%s.%s.Dev%i", viewPrefix.ascii(), grp.ascii(), n );
+
+ if ( mdw->mixDevice()->getVolume().isCapture() ) {
+ /* see loadConfig() for the rationale of having an own name for capture devices. */
+ devgrp.append(".Capture");
+ } // isCapture()
+
+ config->setGroup( devgrp );
+
+ if ( qmdw->inherits("MixDeviceWidget") ) { // -<- in reality it is only in MDWSlider
+ // only sliders have the ability to split apart in mutliple channels
+ config->writeEntry( "Split", ! mdw->isStereoLinked() );
+ }
+ config->writeEntry( "Show" , ! mdw->isDisabled() );
+
+ // Save key bindings
+ /*
+ Implementation hint: Conceptually keys SHOULD be bound to the actual hardware, and not
+ to one GUI representation. Both work, but it COULD confuse users, if we have multiple
+ GUI representations (e.g. "Dock Icon" and "Main Window").
+ If you think about this aspect more deeply, you will find out that this is the case already
+ today with "kmixapplet" and "kmix main application". It would really nice to rework this.
+ */
+ KGlobalAccel *keys=mdw->keys();
+ if (keys) {
+ QString devgrpkeys;
+ devgrpkeys.sprintf( "%s.%s.Dev%i.keys", viewPrefix.ascii(), grp.ascii(), n );
+ //kdDebug(67100) << "KMixToolBox::saveConfig() save Keys " << devgrpkeys << endl;
+ keys->setConfigGroup(devgrpkeys);
+ keys->writeSettings(config);
+ }
+ n++;
+ } // if it is a MixDeviceWidget
+ } // for all widgets
+}
+
diff --git a/kmix/kmixtoolbox.h b/kmix/kmixtoolbox.h
new file mode 100644
index 00000000..4cb5dd8f
--- /dev/null
+++ b/kmix/kmixtoolbox.h
@@ -0,0 +1,28 @@
+#ifndef KMIXTOOLBOX_H
+#define KMIXTOOLBOX_H
+
+#include "qptrlist.h"
+#include "qwidget.h"
+
+class Mixer;
+
+class KConfig;
+
+/**
+ * This toolbox contains various static methods that are shared throughout KMix.
+ * The reason, why it is not put in a common base class is, that the classes are
+ * very different and cannot be changed (e.g. KPanelApplet) without major headache.
+ */
+
+class KMixToolBox {
+ public:
+ static void setIcons (QPtrList<QWidget> &mdws, bool on );
+ static void setLabels (QPtrList<QWidget> &mdws, bool on );
+ static void setTicks (QPtrList<QWidget> &mdws, bool on );
+ static void setValueStyle (QPtrList<QWidget> &mdws, int vs );
+ static void loadConfig(QPtrList<QWidget> &mdws, KConfig *config, const QString &grp, const QString &viewPrefix );
+ static void saveConfig(QPtrList<QWidget> &mdws, KConfig *config, const QString &grp, const QString &viewPrefix );
+};
+
+
+#endif
diff --git a/kmix/kmixui.rc b/kmix/kmixui.rc
new file mode 100644
index 00000000..aada37d8
--- /dev/null
+++ b/kmix/kmixui.rc
@@ -0,0 +1,21 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kmix" version="3">
+
+<ActionProperties>
+ <Action name="hide_kmixwindow" icon="window"/>
+</ActionProperties>
+
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_new_tab"/>
+ <Action name="file_close_tab"/>
+ </Menu>
+ <Menu name="settings">
+ <Action name="settings_global" append="configure_merge"/>
+ </Menu>
+ <Menu name="help" append="about_merge"><text>&amp;Help</text>
+ <Action name="hwinfo"/>
+ </Menu>
+</MenuBar>
+
+</kpartgui>
diff --git a/kmix/ksmallslider.cpp b/kmix/ksmallslider.cpp
new file mode 100644
index 00000000..38e43639
--- /dev/null
+++ b/kmix/ksmallslider.cpp
@@ -0,0 +1,516 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <kdebug.h>
+
+#include <qwidget.h>
+#include <qpainter.h>
+#include <qcolor.h>
+#include <qbrush.h>
+#include <qstyle.h>
+
+#include "kglobalsettings.h"
+#include "ksmallslider.h"
+
+/*
+static const QColor mutedHighColor2 = "#FFFFFF";
+static const QColor mutedLowColor2 = "#808080";
+static const QColor backColor2 = "#000000";
+*/
+
+KSmallSlider::KSmallSlider( QWidget *parent, const char *name )
+ : QWidget( parent, name ), _orientation( Qt::Vertical )
+{
+ init();
+}
+
+KSmallSlider::KSmallSlider( Qt::Orientation orientation, QWidget *parent, const char *name )
+ : QWidget( parent, name ), _orientation( orientation )
+{
+ init();
+}
+
+KSmallSlider::KSmallSlider( int minValue, int maxValue, int pageStep,
+ int value, Qt::Orientation orientation,
+ QWidget *parent, const char *name )
+ : QWidget( parent, name ),
+ QRangeControl( minValue, maxValue, 1, pageStep, value ), _orientation( orientation)
+{
+ init();
+ // sliderVal = value;
+}
+
+void KSmallSlider::init()
+{
+ // !! the following 2 values must be -1, to make sure the values are not the real values.
+ // Otherwise some code below could determine that no change has happened and to send
+ // no signals or to do no initial paint.
+ // sliderPos = -1;
+ // state = Idle;
+ //track = TRUE;
+ //setMouseTracking(true);
+ grayed = false;
+ setFocusPolicy( TabFocus );
+
+ colHigh = QColor(0,255,0);
+ colLow = QColor(255,0,0);
+ colBack = QColor(0,0,0);
+
+ grayHigh = QColor(255,255,255);
+ grayLow = QColor(128,128,128);
+ grayBack = QColor(0,0,0);
+}
+/*
+void KSmallSlider::setTracking( bool enable )
+{
+ track = enable;
+}
+*/
+int KSmallSlider::positionFromValue( int v ) const
+{
+ return QRangeControl::positionFromValue( v, available() );
+}
+
+int KSmallSlider::valueFromPosition( int p ) const
+{
+ if ( _orientation == Qt::Vertical ) {
+ // Coordiante System starts at TopLeft, but the slider values increase from Bottom to Top
+ // Thus "revert" the position
+ int avail = available();
+ return QRangeControl::valueFromPosition( avail - p, avail );
+ }
+ else {
+ // Horizontal everything is fine. Slider values match with Coordinate System
+ return QRangeControl::valueFromPosition( p, available() );
+ }
+}
+
+void KSmallSlider::rangeChange()
+{
+ /*
+ int newPos = positionFromValue( QRangeControl::value() );
+ if ( newPos != sliderPos ) {
+ sliderPos = newPos;
+ }
+ */
+ update();
+}
+
+void KSmallSlider::valueChange()
+{
+ //kdDebug(67100) << "KSmallSlider::valueChange() value=" << value() << "\n";
+ update();
+ emit valueChanged(value());
+ /*
+ if ( sliderVal != QRangeControl::value() ) {
+ //int newPos = positionFromValue( QRangeControl::value() );
+ //sliderPos = newPos;
+ sliderVal = QRangeControl::value();
+ update();
+ emit valueChanged(value());
+ }
+ */
+}
+
+void KSmallSlider::resizeEvent( QResizeEvent * )
+{
+ update();
+ //QWidget::resizeEvent( ev );
+}
+
+// Returns the really available space for the slider. If there is no space, 0 is returned;
+int KSmallSlider::available() const
+{
+ int available = 0;
+ if ( _orientation == Qt::Vertical) {
+ available = height();
+ }
+ else {
+ available = width();
+ }
+ if ( available > 1 ) {
+ available -= 2;
+ }
+ else {
+ available = 0;
+ }
+ return available;
+}
+
+
+
+namespace
+{
+
+void gradient( QPainter &p, bool hor, const QRect &rect, const QColor &ca, const QColor &cb, int /*ncols*/)
+{
+ int rDiff, gDiff, bDiff;
+ int rca, gca, bca, rcb, gcb, bcb;
+
+ register int x, y;
+
+ if ((rect.width()<=0) || (rect.height()<=0)) return;
+
+ rDiff = (rcb = cb.red()) - (rca = ca.red());
+ gDiff = (gcb = cb.green()) - (gca = ca.green());
+ bDiff = (bcb = cb.blue()) - (bca = ca.blue());
+
+ register int rl = rca << 16;
+ register int gl = gca << 16;
+ register int bl = bca << 16;
+
+ int rcdelta = ((1<<16) / ((!hor) ? rect.height() : rect.width())) * rDiff;
+ int gcdelta = ((1<<16) / ((!hor) ? rect.height() : rect.width())) * gDiff;
+ int bcdelta = ((1<<16) / ((!hor) ? rect.height() : rect.width())) * bDiff;
+
+ // these for-loops could be merged, but the if's in the inner loop
+ // would make it slow
+ if (!hor)
+ {
+ for ( y = rect.top(); y <= rect.bottom(); y++ ) {
+ rl += rcdelta;
+ gl += gcdelta;
+ bl += bcdelta;
+
+ p.setPen(QColor(rl>>16, gl>>16, bl>>16));
+ p.drawLine(rect.left(), y, rect.right(), y);
+ }
+ } else
+ {
+ for( x = rect.left(); x <= rect.right(); x++) {
+ rl += rcdelta;
+ gl += gcdelta;
+ bl += bcdelta;
+
+ p.setPen(QColor(rl>>16, gl>>16, bl>>16));
+ p.drawLine(x, rect.top(), x, rect.bottom());
+ }
+ }
+}
+
+QColor interpolate( QColor low, QColor high, int percent ) {
+ if ( percent<=0 ) return low; else
+ if ( percent>=100 ) return high; else
+ return QColor(
+ low.red() + (high.red()-low.red()) * percent/100,
+ low.green() + (high.green()-low.green()) * percent/100,
+ low.blue() + (high.blue()-low.blue()) * percent/100 );
+}
+
+}
+
+void KSmallSlider::paintEvent( QPaintEvent * )
+{
+// kdDebug(67100) << "KSmallSlider::paintEvent: width() = " << width() << ", height() = " << height() << endl;
+ QPainter p( this );
+
+ int sliderPos = positionFromValue( QRangeControl::value() );
+
+ // ------------------------ draw 3d border ---------------------------------------------
+ style().drawPrimitive ( QStyle::PE_Panel, &p, QRect( 0, 0, width(), height() ), colorGroup(), TRUE );
+
+
+ // ------------------------ draw lower/left part ----------------------------------------
+ if ( width()>2 && height()>2 )
+ {
+ if ( _orientation == Qt::Horizontal ) {
+ QRect outer = QRect( 1, 1, sliderPos, height() - 2 );
+// kdDebug(67100) << "KSmallSlider::paintEvent: outer = " << outer << endl;
+
+ if ( grayed )
+ gradient( p, true, outer, grayLow,
+ interpolate( grayLow, grayHigh, 100*sliderPos/(width()-2) ),
+ 32 );
+ else
+ gradient( p, true, outer, colLow,
+ interpolate( colLow, colHigh, 100*sliderPos/(width()-2) ),
+ 32 );
+ }
+ else {
+ QRect outer = QRect( 1, height()-sliderPos-1, width() - 2, sliderPos-1 );
+/*
+ kdDebug(67100) << "KSmallSlider::paintEvent: sliderPos=" << sliderPos
+ << "height()=" << height()
+ << "width()=" << width()
+ << "outer = " << outer << endl;
+*/
+ if ( grayed )
+ gradient( p, false, outer,
+ interpolate( grayLow, grayHigh, 100*sliderPos/(height()-2) ),
+ grayLow, 32 );
+ else
+ gradient( p, false, outer,
+ interpolate( colLow, colHigh, 100*sliderPos/(height()-2) ),
+ colLow, 32 );
+ }
+
+ // -------- draw upper/right part --------------------------------------------------
+ QRect inner;
+ if ( _orientation == Qt::Vertical ) {
+ inner = QRect( 1, 1, width() - 2, height() - 2 -sliderPos );
+ }
+ else {
+ inner = QRect( sliderPos + 1, 1, width() - 2 - sliderPos, height() - 2 );
+ }
+
+ if ( grayed ) {
+ p.setBrush( grayBack );
+ p.setPen( grayBack );
+ } else {
+ p.setBrush( colBack );
+ p.setPen( colBack );
+ }
+ p.drawRect( inner );
+ }
+}
+
+void KSmallSlider::mousePressEvent( QMouseEvent *e )
+{
+ //resetState();
+
+ if ( e->button() == RightButton ) {
+ return;
+ }
+
+ // state = Dragging;
+ //emit sliderPressed();
+
+ int pos = goodPart( e->pos() );
+ moveSlider( pos );
+}
+
+void KSmallSlider::mouseMoveEvent( QMouseEvent *e )
+{
+ /*
+ if ( state != Dragging )
+ return;
+ */
+ int pos = goodPart( e->pos() );
+ moveSlider( pos );
+}
+
+void KSmallSlider::wheelEvent( QWheelEvent * e)
+{
+// kdDebug(67100) << "KSmallslider::wheelEvent()" << endl;
+ /* Unfortunately KSmallSlider is no MixDeviceWidget, so we don't have access to
+ * the MixDevice.
+ */
+ int inc = ( maxValue() - minValue() ) / 20;
+ if ( inc < 1)
+ inc = 1;
+
+ //kdDebug(67100) << "KSmallslider::wheelEvent() inc=" << inc << "delta=" << e->delta() << endl;
+ if ( e->delta() > 0 ) {
+ QRangeControl::setValue( QRangeControl::value() + inc );
+ }
+ else {
+ QRangeControl::setValue( QRangeControl::value() - inc );
+ }
+ e->accept(); // Accept the event
+
+ // Hint: Qt autmatically triggers a valueChange() when we do setValue()
+}
+
+void KSmallSlider::mouseReleaseEvent( QMouseEvent * )
+{
+ //resetState();
+}
+
+/*
+ * Moves slider to a dedicated position. If the value has changed
+ */
+void KSmallSlider::moveSlider( int pos )
+{
+ int a = available();
+ int newPos = QMIN( a, QMAX( 0, pos ) ); // keep it inside the available bounds of the slider
+ int newVal = valueFromPosition( newPos );
+
+ if ( newVal != QRangeControl::value() ) {
+ //QRangeControl::directSetValue( sliderVal );
+ QRangeControl::setValue( newVal );
+ emit valueChanged( value() ); // Only for external use
+ }
+ update();
+}
+
+/*
+void KSmallSlider::resetState()
+{
+ switch ( state ) {
+ case Dragging: {
+ QRangeControl::setValue( valueFromPosition( sliderPos ) );
+ emit sliderReleased();
+ break;
+ }
+ case Idle:
+ break;
+
+ default:
+ qWarning("KSmallSlider: (%s) in wrong state", name( "unnamed" ) );
+ }
+ state = Idle;
+}
+*/
+
+void KSmallSlider::setValue( int value )
+{
+ QRangeControl::setValue( value );
+}
+
+void KSmallSlider::addStep()
+{
+ addPage();
+}
+
+void KSmallSlider::subtractStep()
+{
+ subtractPage();
+}
+
+int KSmallSlider::goodPart( const QPoint &p ) const
+{
+ if ( _orientation == Qt::Vertical ) {
+ return p.y() - 1;
+ }
+ else {
+ return p.x() - 1;
+ }
+}
+
+/***************** SIZE STUFF START ***************/
+QSize KSmallSlider::sizeHint() const
+{
+ //constPolish();
+ const int length = 25;
+ const int thick = 10;
+
+ if ( _orientation == Qt::Vertical )
+ return QSize( thick, length );
+ else
+ return QSize( length, thick );
+}
+
+
+QSize KSmallSlider::minimumSizeHint() const
+{
+ QSize s(10,10);
+ return s;
+}
+
+
+QSizePolicy KSmallSlider::sizePolicy() const
+{
+
+ if ( _orientation == Qt::Vertical ) {
+ //kdDebug(67100) << "KSmallSlider::sizePolicy() vertical value=(Fixed,MinimumExpanding)\n";
+ return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
+ }
+ else {
+ //kdDebug(67100) << "KSmallSlider::sizePolicy() horizontal value=(MinimumExpanding,Fixed)\n";
+ return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+ }
+}
+/***************** SIZE STUFF END ***************/
+
+
+int KSmallSlider::minValue() const
+{
+ return QRangeControl::minValue();
+}
+
+int KSmallSlider::maxValue() const
+{
+ return QRangeControl::maxValue();
+}
+
+int KSmallSlider::lineStep() const
+{
+ return QRangeControl::lineStep();
+}
+
+int KSmallSlider::pageStep() const
+{
+ return QRangeControl::pageStep();
+}
+
+void KSmallSlider::setLineStep( int i )
+{
+ setSteps( i, pageStep() );
+}
+
+void KSmallSlider::setPageStep( int i )
+{
+ setSteps( lineStep(), i );
+}
+
+// Only for external acces. You MUST use QRangeControl::value() internally.
+int KSmallSlider::value() const
+{
+ return QRangeControl::value();
+}
+
+/*
+void KSmallSlider::paletteChange ( const QPalette &) {
+ if ( grayed ) {
+ setColors(mutedLowColor2, mutedHighColor2, backColor2 );
+ }
+ else {
+ // ignore the QPalette and use the values from KGlobalSettings instead
+ //const QColorGroup& qcg = palette().active();
+ setColors(KGlobalSettings::baseColor(), KGlobalSettings::highlightColor(), backColor2 );
+ }
+}
+*/
+
+void KSmallSlider::setGray( bool value )
+{
+ if ( grayed!=value )
+ {
+ grayed = value;
+ update();
+ //repaint();
+ }
+}
+
+bool KSmallSlider::gray() const
+{
+ return grayed;
+}
+
+void KSmallSlider::setColors( QColor high, QColor low, QColor back )
+{
+ colHigh = high;
+ colLow = low;
+ colBack = back;
+ update();
+ //repaint();
+}
+
+void KSmallSlider::setGrayColors( QColor high, QColor low, QColor back )
+{
+ grayHigh = high;
+ grayLow = low;
+ grayBack = back;
+ update();
+ //repaint();
+}
+
+#include "ksmallslider.moc"
diff --git a/kmix/ksmallslider.h b/kmix/ksmallslider.h
new file mode 100644
index 00000000..398d7728
--- /dev/null
+++ b/kmix/ksmallslider.h
@@ -0,0 +1,119 @@
+//-*-C++-*-
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KSMALLSLIDER_H
+#define KSMALLSLIDER_H
+
+#include <kpanelapplet.h>
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qrangecontrol.h>
+
+class KSmallSlider : public QWidget, public QRangeControl
+{
+ Q_OBJECT
+
+ public:
+ KSmallSlider( QWidget *parent, const char *name=0 );
+ KSmallSlider( Qt::Orientation, QWidget *parent, const char *name=0 );
+ KSmallSlider( int minValue, int maxValue, int pageStep, int value,
+ Qt::Orientation, QWidget *parent, const char *name=0 );
+
+ //virtual void setTracking( bool enable );
+ //bool tracking() const;
+ QSize sizeHint() const;
+ QSizePolicy sizePolicy() const;
+ QSize minimumSizeHint() const;
+
+ int minValue() const;
+ int maxValue() const;
+ void setMinValue( int ); // Don't use these unless you make versions
+ void setMaxValue( int ); // that work. -esigra
+ int lineStep() const;
+ int pageStep() const;
+ void setLineStep( int );
+ void setPageStep( int );
+ int value() const;
+
+ //void paletteChange ( const QPalette & oldPalette );
+ bool gray() const;
+
+public slots:
+ virtual void setValue( int );
+ void addStep();
+ void subtractStep();
+
+ void setGray( bool value );
+ void setColors( QColor high, QColor low, QColor back );
+ void setGrayColors( QColor high, QColor low, QColor back );
+
+ signals:
+ void valueChanged( int value );
+ void sliderPressed();
+ void sliderMoved( int value );
+ void sliderReleased();
+
+ protected:
+ void resizeEvent( QResizeEvent * );
+ void paintEvent( QPaintEvent * );
+
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void wheelEvent( QWheelEvent * );
+
+ void valueChange();
+ void rangeChange();
+
+ private:
+ //enum State { Idle, Dragging };
+
+ void init();
+ int positionFromValue( int ) const;
+ int valueFromPosition( int ) const;
+ void moveSlider( int );
+ //void resetState();
+
+ // int slideLength() const;
+ int available() const;
+ int goodPart( const QPoint& ) const;
+ //void initTicks();
+
+ //QCOORD sliderPos;
+ //int sliderVal;
+ //State state;
+ //bool track;
+ bool grayed;
+ Qt::Orientation _orientation;
+ QColor colHigh, colLow, colBack;
+ QColor grayHigh, grayLow, grayBack;
+
+};
+
+/*
+inline bool KSmallSlider::tracking() const
+{
+ return track;
+}
+*/
+#endif
diff --git a/kmix/main.cpp b/kmix/main.cpp
new file mode 100644
index 00000000..3842ecaa
--- /dev/null
+++ b/kmix/main.cpp
@@ -0,0 +1,69 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <schimmi@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+#include "KMixApp.h"
+#include "version.h"
+
+static const char description[] =
+I18N_NOOP("KMix - KDE's full featured mini mixer");
+
+static KCmdLineOptions options[] =
+{
+ KCmdLineLastOption
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+};
+
+extern "C" KDE_EXPORT int kdemain(int argc, char *argv[])
+{
+ KAboutData aboutData( "kmix", I18N_NOOP("KMix"),
+ APP_VERSION, description, KAboutData::License_GPL,
+ I18N_NOOP("(c) 1996-2000 Christian Esken\n(c) 2000-2003 Christian Esken, Stefan Schimanski\n(c) 2002-2005 Christian Esken, Helio Chissini de Castro"));
+
+ aboutData.addAuthor("Christian Esken", "Current maintainer", "esken@kde.org");
+ aboutData.addAuthor("Helio Chissini de Castro", I18N_NOOP("Current redesign and co-maintainer, Alsa 0.9x port"), "helio@kde.org" );
+ aboutData.addAuthor("Stefan Schimanski", 0, "schimmi@kde.org");
+ aboutData.addAuthor("Sven Leiber", 0, "s.leiber@web.de");
+ aboutData.addAuthor("Brian Hanson", I18N_NOOP("Solaris port"), "bhanson@hotmail.com");
+ aboutData.addAuthor("Paul Kendall", I18N_NOOP("SGI Port"), "paul@orion.co.nz");
+ aboutData.addAuthor("Sebestyen Zoltan", I18N_NOOP("*BSD fixes"), "szoli@digo.inf.elte.hu");
+ aboutData.addAuthor("Lennart Augustsson", I18N_NOOP("*BSD fixes"), "augustss@cs.chalmers.se");
+ aboutData.addAuthor("Nick Lopez", I18N_NOOP("ALSA port"), "kimo_sabe@usa.net");
+ aboutData.addAuthor("Helge Deller", I18N_NOOP("HP/UX port"), "deller@gmx.de");
+ aboutData.addAuthor("Jean Labrousse", I18N_NOOP("NAS port"), "jean.labrousse@alcatel.com" );
+ aboutData.addCredit("Nadeem Hasan", I18N_NOOP("Mute and volume preview, other fixes"), "nhasan@kde.org");
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ if (!KMixApp::start())
+ return 0;
+
+ KMixApp *app = new KMixApp();
+ int ret = app->exec();
+ delete app;
+ return ret;
+}
diff --git a/kmix/mdwenum.cpp b/kmix/mdwenum.cpp
new file mode 100644
index 00000000..91220902
--- /dev/null
+++ b/kmix/mdwenum.cpp
@@ -0,0 +1,206 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <qcursor.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qobject.h>
+#include <qtooltip.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kcombobox.h>
+#include <kaction.h>
+#include <kpopupmenu.h>
+
+#include <kglobalaccel.h>
+#include <kkeydialog.h>
+
+#include <kdebug.h>
+
+#include "mdwenum.h"
+#include "mixer.h"
+#include "viewbase.h"
+
+/**
+ * Class that represents an Enum element (a select one-from-many selector)
+ * The orientation (horizontal, vertical) is ignored
+ */
+MDWEnum::MDWEnum(Mixer *mixer, MixDevice* md,
+ Qt::Orientation orientation,
+ QWidget* parent, ViewBase* mw, const char* name) :
+ MixDeviceWidget(mixer,md,false,orientation,parent,mw,name),
+ _label(0), _enumCombo(0), _layout(0)
+{
+ // create actions (on _mdwActions, see MixDeviceWidget)
+
+ // KStdAction::showMenubar() is in MixDeviceWidget now
+ new KToggleAction( i18n("&Hide"), 0, this, SLOT(setDisabled()), _mdwActions, "hide" );
+ new KAction( i18n("C&onfigure Shortcuts..."), 0, this, SLOT(defineKeys()), _mdwActions, "keys" );
+
+ // create widgets
+ createWidgets();
+
+ /* !!! remove this for production version */
+ m_keys->insert( "Next Value", i18n( "Next Value" ), QString::null,
+ KShortcut(), KShortcut(), this, SLOT( nextEnumId() ) );
+
+ installEventFilter( this ); // filter for popup
+}
+
+MDWEnum::~MDWEnum()
+{
+}
+
+
+void MDWEnum::createWidgets()
+{
+ if ( _orientation == Qt::Vertical ) {
+ _layout = new QVBoxLayout( this );
+ _layout->setAlignment(Qt::AlignHCenter);
+ }
+ else {
+ _layout = new QHBoxLayout( this );
+ _layout->setAlignment(Qt::AlignVCenter);
+ }
+ QToolTip::add( this, m_mixdevice->name() );
+
+ //this->setStretchFactor( _layout, 0 );
+ //QSizePolicy qsp( QSizePolicy::Ignored, QSizePolicy::Maximum);
+ //_layout->setSizePolicy(qsp);
+ //_layout->setSpacing(KDialog::spacingHint());
+ _label = new QLabel( m_mixdevice->name(), this);
+ _layout->addWidget(_label);
+ _label->setFixedHeight(_label->sizeHint().height());
+ _enumCombo = new KComboBox( FALSE, this, "mixerCombo" );
+ // ------------ fill ComboBox start ------------
+ int maxEnumId= m_mixdevice->enumValues().count();
+ for (int i=0; i<maxEnumId; i++ ) {
+ _enumCombo->insertItem( *(m_mixdevice->enumValues().at(i)),i);
+ }
+ // ------------ fill ComboBox end --------------
+ _layout->addWidget(_enumCombo);
+ _enumCombo->setFixedHeight(_enumCombo->sizeHint().height());
+ connect( _enumCombo, SIGNAL( activated( int ) ), this, SLOT( setEnumId( int ) ) );
+ QToolTip::add( _enumCombo, m_mixdevice->name() );
+
+ //_layout->addSpacing( 4 );
+}
+
+void MDWEnum::update()
+{
+ if ( m_mixdevice->isEnum() ) {
+ //kdDebug(67100) << "MDWEnum::update() enumID=" << m_mixdevice->enumId() << endl;
+ _enumCombo->setCurrentItem( m_mixdevice->enumId() );
+ }
+ else {
+ // !!! print warning message
+ }
+}
+
+void MDWEnum::showContextMenu()
+{
+ if( m_mixerwidget == NULL )
+ return;
+
+ KPopupMenu *menu = m_mixerwidget->getPopup();
+
+ QPoint pos = QCursor::pos();
+ menu->popup( pos );
+}
+
+QSize MDWEnum::sizeHint() const {
+ if ( _layout != 0 ) {
+ return _layout->sizeHint();
+ }
+ else {
+ // layout not (yet) created
+ return QWidget::sizeHint();
+ }
+}
+
+
+/**
+ This slot is called, when a user has clicked the mute button. Also it is called by any other
+ associated KAction like the context menu.
+*/
+void MDWEnum::nextEnumId() {
+ if( m_mixdevice->isEnum() ) {
+ int curEnum = enumId();
+ if ( (unsigned int)curEnum < m_mixdevice->enumValues().count() ) {
+ // next enum value
+ setEnumId(curEnum+1);
+ }
+ else {
+ // wrap around
+ setEnumId(0);
+ }
+ } // isEnum
+}
+
+void MDWEnum::setEnumId(int value)
+{
+ if ( m_mixdevice->isEnum() ) {
+ m_mixdevice->setEnumId( value );
+ m_mixer->commitVolumeChange( m_mixdevice );
+ }
+}
+
+int MDWEnum::enumId()
+{
+ if ( m_mixdevice->isEnum() ) {
+ return m_mixdevice->enumId();
+ }
+ else {
+ return 0;
+ }
+}
+
+void MDWEnum::setDisabled()
+{
+ setDisabled( true );
+}
+
+void MDWEnum::setDisabled( bool value ) {
+ if ( m_disabled!=value)
+ {
+ value ? hide() : show();
+ m_disabled = value;
+ }
+}
+
+/**
+ * An event filter for the various QWidgets. We watch for Mouse press Events, so
+ * that we can popup the context menu.
+ */
+bool MDWEnum::eventFilter( QObject* obj, QEvent* e )
+{
+ if (e->type() == QEvent::MouseButtonPress) {
+ QMouseEvent *qme = static_cast<QMouseEvent*>(e);
+ if (qme->button() == Qt::RightButton) {
+ showContextMenu();
+ return true;
+ }
+ }
+ return QWidget::eventFilter(obj,e);
+}
+
+#include "mdwenum.moc"
diff --git a/kmix/mdwenum.h b/kmix/mdwenum.h
new file mode 100644
index 00000000..09b2d0a4
--- /dev/null
+++ b/kmix/mdwenum.h
@@ -0,0 +1,77 @@
+//-*-C++-*-
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2004 Chrisitan Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MDWENUM_H
+#define MDWENUM_H
+
+#include <qwidget.h>
+#include "volume.h"
+
+class QBoxLayout;
+
+class KAction;
+class KActionCollection;
+class KComboBox;
+class KGlobalAccel;
+
+class MixDevice;
+class Mixer;
+class ViewBase;
+
+#include "mixdevicewidget.h"
+
+class MDWEnum : public MixDeviceWidget
+{
+ Q_OBJECT
+
+public:
+ MDWEnum( Mixer *mixer, MixDevice* md,
+ Qt::Orientation orientation,
+ QWidget* parent = 0, ViewBase* mw = 0, const char* name = 0);
+ ~MDWEnum();
+
+ void addActionToPopup( KAction *action );
+ QSize sizeHint() const;
+ bool eventFilter( QObject* obj, QEvent* e );
+
+public slots:
+ // GUI hide and show
+ void setDisabled();
+ void setDisabled(bool);
+
+ // Enum handling: next and selecting
+ void nextEnumId();
+ int enumId();
+ void setEnumId(int value);
+
+ void update();
+ virtual void showContextMenu();
+
+private:
+ void createWidgets();
+
+ QLabel *_label;
+ KComboBox *_enumCombo;
+ QBoxLayout *_layout;
+};
+
+#endif
diff --git a/kmix/mdwslider.cpp b/kmix/mdwslider.cpp
new file mode 100644
index 00000000..6ee8166c
--- /dev/null
+++ b/kmix/mdwslider.cpp
@@ -0,0 +1,974 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <klocale.h>
+#include <kled.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kaction.h>
+#include <kpopupmenu.h>
+#include <kglobalaccel.h>
+#include <kkeydialog.h>
+#include <kdebug.h>
+
+#include <qobject.h>
+#include <qcursor.h>
+#include <qslider.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qtooltip.h>
+#include <qwmatrix.h>
+
+#include "mdwslider.h"
+#include "mixer.h"
+#include "viewbase.h"
+#include "kledbutton.h"
+#include "ksmallslider.h"
+#include "verticaltext.h"
+
+/**
+ * MixDeviceWidget that represents a single mix device, inlcuding PopUp, muteLED, ...
+ *
+ * Used in KMix main window and DockWidget and PanelApplet.
+ * It can be configured to include or exclude the recordLED and the muteLED.
+ * The direction (horizontal, vertical) can be configured and whether it should
+ * be "small" (uses KSmallSlider instead of QSlider then).
+ *
+ * Due to the many options, this is the most complicated MixDeviceWidget subclass.
+ */
+MDWSlider::MDWSlider(Mixer *mixer, MixDevice* md,
+ bool showMuteLED, bool showRecordLED,
+ bool small, Qt::Orientation orientation,
+ QWidget* parent, ViewBase* mw, const char* name) :
+ MixDeviceWidget(mixer,md,small,orientation,parent,mw,name),
+ m_linked(true), m_valueStyle( NNONE), m_iconLabel( 0 ), m_muteLED( 0 ), m_recordLED( 0 ), m_label( 0 ), _layout(0)
+{
+ // create actions (on _mdwActions, see MixDeviceWidget)
+
+ new KToggleAction( i18n("&Split Channels"), 0, this, SLOT(toggleStereoLinked()),
+ _mdwActions, "stereo" );
+ new KToggleAction( i18n("&Hide"), 0, this, SLOT(setDisabled()), _mdwActions, "hide" );
+
+ KToggleAction *a = new KToggleAction(i18n("&Muted"), 0, 0, 0, _mdwActions, "mute" );
+ connect( a, SIGNAL(toggled(bool)), SLOT(toggleMuted()) );
+
+ if( m_mixdevice->isRecordable() ) {
+ a = new KToggleAction( i18n("Set &Record Source"), 0, 0, 0, _mdwActions, "recsrc" );
+ connect( a, SIGNAL(toggled(bool)), SLOT( toggleRecsrc()) );
+ }
+
+ new KAction( i18n("C&onfigure Global Shortcuts..."), 0, this, SLOT(defineKeys()), _mdwActions, "keys" );
+
+ // create widgets
+ createWidgets( showMuteLED, showRecordLED );
+
+ m_keys->insert( "Increase volume", i18n( "Increase Volume of '%1'" ).arg(m_mixdevice->name().utf8().data()), QString::null,
+ KShortcut(), KShortcut(), this, SLOT( increaseVolume() ) );
+ m_keys->insert( "Decrease volume", i18n( "Decrease Volume of '%1'" ).arg(m_mixdevice->name().utf8().data()), QString::null,
+ KShortcut(), KShortcut(), this, SLOT( decreaseVolume() ) );
+ m_keys->insert( "Toggle mute", i18n( "Toggle Mute of '%1'" ).arg(m_mixdevice->name().utf8().data()), QString::null,
+ KShortcut(), KShortcut(), this, SLOT( toggleMuted() ) );
+
+ installEventFilter( this ); // filter for popup
+
+ update();
+}
+
+
+QSizePolicy MDWSlider::sizePolicy() const
+{
+ if ( _orientation == Qt::Vertical ) {
+ return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
+ }
+ else {
+ return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+ }
+}
+
+
+/**
+ * Creates up to 4 widgets - Icon, Mute-Button, Slider and Record-Button.
+ *
+ * Those widgets are placed into
+
+*/
+void MDWSlider::createWidgets( bool showMuteLED, bool showRecordLED )
+{
+ if ( _orientation == Qt::Vertical ) {
+ _layout = new QVBoxLayout( this );
+ _layout->setAlignment(Qt::AlignCenter);
+ }
+ else {
+ _layout = new QHBoxLayout( this );
+ _layout->setAlignment(Qt::AlignCenter);
+ }
+
+ // -- MAIN SLIDERS LAYOUT ---
+ QBoxLayout *slidersLayout;
+ if ( _orientation == Qt::Vertical ) {
+ slidersLayout = new QHBoxLayout( _layout );
+ slidersLayout->setAlignment(Qt::AlignVCenter);
+ }
+ else {
+ slidersLayout = new QVBoxLayout( _layout );
+ slidersLayout->setAlignment(Qt::AlignHCenter);
+ }
+
+ /* cesken: This is inconsistent. Why should vertical and horizontal layout differ?
+ * Also it eats too much space - especially when you don't show sliders at all.
+ * Even more on the vertical panel applet (see Bug #97667)
+ if ( _orientation == Qt::Horizontal )
+ slidersLayout->addSpacing( 10 );
+ */
+
+
+ // -- LABEL LAYOUT TO POSITION
+ QBoxLayout *labelLayout;
+ if ( _orientation == Qt::Vertical ) {
+ labelLayout = new QVBoxLayout( slidersLayout );
+ labelLayout->setAlignment(Qt::AlignHCenter);
+ }
+ else {
+ labelLayout = new QHBoxLayout( slidersLayout );
+ labelLayout->setAlignment(Qt::AlignVCenter);
+ }
+ if ( _orientation == Qt::Vertical ) {
+ m_label = new VerticalText( this, m_mixdevice->name().utf8().data() );
+ QToolTip::add( m_label, m_mixdevice->name() );
+
+ }
+ else {
+ m_label = new QLabel(this);
+ static_cast<QLabel*>(m_label) ->setText(m_mixdevice->name());
+ QToolTip::add( m_label, m_mixdevice->name() );
+ }
+
+ m_label->hide();
+
+/* This addSpacing() looks VERY bizarre => removing it (cesken, 21.2.2006).
+ Also horizontal and vertical spacing differs. This doesn't look sensible.
+ if ( _orientation == Qt::Horizontal )
+ labelLayout->addSpacing( 36 );
+*/
+ labelLayout->addWidget( m_label );
+ m_label->installEventFilter( this );
+
+/* This addSpacing() looks VERY bizarre => removing it (cesken, 21.2.2006)
+ Also horizontal and vertical spacing differs. This doesn't look sensible.
+ if ( _orientation == Qt::Vertical ) {
+ labelLayout->addSpacing( 18 );
+ }
+*/
+
+ // -- SLIDERS, LEDS AND ICON
+ QBoxLayout *sliLayout;
+ if ( _orientation == Qt::Vertical ) {
+ sliLayout = new QVBoxLayout( slidersLayout );
+ sliLayout->setAlignment(Qt::AlignHCenter);
+ }
+ else {
+ sliLayout = new QHBoxLayout( slidersLayout );
+ sliLayout->setAlignment(Qt::AlignVCenter);
+ }
+
+ // --- ICON ----------------------------
+ QBoxLayout *iconLayout;
+ if ( _orientation == Qt::Vertical ) {
+ iconLayout = new QHBoxLayout( sliLayout );
+ iconLayout->setAlignment(Qt::AlignVCenter);
+ }
+ else {
+ iconLayout = new QVBoxLayout( sliLayout );
+ iconLayout->setAlignment(Qt::AlignHCenter);
+ }
+
+ m_iconLabel = 0L;
+ setIcon( m_mixdevice->type() );
+ iconLayout->addStretch();
+ iconLayout->addWidget( m_iconLabel );
+ iconLayout->addStretch();
+ m_iconLabel->installEventFilter( this );
+
+ sliLayout->addSpacing( 5 );
+
+
+ // --- MUTE LED
+ if ( showMuteLED ) {
+ QBoxLayout *ledlayout;
+ if ( _orientation == Qt::Vertical ) {
+ ledlayout = new QHBoxLayout( sliLayout );
+ ledlayout->setAlignment(Qt::AlignVCenter);
+ }
+ else {
+ ledlayout = new QVBoxLayout( sliLayout );
+ ledlayout->setAlignment(Qt::AlignHCenter);
+ }
+
+ if( m_mixdevice->hasMute() )
+ {
+ ledlayout->addStretch();
+ // create mute LED
+ m_muteLED = new KLedButton( Qt::green, KLed::On, KLed::Sunken,
+ KLed::Circular, this, "MuteLED" );
+ m_muteLED->setFixedSize( QSize(16, 16) );
+ m_muteLED->resize( QSize(16, 16) );
+ ledlayout->addWidget( m_muteLED );
+ QToolTip::add( m_muteLED, i18n( "Mute" ) );
+ connect( m_muteLED, SIGNAL(stateChanged(bool)), this, SLOT(toggleMuted()) );
+ m_muteLED->installEventFilter( this );
+ ledlayout->addStretch();
+ } // has Mute LED
+ else {
+ // we don't have a MUTE LED. We create a dummy widget
+ // !! possibly not neccesary any more (we are layouted)
+ QWidget *qw = new QWidget(this, "Spacer");
+ qw->setFixedSize( QSize(16, 16) );
+ ledlayout->addWidget(qw);
+ qw->installEventFilter( this );
+ } // has no Mute LED
+
+ sliLayout->addSpacing( 3 );
+ } // showMuteLED
+
+ // --- SLIDERS ---------------------------
+ QBoxLayout *volLayout;
+ if ( _orientation == Qt::Vertical ) {
+ volLayout = new QHBoxLayout( sliLayout );
+ volLayout->setAlignment(Qt::AlignVCenter);
+ }
+ else {
+ volLayout = new QVBoxLayout( sliLayout );
+ volLayout->setAlignment(Qt::AlignHCenter);
+ }
+
+ // Sliders and volume number indication
+ QBoxLayout *slinumLayout;
+ for( int i = 0; i < m_mixdevice->getVolume().count(); i++ )
+ {
+ Volume::ChannelID chid = Volume::ChannelID(i);
+ // @todo !! Normally the mixdevicewidget SHOULD know, which slider represents which channel.
+ // We should look up the mapping here, but for now, we simply assume "chid == i".
+
+ int maxvol = m_mixdevice->getVolume().maxVolume();
+ int minvol = m_mixdevice->getVolume().minVolume();
+
+ if ( _orientation == Qt::Vertical ) {
+ slinumLayout = new QVBoxLayout( volLayout );
+ slinumLayout->setAlignment(Qt::AlignHCenter);
+ }
+ else {
+ slinumLayout = new QHBoxLayout( volLayout );
+ slinumLayout->setAlignment(Qt::AlignVCenter);
+ }
+
+ // create labels to hold volume values (taken from qamix/kamix)
+ QLabel *number = new QLabel( "100", this );
+ slinumLayout->addWidget( number );
+ number->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ number->setLineWidth( 2 );
+ number->setMinimumWidth( number->sizeHint().width() );
+ number->setPaletteBackgroundColor( QColor(190, 250, 190) );
+ // don't show the value by default
+ number->hide();
+ updateValue( number, chid );
+ _numbers.append( number );
+
+ QWidget* slider;
+ if ( m_small ) {
+ slider = new KSmallSlider( minvol, maxvol, maxvol/10,
+ m_mixdevice->getVolume( chid ), _orientation,
+ this, m_mixdevice->name().ascii() );
+ }
+ else {
+ slider = new QSlider( 0, maxvol, maxvol/10,
+ maxvol - m_mixdevice->getVolume( chid ), _orientation,
+ this, m_mixdevice->name().ascii() );
+ slider->setMinimumSize( slider->sizeHint() );
+ }
+
+ slider->setBackgroundOrigin(AncestorOrigin);
+ slider->installEventFilter( this );
+ QToolTip::add( slider, m_mixdevice->name() );
+
+ if( i>0 && isStereoLinked() ) {
+ // show only one (the first) slider, when the user wants it so
+ slider->hide();
+ number->hide();
+ }
+ slinumLayout->addWidget( slider ); // add to layout
+ m_sliders.append ( slider ); // add to list
+ _slidersChids.append(chid); // Remember slider-chid association
+ connect( slider, SIGNAL(valueChanged(int)), SLOT(volumeChange(int)) );
+ } // for all channels of this device
+
+
+ // --- RECORD SOURCE LED --------------------------
+ if ( showRecordLED )
+ {
+ sliLayout->addSpacing( 5 );
+
+ // --- LED LAYOUT TO CENTER ---
+ QBoxLayout *reclayout;
+ if ( _orientation == Qt::Vertical ) {
+ reclayout = new QHBoxLayout( sliLayout );
+ reclayout->setAlignment(Qt::AlignVCenter);
+ }
+ else {
+ reclayout = new QVBoxLayout( sliLayout );
+ reclayout->setAlignment(Qt::AlignHCenter);
+ }
+
+ if( m_mixdevice->isRecordable() ) {
+ reclayout->addStretch();
+ m_recordLED = new KLedButton( Qt::red,
+ m_mixdevice->isRecSource()?KLed::On:KLed::Off,
+ KLed::Sunken, KLed::Circular, this, "RecordLED" );
+ m_recordLED->setFixedSize( QSize(16, 16) );
+ reclayout->addWidget( m_recordLED );
+ connect(m_recordLED, SIGNAL(stateChanged(bool)), this, SLOT(setRecsrc(bool)));
+ m_recordLED->installEventFilter( this );
+ QToolTip::add( m_recordLED, i18n( "Record" ) );
+ reclayout->addStretch();
+ }
+ else
+ {
+ // we don't have a RECORD LED. We create a dummy widget
+ // !! possibly not neccesary any more (we are layouted)
+ QWidget *qw = new QWidget(this, "Spacer");
+ qw->setFixedSize( QSize(16, 16) );
+ reclayout->addWidget(qw);
+ qw->installEventFilter( this );
+ } // has no Record LED
+ } // showRecordLED
+
+ layout()->activate();
+}
+
+
+QPixmap
+MDWSlider::icon( int icontype )
+{
+ QPixmap miniDevPM;
+ switch (icontype) {
+ case MixDevice::AUDIO:
+ miniDevPM = UserIcon("mix_audio"); break;
+ case MixDevice::BASS:
+ case MixDevice::SURROUND_LFE: // "LFE" SHOULD have an own icon
+ miniDevPM = UserIcon("mix_bass"); break;
+ case MixDevice::CD:
+ miniDevPM = UserIcon("mix_cd"); break;
+ case MixDevice::EXTERNAL:
+ miniDevPM = UserIcon("mix_ext"); break;
+ case MixDevice::MICROPHONE:
+ miniDevPM = UserIcon("mix_microphone");break;
+ case MixDevice::MIDI:
+ miniDevPM = UserIcon("mix_midi"); break;
+ case MixDevice::RECMONITOR:
+ miniDevPM = UserIcon("mix_recmon"); break;
+ case MixDevice::TREBLE:
+ miniDevPM = UserIcon("mix_treble"); break;
+ case MixDevice::UNKNOWN:
+ miniDevPM = UserIcon("mix_unknown"); break;
+ case MixDevice::VOLUME:
+ miniDevPM = UserIcon("mix_volume"); break;
+ case MixDevice::VIDEO:
+ miniDevPM = UserIcon("mix_video"); break;
+ case MixDevice::SURROUND:
+ case MixDevice::SURROUND_BACK:
+ case MixDevice::SURROUND_CENTERFRONT:
+ case MixDevice::SURROUND_CENTERBACK:
+ miniDevPM = UserIcon("mix_surround"); break;
+ case MixDevice::HEADPHONE:
+ miniDevPM = UserIcon( "mix_headphone" ); break;
+ case MixDevice::DIGITAL:
+ miniDevPM = UserIcon( "mix_digital" ); break;
+ case MixDevice::AC97:
+ miniDevPM = UserIcon( "mix_ac97" ); break;
+ default:
+ miniDevPM = UserIcon("mix_unknown"); break;
+ }
+
+ return miniDevPM;
+}
+
+void
+MDWSlider::setIcon( int icontype )
+{
+ if( !m_iconLabel )
+ {
+ m_iconLabel = new QLabel(this);
+ m_iconLabel->setBackgroundOrigin(AncestorOrigin);
+ installEventFilter( m_iconLabel );
+ }
+
+ QPixmap miniDevPM = icon( icontype );
+ if ( !miniDevPM.isNull() )
+ {
+ if ( m_small )
+ {
+ // scale icon
+ QWMatrix t;
+ t = t.scale( 10.0/miniDevPM.width(), 10.0/miniDevPM.height() );
+ m_iconLabel->setPixmap( miniDevPM.xForm( t ) );
+ m_iconLabel->resize( 10, 10 );
+ } else
+ m_iconLabel->setPixmap( miniDevPM );
+ m_iconLabel->setAlignment( Qt::AlignCenter );
+ } else
+ {
+ kdError(67100) << "Pixmap missing." << endl;
+ }
+
+ layout()->activate();
+}
+
+bool
+MDWSlider::isLabeled() const
+{
+ if ( m_label == 0 )
+ return false;
+ else
+ return !m_label->isHidden();
+}
+
+void
+MDWSlider::toggleStereoLinked()
+{
+ setStereoLinked( !isStereoLinked() );
+}
+
+void
+MDWSlider::setStereoLinked(bool value)
+{
+ m_linked = value;
+
+ QWidget *slider = m_sliders.first();
+ QLabel *number = _numbers.first();
+ QString qs = number->text();
+
+ /***********************************************************
+ Remember value of first slider, so that it can be copied
+ to the other sliders.
+ ***********************************************************/
+ int firstSliderValue = 0;
+ bool firstSliderValueValid = false;
+ if (slider->isA("QSlider") ) {
+ QSlider *sld = static_cast<QSlider*>(slider);
+ firstSliderValue = sld->value();
+ firstSliderValueValid = true;
+ }
+ else if ( slider->isA("KSmallSlider") ) {
+ KSmallSlider *sld = static_cast<KSmallSlider*>(slider);
+ firstSliderValue = sld->value();
+ firstSliderValueValid = true;
+ }
+
+ for( slider=m_sliders.next(), number=_numbers.next(); slider!=0 && number!=0; slider=m_sliders.next(), number=_numbers.next() ) {
+ if ( m_linked ) {
+ slider->hide();
+ number->hide();
+ }
+ else {
+ // When splitting, make the next sliders show the same value as the first.
+ // This might not be entirely true, but better than showing the random value
+ // that was used to be shown before hot-fixing this. !! must be revised
+ if ( firstSliderValueValid ) {
+ // Remark: firstSlider== 0 could happen, if the static_cast<QRangeControl*> above fails.
+ // It's a safety measure, if we got other Slider types in the future.
+ if (slider->isA("QSlider") ) {
+ QSlider *sld = static_cast<QSlider*>(slider);
+ sld->setValue( firstSliderValue );
+ }
+ if (slider->isA("KSmallSlider") ) {
+ KSmallSlider *sld = static_cast<KSmallSlider*>(slider);
+ sld->setValue( firstSliderValue );
+ }
+ }
+ slider->show();
+ number->setText(qs);
+ if (m_valueStyle != NNONE)
+ number->show();
+ }
+ }
+
+ slider = m_sliders.last();
+ if( slider && static_cast<QSlider *>(slider)->tickmarks() )
+ setTicks( true );
+
+ layout()->activate();
+}
+
+
+void
+MDWSlider::setLabeled(bool value)
+{
+ if ( m_label == 0 )
+ return;
+
+ if (value )
+ m_label->show();
+ else
+ m_label->hide();
+
+ layout()->activate();
+}
+
+void
+MDWSlider::setTicks( bool ticks )
+{
+ QWidget* slider;
+
+ slider = m_sliders.first();
+
+ if ( slider->inherits( "QSlider" ) )
+ {
+ if( ticks )
+ if( isStereoLinked() )
+ static_cast<QSlider *>(slider)->setTickmarks( QSlider::Right );
+ else
+ {
+ static_cast<QSlider *>(slider)->setTickmarks( QSlider::NoMarks );
+ slider = m_sliders.last();
+ static_cast<QSlider *>(slider)->setTickmarks( QSlider::Left );
+ }
+ else
+ {
+ static_cast<QSlider *>(slider)->setTickmarks( QSlider::NoMarks );
+ slider = m_sliders.last();
+ static_cast<QSlider *>(slider)->setTickmarks( QSlider::NoMarks );
+ }
+ }
+
+ layout()->activate();
+}
+
+void
+MDWSlider::setValueStyle( ValueStyle valueStyle )
+{
+ m_valueStyle = valueStyle;
+
+ int i = 0;
+ QValueList<Volume::ChannelID>::Iterator it = _slidersChids.begin();
+ for(QLabel *number = _numbers.first(); number!=0; number = _numbers.next(), ++i, ++it) {
+ Volume::ChannelID chid = *it;
+ switch ( m_valueStyle ) {
+ case NNONE: number->hide(); break;
+ default:
+ if ( !isStereoLinked() || (i == 0)) {
+ updateValue( number, chid );
+ number->show();
+ }
+ }
+ }
+ layout()->activate();
+}
+
+void
+MDWSlider::setIcons(bool value)
+{
+ if ( m_iconLabel != 0 ) {
+ if ( ( !m_iconLabel->isHidden()) !=value ) {
+ if (value)
+ m_iconLabel->show();
+ else
+ m_iconLabel->hide();
+
+ layout()->activate();
+ }
+ } // if it has an icon
+}
+
+void
+MDWSlider::setColors( QColor high, QColor low, QColor back )
+{
+ for( QWidget *slider=m_sliders.first(); slider!=0; slider=m_sliders.next() ) {
+ KSmallSlider *smallSlider = dynamic_cast<KSmallSlider*>(slider);
+ if ( smallSlider ) smallSlider->setColors( high, low, back );
+ }
+}
+
+void
+MDWSlider::setMutedColors( QColor high, QColor low, QColor back )
+{
+ for( QWidget *slider=m_sliders.first(); slider!=0; slider=m_sliders.next() ) {
+ KSmallSlider *smallSlider = dynamic_cast<KSmallSlider*>(slider);
+ if ( smallSlider ) smallSlider->setGrayColors( high, low, back );
+ }
+}
+
+void
+MDWSlider::updateValue( QLabel *value, Volume::ChannelID chid ) {
+ QString qs;
+ Volume& vol = m_mixdevice->getVolume();
+
+ if (m_valueStyle == NABSOLUTE )
+ qs.sprintf("%3d", (int) vol.getVolume( chid ) );
+ else
+ qs.sprintf("%3d", (int)( vol.getVolume( chid ) / (double)vol.maxVolume() * 100 ) );
+ value->setText(qs);
+}
+
+
+/** This slot is called, when a user has changed the volume via the KMix Slider */
+void MDWSlider::volumeChange( int )
+{
+ // --- Step 1: Get a REFERENCE of the volume Object ---
+ Volume& vol = m_mixdevice->getVolume();
+
+ // --- Step 2: Change the volumes directly in the Volume object to reflect the Sliders ---
+ if ( isStereoLinked() )
+ {
+ QWidget *slider = m_sliders.first();
+ Volume::ChannelID chid = _slidersChids.first();
+
+ int sliderValue = 0;
+ if ( slider->inherits( "KSmallSlider" ) )
+ {
+ KSmallSlider *slider = dynamic_cast<KSmallSlider *>(m_sliders.first());
+ if (slider) {
+ sliderValue= slider->value();
+ }
+ }
+ else {
+ QSlider *slider = dynamic_cast<QSlider *>(m_sliders.first());
+ if (slider) {
+ if ( _orientation == Qt::Vertical )
+ sliderValue= slider->maxValue() - slider->value();
+ else
+ sliderValue= slider->value();
+
+ }
+ }
+
+ // With balance proper working, we must change relative volumes,
+ // not absolute, which leads a make some difference calc related
+ // to new sliders position against the top volume on channels
+ long volumeDif = sliderValue - vol.getTopStereoVolume( Volume::MMAIN );
+
+ if ( chid == Volume::LEFT ) {
+ vol.setVolume( Volume::LEFT , vol.getVolume( Volume::LEFT ) + volumeDif );
+ vol.setVolume( Volume::RIGHT, vol.getVolume( Volume::RIGHT ) + volumeDif );
+ }
+ else {
+ kdDebug(67100) << "MDWSlider::volumeChange(), unknown chid " << chid << endl;
+ }
+
+ updateValue( _numbers.first(), Volume::LEFT );
+ } // joined
+ else {
+ int n = 0;
+ QValueList<Volume::ChannelID>::Iterator it = _slidersChids.begin();
+ QLabel *number = _numbers.first();
+ for( QWidget *slider=m_sliders.first(); slider!=0 && number!=0; slider=m_sliders.next(), number=_numbers.next(), ++it )
+ {
+ Volume::ChannelID chid = *it;
+ if ( slider->inherits( "KSmallSlider" ) )
+ {
+ KSmallSlider *smallSlider = dynamic_cast<KSmallSlider *>(slider);
+ if (smallSlider)
+ vol.setVolume( chid, smallSlider->value() );
+ }
+ else
+ {
+ QSlider *bigSlider = dynamic_cast<QSlider *>(slider);
+ if (bigSlider)
+ if ( _orientation == Qt::Vertical )
+ vol.setVolume( chid, bigSlider->maxValue() - bigSlider->value() );
+ else
+ vol.setVolume( chid, bigSlider->value() );
+ }
+ updateValue( number, chid );
+ n++;
+ }
+ }
+
+ // --- Step 3: Write back the new volumes to the HW ---
+ m_mixer->commitVolumeChange(m_mixdevice);
+}
+
+
+/**
+ This slot is called, when a user has clicked the recsrc button. Also it is called by any other
+ associated KAction like the context menu.
+*/
+void MDWSlider::toggleRecsrc() {
+ setRecsrc( !m_mixdevice->isRecSource() );
+}
+
+
+void MDWSlider::setRecsrc(bool value )
+{
+ if ( m_mixdevice->isRecordable() ) {
+ m_mixer->setRecordSource( m_mixdevice->num(), value );
+ }
+}
+
+
+/**
+ This slot is called, when a user has clicked the mute button. Also it is called by any other
+ associated KAction like the context menu.
+*/
+void MDWSlider::toggleMuted() {
+ setMuted( !m_mixdevice->isMuted() );
+}
+
+void MDWSlider::setMuted(bool value)
+{
+ if ( m_mixdevice->hasMute() ) {
+ m_mixdevice->setMuted( value );
+ m_mixer->commitVolumeChange(m_mixdevice);
+ }
+}
+
+
+void MDWSlider::setDisabled()
+{
+ setDisabled( true );
+}
+
+void MDWSlider::setDisabled( bool value )
+{
+ if ( m_disabled!=value) {
+ value ? hide() : show();
+ m_disabled = value;
+ }
+}
+
+
+/**
+ This slot is called on a MouseWheel event. Also it is called by any other
+ associated KAction like the context menu.
+*/
+void MDWSlider::increaseVolume()
+{
+ Volume vol = m_mixdevice->getVolume();
+ long inc = vol.maxVolume() / 20;
+ if ( inc == 0 )
+ inc = 1;
+ for ( int i = 0; i < vol.count(); i++ ) {
+ long newVal = (vol[i]) + inc;
+ m_mixdevice->setVolume( i, newVal < vol.maxVolume() ? newVal : vol.maxVolume() );
+ }
+ m_mixer->commitVolumeChange(m_mixdevice);
+}
+
+/**
+ This slot is called on a MouseWheel event. Also it is called by any other
+ associated KAction like the context menu.
+*/
+void MDWSlider::decreaseVolume()
+{
+ Volume vol = m_mixdevice->getVolume();
+ long inc = vol.maxVolume() / 20;
+ if ( inc == 0 )
+ inc = 1;
+ for ( int i = 0; i < vol.count(); i++ ) {
+ long newVal = (vol[i]) - inc;
+ m_mixdevice->setVolume( i, newVal > 0 ? newVal : 0 );
+ }
+ m_mixer->commitVolumeChange(m_mixdevice);
+}
+
+
+/**
+ This is called whenever there are volume updates pending from the hardware for this MDW.
+ At the moment it is called regulary via a QTimer (implicitely).
+*/
+void MDWSlider::update()
+{
+ // update volumes
+ Volume vol = m_mixdevice->getVolume();
+ if( isStereoLinked() )
+ {
+ QValueList<Volume::ChannelID>::Iterator it = _slidersChids.begin();
+
+ long avgVol = vol.getAvgVolume( Volume::MMAIN );
+
+ QWidget *slider = m_sliders.first();
+ if ( slider == 0 ) {
+ return; // !!! Development version, check this !!!
+ }
+ slider->blockSignals( true );
+ if ( slider->inherits( "KSmallSlider" ) )
+ {
+ KSmallSlider *smallSlider = dynamic_cast<KSmallSlider *>(slider);
+ if (smallSlider) {
+ smallSlider->setValue( avgVol ); // !! inverted ?!?
+ smallSlider->setGray( m_mixdevice->isMuted() );
+ }
+ } // small slider
+ else {
+ QSlider *bigSlider = dynamic_cast<QSlider *>(slider);
+ if (bigSlider)
+ {
+ // In case of stereo linked and single slider, slider must
+ // show the top of both volumes, and not strangely low down
+ // the main volume by half
+
+ if ( _orientation == Qt::Vertical )
+ bigSlider->setValue( vol.maxVolume() - vol.getTopStereoVolume( Volume::MMAIN ) );
+ else
+ bigSlider->setValue( vol.getTopStereoVolume( Volume::MMAIN ) );
+ }
+ } // big slider
+
+ updateValue( _numbers.first(), Volume::LEFT );
+ slider->blockSignals( false );
+ } // only 1 slider (stereo-linked)
+ else {
+ QValueList<Volume::ChannelID>::Iterator it = _slidersChids.begin();
+ for( int i=0; i<vol.count(); i++, ++it ) {
+ QWidget *slider = m_sliders.at( i );
+ Volume::ChannelID chid = *it;
+ if (slider == 0) {
+ // !!! not implemented !!!
+ // not implemented: happens if there are record and playback
+ // sliders in the same device. Or if you only show
+ // the right slider (or any other fancy occasion)
+ continue;
+ }
+ slider->blockSignals( true );
+
+ if ( slider->inherits( "KSmallSlider" ) )
+ {
+ KSmallSlider *smallSlider = dynamic_cast<KSmallSlider *>(slider);
+ if (smallSlider) {
+ smallSlider->setValue( vol[chid] );
+ smallSlider->setGray( m_mixdevice->isMuted() );
+ }
+ }
+ else
+ {
+ QSlider *bigSlider = dynamic_cast<QSlider *>(slider);
+ if (bigSlider)
+ if ( _orientation == Qt::Vertical ) {
+ bigSlider->setValue( vol.maxVolume() - vol[i] );
+ }
+ else {
+ bigSlider->setValue( vol[i] );
+ }
+ }
+
+ updateValue( _numbers.at ( i ), chid );
+
+ slider->blockSignals( false );
+ } // for all sliders
+ } // more than 1 slider
+
+ // update mute led
+ if ( m_muteLED ) {
+ m_muteLED->blockSignals( true );
+ m_muteLED->setState( m_mixdevice->isMuted() ? KLed::Off : KLed::On );
+ m_muteLED->blockSignals( false );
+ }
+
+ // update recsrc
+ if( m_recordLED ) {
+ m_recordLED->blockSignals( true );
+ m_recordLED->setState( m_mixdevice->isRecSource() ? KLed::On : KLed::Off );
+ m_recordLED->blockSignals( false );
+ }
+}
+
+void MDWSlider::showContextMenu()
+{
+ if( m_mixerwidget == NULL )
+ return;
+
+ KPopupMenu *menu = m_mixerwidget->getPopup();
+ menu->insertTitle( SmallIcon( "kmix" ), m_mixdevice->name() );
+
+ if ( m_sliders.count()>1 ) {
+ KToggleAction *stereo = (KToggleAction *)_mdwActions->action( "stereo" );
+ if ( stereo ) {
+ stereo->setChecked( !isStereoLinked() );
+ stereo->plug( menu );
+ }
+ }
+
+ KToggleAction *ta = (KToggleAction *)_mdwActions->action( "recsrc" );
+ if ( ta ) {
+ ta->setChecked( m_mixdevice->isRecSource() );
+ ta->plug( menu );
+ }
+
+ if ( m_mixdevice->hasMute() ) {
+ ta = ( KToggleAction* )_mdwActions->action( "mute" );
+ if ( ta ) {
+ ta->setChecked( m_mixdevice->isMuted() );
+ ta->plug( menu );
+ }
+ }
+
+ KAction *a = _mdwActions->action( "hide" );
+ if ( a )
+ a->plug( menu );
+
+ a = _mdwActions->action( "keys" );
+ if ( a && m_keys ) {
+ KActionSeparator sep( this );
+ sep.plug( menu );
+ a->plug( menu );
+ }
+
+ QPoint pos = QCursor::pos();
+ menu->popup( pos );
+}
+
+QSize MDWSlider::sizeHint() const {
+ if ( _layout != 0 ) {
+ return _layout->sizeHint();
+ }
+ else {
+ // layout not (yet) created
+ return QWidget::sizeHint();
+ }
+}
+
+/**
+ * An event filter for the various QWidgets. We watch for Mouse press Events, so
+ * that we can popup the context menu.
+ */
+bool MDWSlider::eventFilter( QObject* obj, QEvent* e )
+{
+ if (e->type() == QEvent::MouseButtonPress) {
+ QMouseEvent *qme = static_cast<QMouseEvent*>(e);
+ if (qme->button() == Qt::RightButton) {
+ showContextMenu();
+ return true;
+ }
+ }
+ // Attention: We don't filter WheelEvents for KSmallSlider, because it handles WheelEvents itself
+ else if ( (e->type() == QEvent::Wheel) && !obj->isA("KSmallSlider") ) {
+ QWheelEvent *qwe = static_cast<QWheelEvent*>(e);
+ if (qwe->delta() > 0) {
+ increaseVolume();
+ }
+ else {
+ decreaseVolume();
+ }
+ return true;
+ }
+ return QWidget::eventFilter(obj,e);
+}
+
+#include "mdwslider.moc"
diff --git a/kmix/mdwslider.h b/kmix/mdwslider.h
new file mode 100644
index 00000000..2083c9e4
--- /dev/null
+++ b/kmix/mdwslider.h
@@ -0,0 +1,128 @@
+//-*-C++-*-
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2004 Chrisitan Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MDWSLIDER_H
+#define MDWSLIDER_H
+
+#include <kpanelapplet.h>
+
+#include <qvaluelist.h>
+#include <qwidget.h>
+#include <qlabel.h>
+#include <qptrlist.h>
+#include <qpixmap.h>
+#include <qrangecontrol.h>
+
+class QBoxLayout;
+class QLabel;
+class QPopupMenu;
+class QSlider;
+
+class KLed;
+class KLedButton;
+class KAction;
+class KActionCollection;
+class KSmallSlider;
+class KGlobalAccel;
+
+class MixDevice;
+class VerticalText;
+class Mixer;
+class ViewBase;
+
+#include "mixdevicewidget.h"
+#include "volume.h"
+
+
+class MDWSlider : public MixDeviceWidget
+{
+ Q_OBJECT
+
+public:
+ MDWSlider( Mixer *mixer, MixDevice* md,
+ bool showMuteLED, bool showRecordLED,
+ bool small, Qt::Orientation,
+ QWidget* parent = 0, ViewBase* mw = 0, const char* name = 0);
+ ~MDWSlider() {}
+
+ void addActionToPopup( KAction *action );
+
+ bool isStereoLinked() const { return m_linked; };
+ bool isLabeled() const;
+
+ void setStereoLinked( bool value );
+ void setLabeled( bool value );
+ void setTicks( bool ticks );
+ void setIcons( bool value );
+ void setValueStyle( ValueStyle valueStyle );
+ void setColors( QColor high, QColor low, QColor back );
+ void setMutedColors( QColor high, QColor low, QColor back );
+ QSize sizeHint() const;
+ bool eventFilter( QObject* obj, QEvent* e );
+ QSizePolicy sizePolicy() const;
+
+public slots:
+ void toggleRecsrc();
+ void toggleMuted();
+ void toggleStereoLinked();
+
+ void setDisabled();
+ void setDisabled( bool value );
+ void update();
+ virtual void showContextMenu();
+
+
+signals:
+ void newVolume( int num, Volume volume );
+ void newMasterVolume( Volume volume );
+ void masterMuted( bool );
+ void newRecsrc( int num, bool on );
+ void toggleMenuBar(bool value);
+
+private slots:
+ void setRecsrc( bool value );
+ void setMuted(bool value);
+ void volumeChange( int );
+
+ void increaseVolume();
+ void decreaseVolume();
+
+private:
+ QPixmap icon( int icontype );
+ void setIcon( int icontype );
+ void createWidgets( bool showMuteLED, bool showRecordLED );
+ void updateValue( QLabel *value, Volume::ChannelID chid );
+
+ bool m_linked;
+ ValueStyle m_valueStyle;
+ QLabel *m_iconLabel;
+ KLedButton *m_muteLED;
+ KLedButton *m_recordLED;
+ QWidget *m_label; // is either QLabel or VerticalText
+ QBoxLayout *_layout;
+ QPtrList<QWidget> m_sliders;
+ QValueList<Volume::ChannelID> _slidersChids;
+ QPtrList<QLabel> _numbers;
+ // QValueList<Volume::ChannelID> _numbersChids;
+};
+
+#endif
diff --git a/kmix/mdwswitch.cpp b/kmix/mdwswitch.cpp
new file mode 100644
index 00000000..54f6def1
--- /dev/null
+++ b/kmix/mdwswitch.cpp
@@ -0,0 +1,231 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <qcursor.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qobject.h>
+#include <qslider.h>
+#include <qtooltip.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kaction.h>
+#include <kpopupmenu.h>
+#include <kglobalaccel.h>
+#include <kkeydialog.h>
+#include <kdebug.h>
+
+#include "kledbutton.h"
+#include "mdwswitch.h"
+#include "mixer.h"
+#include "viewbase.h"
+#include "verticaltext.h"
+
+/**
+ * Class that represents a single Switch
+ * The orientation (horizontal, vertical) can be configured and whether it should
+ * be "small" (uses KSmallSlider instead of QSlider then).
+ */
+MDWSwitch::MDWSwitch(Mixer *mixer, MixDevice* md,
+ bool small, Qt::Orientation orientation,
+ QWidget* parent, ViewBase* mw, const char* name) :
+ MixDeviceWidget(mixer,md,small,orientation,parent,mw,name),
+ _label(0) , _labelV(0) , _switchLED(0), _layout(0)
+{
+ // create actions (on _mdwActions, see MixDeviceWidget)
+
+ // KStdAction::showMenubar() is in MixDeviceWidget now
+ new KToggleAction( i18n("&Hide"), 0, this, SLOT(setDisabled()), _mdwActions, "hide" );
+ new KAction( i18n("C&onfigure Shortcuts..."), 0, this, SLOT(defineKeys()), _mdwActions, "keys" );
+
+ // create widgets
+ createWidgets();
+
+ m_keys->insert( "Toggle switch", i18n( "Toggle Switch" ), QString::null,
+ KShortcut(), KShortcut(), this, SLOT( toggleSwitch() ) );
+
+ // The keys are loaded in KMixerWidget::loadConfig, see kmixerwidget.cpp (now: kmixtoolbox.cpp)
+ //m_keys->readSettings();
+ //m_keys->updateConnections();
+
+ installEventFilter( this ); // filter for popup
+}
+
+MDWSwitch::~MDWSwitch()
+{
+}
+
+
+void MDWSwitch::createWidgets()
+{
+ if ( _orientation == Qt::Vertical ) {
+ _layout = new QVBoxLayout( this );
+ _layout->setAlignment(Qt::AlignHCenter);
+ }
+ else {
+ _layout = new QHBoxLayout( this );
+ _layout->setAlignment(Qt::AlignVCenter);
+ }
+ QToolTip::add( this, m_mixdevice->name() );
+
+
+ _layout->addSpacing( 4 );
+ // --- LEDS --------------------------
+ if ( _orientation == Qt::Vertical ) {
+ if( m_mixdevice->isRecordable() )
+ _switchLED = new KLedButton( Qt::red,
+ m_mixdevice->isRecSource()?KLed::On:KLed::Off,
+ KLed::Sunken, KLed::Circular, this, "RecordLED" );
+ else
+ _switchLED = new KLedButton( Qt::yellow, KLed::On, KLed::Sunken, KLed::Circular, this, "SwitchLED" );
+ _switchLED->setFixedSize(16,16);
+ _labelV = new VerticalText( this, m_mixdevice->name().utf8().data() );
+
+ _layout->addWidget( _switchLED );
+ _layout->addSpacing( 2 );
+ _layout->addWidget( _labelV );
+
+ _switchLED->installEventFilter( this );
+ _labelV->installEventFilter( this );
+ }
+ else
+ {
+ if( m_mixdevice->isRecordable() )
+ _switchLED = new KLedButton( Qt::red,
+ m_mixdevice->isRecSource()?KLed::On:KLed::Off,
+ KLed::Sunken, KLed::Circular, this, "RecordLED" );
+ else
+ _switchLED = new KLedButton( Qt::yellow, KLed::On, KLed::Sunken, KLed::Circular, this, "SwitchLED" );
+ _switchLED->setFixedSize(16,16);
+ _label = new QLabel(m_mixdevice->name(), this, "SwitchName");
+
+ _layout->addWidget( _switchLED );
+ _layout->addSpacing( 1 );
+ _layout->addWidget( _label );
+ _switchLED->installEventFilter( this );
+ _label->installEventFilter( this );
+ }
+ connect( _switchLED, SIGNAL(stateChanged(bool)), this, SLOT(toggleSwitch()) );
+ _layout->addSpacing( 4 );
+}
+
+void MDWSwitch::update()
+{
+ if ( _switchLED != 0 ) {
+ _switchLED->blockSignals( true );
+ if( m_mixdevice->isRecordable() )
+ _switchLED->setState( m_mixdevice->isRecSource() ? KLed::On : KLed::Off );
+ else
+ _switchLED->setState( m_mixdevice->isMuted() ? KLed::Off : KLed::On );
+
+ _switchLED->blockSignals( false );
+ }
+}
+
+void MDWSwitch::setBackgroundMode(BackgroundMode m)
+{
+ if ( _label != 0 ){
+ _label->setBackgroundMode(m);
+ }
+ if ( _labelV != 0 ){
+ _labelV->setBackgroundMode(m);
+ }
+ _switchLED->setBackgroundMode(m);
+ MixDeviceWidget::setBackgroundMode(m);
+}
+
+void MDWSwitch::showContextMenu()
+{
+ if( m_mixerwidget == NULL )
+ return;
+
+ KPopupMenu *menu = m_mixerwidget->getPopup();
+
+ QPoint pos = QCursor::pos();
+ menu->popup( pos );
+}
+
+QSize MDWSwitch::sizeHint() const {
+ if ( _layout != 0 ) {
+ return _layout->sizeHint();
+ }
+ else {
+ // layout not (yet) created
+ return QWidget::sizeHint();
+ }
+}
+
+
+/**
+ This slot is called, when a user has clicked the mute button. Also it is called by any other
+ associated KAction like the context menu.
+*/
+void MDWSwitch::toggleSwitch() {
+ if( m_mixdevice->isRecordable() )
+ setSwitch( !m_mixdevice->isRecSource() );
+ else
+ setSwitch( !m_mixdevice->isMuted() );
+}
+
+void MDWSwitch::setSwitch(bool value)
+{
+ if ( m_mixdevice->isSwitch() ) {
+ if ( m_mixdevice->isRecordable() ) {
+ m_mixer->setRecordSource( m_mixdevice->num(), value );
+ }
+ else {
+ m_mixdevice->setMuted( value );
+ m_mixer->commitVolumeChange( m_mixdevice );
+ }
+ }
+}
+
+void MDWSwitch::setDisabled()
+{
+ setDisabled( true );
+}
+
+void MDWSwitch::setDisabled( bool value ) {
+ if ( m_disabled!=value)
+ {
+ value ? hide() : show();
+ m_disabled = value;
+ }
+}
+
+/**
+ * An event filter for the various QWidgets. We watch for Mouse press Events, so
+ * that we can popup the context menu.
+ */
+bool MDWSwitch::eventFilter( QObject* obj, QEvent* e )
+{
+ if (e->type() == QEvent::MouseButtonPress) {
+ QMouseEvent *qme = static_cast<QMouseEvent*>(e);
+ if (qme->button() == Qt::RightButton) {
+ showContextMenu();
+ return true;
+ }
+ }
+ return QWidget::eventFilter(obj,e);
+}
+
+#include "mdwswitch.moc"
diff --git a/kmix/mdwswitch.h b/kmix/mdwswitch.h
new file mode 100644
index 00000000..fd145623
--- /dev/null
+++ b/kmix/mdwswitch.h
@@ -0,0 +1,88 @@
+//-*-C++-*-
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2004 Chrisitan Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MDWSWITCH_H
+#define MDWSWITCH_H
+
+#include <kpanelapplet.h>
+
+#include <qwidget.h>
+#include "volume.h"
+#include <qptrlist.h>
+#include <qpixmap.h>
+#include <qrangecontrol.h>
+
+class QBoxLayout;
+class QLabel;
+class QPopupMenu;
+class QSlider;
+
+class KLedButton;
+class KAction;
+class KActionCollection;
+class KSmallSlider;
+class KGlobalAccel;
+
+class MixDevice;
+class VerticalText;
+class Mixer;
+class ViewBase;
+
+#include "mixdevicewidget.h"
+
+class MDWSwitch : public MixDeviceWidget
+{
+ Q_OBJECT
+
+public:
+ MDWSwitch( Mixer *mixer, MixDevice* md,
+ bool small, Qt::Orientation orientation,
+ QWidget* parent = 0, ViewBase* mw = 0, const char* name = 0);
+ ~MDWSwitch();
+
+ void addActionToPopup( KAction *action );
+ QSize sizeHint() const;
+ void setBackgroundMode(BackgroundMode m);
+ bool eventFilter( QObject* obj, QEvent* e );
+
+public slots:
+ // GUI hide and show
+ void setDisabled();
+ void setDisabled(bool);
+
+ // Switch on/off
+ void toggleSwitch();
+ void setSwitch(bool value);
+
+ void update();
+ virtual void showContextMenu();
+
+private:
+ void createWidgets();
+
+ QLabel *_label;
+ VerticalText *_labelV;
+ KLedButton *_switchLED;
+ QBoxLayout *_layout;
+};
+
+#endif
diff --git a/kmix/mixdevice.cpp b/kmix/mixdevice.cpp
new file mode 100644
index 00000000..16984ceb
--- /dev/null
+++ b/kmix/mixdevice.cpp
@@ -0,0 +1,221 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "mixdevice.h"
+
+
+/**
+ * Constructs a MixDevice. A MixDevice represents one channel or control of
+ * the mixer hardware. A MixDevice has a type (e.g. PCM), a descriptive name
+ * (for example "Master" or "Headphone" or "IEC 958 Output"),
+ * can have a volume level (2 when stereo), can be recordable and muted.
+ * The category tells which kind of control the MixDevice is.
+ *
+ * Hints: Meaning of "category" has changed. In future the MixDevice might contain two
+ * Volume objects, one for Output (Playback volume) and one for Input (Record volume).
+ */
+MixDevice::MixDevice( int num, Volume &vol, bool recordable, bool mute,
+ QString name, ChannelType type, DeviceCategory category ) :
+ _volume( vol ), _type( type ), _num( num ), _recordable( recordable ),
+ _mute( mute ), _category( category )
+{
+ // Hint: "_volume" gets COPIED from "vol" due to the fact that the copy-constructor actually copies the volume levels.
+ _switch = false;
+ _recSource = false;
+ if( name.isEmpty() )
+ _name = i18n("unknown");
+ else
+ _name = name;
+
+ _pk.setNum(num);
+
+
+ if( category == MixDevice::SWITCH )
+ _switch = true;
+}
+
+MixDevice::MixDevice(const MixDevice &md) : QObject()
+{
+ _name = md._name;
+ _volume = md._volume;
+ _type = md._type;
+ _num = md._num;
+ _pk = md._pk;
+ _recordable = md._recordable;
+ _recSource = md._recSource;
+ _category = md._category;
+ _switch = md._switch;
+ _mute = md._mute;
+ _enumValues = md._enumValues;
+}
+
+MixDevice::~MixDevice() {
+ // Clear MixDevices enum Strings (switch on auto-delete, so the QString's inside will be cleared)
+ _enumValues.setAutoDelete(true);
+ _enumValues.clear();
+}
+
+Volume& MixDevice::getVolume()
+{
+ return _volume;
+}
+
+long MixDevice::getVolume(Volume::ChannelID chid) {
+ return _volume.getVolume(chid);
+}
+
+long MixDevice::maxVolume() {
+ return _volume.maxVolume();
+}
+
+long MixDevice::minVolume() {
+ return _volume.minVolume();
+}
+
+void MixDevice::setEnumId(int enumId)
+{
+ if ( enumId < _enumValues.count() ) {
+ _enumCurrentId = enumId;
+ }
+}
+
+unsigned int MixDevice::enumId()
+{
+ return _enumCurrentId;
+}
+
+QPtrList<QString>& MixDevice::enumValues() {
+ return _enumValues;
+}
+
+
+// @todo Used only at mixdevicewidget.cpp:625 . Replace that ASAP !!!
+void MixDevice::setVolume( int channel, int volume )
+{
+ _volume.setVolume( (Volume::ChannelID)channel /* ARGH! */, volume );
+}
+
+QString& MixDevice::getPK() {
+ return _pk;
+}
+
+void MixDevice::setPK(QString &PK) {
+ _pk = PK;
+ // The key is used in the config file. It should not contain spaces
+ _pk.replace(' ', '_');
+}
+
+/**
+ * This mehtod is currently only called on "kmixctrl --restore"
+ *
+ * Normally we have a working _volume object already, which is very important,
+ * because we need to read the minimum and maximum volume levels.
+ * (Another solutien would be to "equip" volFromConfig with maxInt and minInt values).
+ */
+void MixDevice::read( KConfig *config, const QString& grp )
+{
+ QString devgrp;
+ devgrp.sprintf( "%s.Dev%i", grp.ascii(), _num );
+ config->setGroup( devgrp );
+ //kdDebug(67100) << "MixDevice::read() of group devgrp=" << devgrp << endl;
+
+ char *nameLeftVolume, *nameRightVolume;
+ if ( _volume.isCapture() ) {
+ nameLeftVolume = "volumeLCapture";
+ nameRightVolume = "volumeRCapture";
+ } else {
+ nameLeftVolume = "volumeL";
+ nameRightVolume = "volumeR";
+ }
+ Volume::ChannelMask chMask = Volume::MNONE;
+ int vl = config->readNumEntry(nameLeftVolume, -1);
+ if (vl!=-1) {
+ chMask = (Volume::ChannelMask)(chMask | Volume::MLEFT);
+ }
+ int vr = config->readNumEntry(nameRightVolume, -1);
+ if (vr!=-1) {
+ chMask = (Volume::ChannelMask)(chMask | Volume::MRIGHT);
+ }
+
+ /*
+ * Now start construction a temporary Volume object.
+ * We take the maxvol and minvol values from _volume, which is already constructed.
+ * Otherwise we would have to wildly guess those values
+ */
+ Volume *volFromConfig = new Volume(chMask, _volume._maxVolume, _volume._minVolume);
+ if (vl!=-1) {
+ volFromConfig->setVolume(Volume::LEFT , vl);
+ }
+ if (vr!=-1) {
+ volFromConfig->setVolume(Volume::RIGHT, vr);
+ }
+ // commit the read config
+ _volume.setVolume(*volFromConfig);
+ delete volFromConfig;
+
+ int mute = config->readNumEntry("is_muted", -1);
+ if ( mute!=-1 ) {
+ _volume.setMuted( mute!=0 );
+ }
+
+ int recsrc = config->readNumEntry("is_recsrc", -1);
+ if ( recsrc!=-1 ) {
+ setRecSource( recsrc!=0 );
+ }
+
+ int enumId = config->readNumEntry("enum_id", -1);
+ if ( enumId != -1 ) {
+ setEnumId( enumId );
+ }
+}
+
+/**
+ * called on "kmixctrl --save" and from the GUI's (currently only on exit)
+ */
+void MixDevice::write( KConfig *config, const QString& grp )
+{
+ QString devgrp;
+ devgrp.sprintf( "%s.Dev%i", grp.ascii(), _num );
+ config->setGroup(devgrp);
+ // kdDebug(67100) << "MixDevice::write() of group devgrp=" << devgrp << endl;
+ char *nameLeftVolume, *nameRightVolume;
+ if ( _volume.isCapture() ) {
+ nameLeftVolume = "volumeLCapture";
+ nameRightVolume = "volumeRCapture";
+ } else {
+ nameLeftVolume = "volumeL";
+ nameRightVolume = "volumeR";
+ }
+ config->writeEntry(nameLeftVolume, getVolume( Volume::LEFT ) );
+ config->writeEntry(nameRightVolume, getVolume( Volume::RIGHT ) );
+ config->writeEntry("is_muted", (int)_volume.isMuted() );
+ config->writeEntry("is_recsrc", (int)isRecSource() );
+ config->writeEntry("name", _name);
+ if ( isEnum() ) {
+ config->writeEntry("enum_id", enumId() );
+ }
+}
+
+#include "mixdevice.moc"
+
diff --git a/kmix/mixdevice.h b/kmix/mixdevice.h
new file mode 100644
index 00000000..89ec052c
--- /dev/null
+++ b/kmix/mixdevice.h
@@ -0,0 +1,114 @@
+#ifndef MixDevice_h
+#define MixDevice_h
+
+#include "volume.h"
+#include <qstring.h>
+#include <kconfig.h>
+#include <qobject.h>
+#include <qptrlist.h>
+
+// ! @todo : CONSIDER MERGING OF MixDevice and Volume classes:
+// Not easy possible, because Volume is used in the driver backends
+
+/* !! @todo : Add 2 fields:
+ * bool update_from_Hardware;
+ * bool update_from_UI;
+ * They will show whether there are pending changes from both sides.
+ * Updates will be faster and more reliable by this.
+ */
+class MixDevice : public QObject
+{
+ Q_OBJECT
+
+ public:
+ // For each ChannelType a special icon exists
+ enum ChannelType {AUDIO = 1, BASS, CD, EXTERNAL, MICROPHONE,
+ MIDI, RECMONITOR, TREBLE, UNKNOWN, VOLUME,
+ VIDEO, SURROUND, HEADPHONE, DIGITAL, AC97,
+ SURROUND_BACK, SURROUND_LFE, SURROUND_CENTERFRONT, SURROUND_CENTERBACK
+ };
+
+
+ // The DeviceCategory tells the type of the device
+ // It is used in bitmasks, so you must use values of 2^n .
+ enum DeviceCategory { UNDEFINED= 0x00, SLIDER=0x01, SWITCH=0x02, ENUM=0x04, ALL=0xff };
+
+
+ MixDevice(int num, Volume &vol, bool recordable, bool mute,
+ QString name, ChannelType type = UNKNOWN, DeviceCategory category =
+SLIDER );
+ MixDevice(const MixDevice &md);
+ ~MixDevice();
+
+ int num() { return _num; };
+ QString name() { return _name; };
+ /**
+ * Returns an unique ID of this MixDevice. By default the number
+ * 'num' from the constructor is returned. It is recommended that
+ * a better ID is set directly after constructing the MixDevice using
+ * the setUniqueID().
+ */
+ QString& getPK();
+ /**
+ * Set a suitable PK for this MixDevice. It is used in looking up
+ * the keys in kmixrc. It is advised to set a nice name, like
+ * 'PCM_2', which would mean "2nd PCM device of the sound card".
+ */
+ void setPK(QString &id);
+ bool isRecordable() { return _recordable; };
+ bool isRecSource() { return _recSource; };
+ bool isSwitch() { return _switch; } // !! change to _category == MixDevice::SWITCH
+ bool isEnum() { return _category == MixDevice::ENUM; }
+ bool isMuted() { return _volume.isMuted(); };
+ bool hasMute() { return _mute; }
+
+ void setMuted(bool value) { _volume.setMuted( value ); };
+ void setVolume( int channel, int volume );
+ void setRecSource( bool rec ) { _recSource = rec; }
+ long getVolume(Volume::ChannelID chid);
+ Volume& getVolume();
+ long maxVolume();
+ long minVolume();
+
+ void setEnumId(int);
+ unsigned int enumId();
+ QPtrList<QString>& enumValues();
+
+ void read( KConfig *config, const QString& grp );
+ void write( KConfig *config, const QString& grp );
+
+ void setType( ChannelType channeltype ) { _type = channeltype; };
+ ChannelType type() { return _type; };
+
+ DeviceCategory category() { return _category; };
+
+ signals:
+ void newVolume( int num, Volume volume );
+
+ protected:
+ Volume _volume;
+ ChannelType _type;
+ // The DeviceCategory tells, how "important" a MixDevice is.
+ // The driver (e.g. mixer_oss.cpp) must set this value. It is
+ // used for deciding what Sliders to show and for distributing
+ // the sliders. It is advised to use the following categories:
+ // BASIC: Master, PCM
+ // PRIMARY: CD, Headphone, Microphone, Line
+ // SECONDARY: All others
+ // SWITCH: All devices which only have a On/Off-Switch
+ int _num; // ioctl() device number of mixer
+ bool _recordable; // Can it be recorded?
+ bool _switch; // On/Off switch // !! remove
+ bool _mute; // Available mute option
+ bool _recSource; // Current rec status
+ DeviceCategory _category; // category
+ QString _name; // Ascii channel name
+ QString _pk; // Primary key, used as part in config file keys
+ // A MixDevice, that is an ENUM, has these _enumValues
+ QPtrList<QString> _enumValues;
+ int _enumCurrentId;
+
+};
+
+#endif
+
diff --git a/kmix/mixdevicewidget.cpp b/kmix/mixdevicewidget.cpp
new file mode 100644
index 00000000..e032f361
--- /dev/null
+++ b/kmix/mixdevicewidget.cpp
@@ -0,0 +1,120 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <klocale.h>
+#include <kled.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kaction.h>
+#include <kpopupmenu.h>
+#include <kglobalaccel.h>
+#include <kkeydialog.h>
+#include <kdebug.h>
+
+#include <qobject.h>
+#include <qcursor.h>
+#include <qslider.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qtooltip.h>
+#include <qwmatrix.h>
+
+#include "mixer.h"
+#include "mixdevicewidget.h"
+#include "viewbase.h"
+#include "kledbutton.h"
+#include "ksmallslider.h"
+#include "verticaltext.h"
+
+/**
+ * Class that represents a single mix device, inlcuding PopUp, muteLED, ...
+ * Used in KMix main window and DockWidget and PanelApplet.
+ * It can be configured to include or exclude the recordLED and the muteLED.
+ * The direction (horizontal, vertical) can be configured and whether it should
+ * be "small" (uses KSmallSlider instead of QSlider then).
+ */
+MixDeviceWidget::MixDeviceWidget(Mixer *mixer, MixDevice* md,
+ bool small, Qt::Orientation orientation,
+ QWidget* parent, ViewBase* mw, const char* name) :
+ QWidget( parent, name ), m_mixer(mixer), m_mixdevice( md ), m_mixerwidget( mw ),
+ m_disabled( false ), _orientation( orientation ), m_small( small )
+{
+ _mdwActions = new KActionCollection( this );
+ m_keys = new KGlobalAccel( this, "Keys" );
+}
+
+MixDeviceWidget::~MixDeviceWidget()
+{
+}
+
+
+void MixDeviceWidget::addActionToPopup( KAction *action )
+{
+ _mdwActions->insert( action );
+}
+
+
+bool MixDeviceWidget::isDisabled() const
+{
+ return m_disabled;
+}
+
+
+KGlobalAccel *MixDeviceWidget::keys( void )
+{
+ return m_keys;
+}
+
+void MixDeviceWidget::defineKeys()
+{
+ if (m_keys) {
+ KKeyDialog::configure(m_keys, 0, false);
+ // The keys are saved in KMixerWidget::saveConfig, see kmixerwidget.cpp
+ m_keys->updateConnections();
+ }
+}
+
+void MixDeviceWidget::volumeChange( int ) { /* is virtual */ }
+void MixDeviceWidget::setDisabled( bool ) { /* is virtual */ }
+void MixDeviceWidget::setVolume( int /*channel*/, int /*vol*/ ) { /* is virtual */ }
+void MixDeviceWidget::setVolume( Volume /*vol*/ ) { /* is virtual */ }
+void MixDeviceWidget::update() { /* is virtual */ }
+void MixDeviceWidget::showContextMenu() { /* is virtual */ }
+void MixDeviceWidget::setColors( QColor , QColor , QColor ) { /* is virtual */ }
+void MixDeviceWidget::setIcons( bool ) { /* is virtual */ }
+void MixDeviceWidget::setLabeled( bool ) { /* is virtual */ }
+void MixDeviceWidget::setMutedColors( QColor , QColor , QColor ) { /* is virtual */ }
+
+
+
+
+void MixDeviceWidget::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button()==RightButton )
+ showContextMenu();
+ else {
+ QWidget::mousePressEvent(e);
+ }
+}
+
+
+#include "mixdevicewidget.moc"
diff --git a/kmix/mixdevicewidget.h b/kmix/mixdevicewidget.h
new file mode 100644
index 00000000..96242e73
--- /dev/null
+++ b/kmix/mixdevicewidget.h
@@ -0,0 +1,115 @@
+//-*-C++-*-
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ * 1996-2000 Christian Esken <esken@kde.org>
+ * Sven Fischer <herpes@kawo2.rwth-aachen.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MIXDEVICEWIDGET_H
+#define MIXDEVICEWIDGET_H
+
+#include <kpanelapplet.h>
+
+#include <qwidget.h>
+#include "volume.h"
+#include <qptrlist.h>
+#include <qpixmap.h>
+#include <qrangecontrol.h>
+
+class QBoxLayout;
+class QLabel;
+class QPopupMenu;
+class QSlider;
+
+class KLed;
+class KLedButton;
+class KAction;
+class KActionCollection;
+class KSmallSlider;
+class KGlobalAccel;
+
+class MixDevice;
+class VerticalText;
+class Mixer;
+class ViewBase;
+
+class MixDeviceWidget
+ : public QWidget
+{
+ Q_OBJECT
+
+public:
+ enum ValueStyle { NNONE = 0, NABSOLUTE = 1, NRELATIVE = 2 } ;
+
+ MixDeviceWidget( Mixer *mixer, MixDevice* md,
+ bool small, Qt::Orientation orientation,
+ QWidget* parent = 0, ViewBase* mw = 0, const char* name = 0);
+ ~MixDeviceWidget();
+
+ void addActionToPopup( KAction *action );
+
+ virtual bool isDisabled() const;
+ MixDevice* mixDevice() { return m_mixdevice; };
+
+ virtual void setColors( QColor high, QColor low, QColor back );
+ virtual void setIcons( bool value );
+ virtual void setMutedColors( QColor high, QColor low, QColor back );
+
+ virtual bool isStereoLinked() const { return false; };
+ //virtual bool isLabeled() const { return false; };
+ virtual void setStereoLinked( bool ) {};
+ virtual void setLabeled( bool );
+ virtual void setTicks( bool ) {};
+ virtual void setValueStyle( ValueStyle ) {};
+
+ virtual KGlobalAccel *keys(void);
+
+public slots:
+ virtual void setDisabled( bool value );
+ virtual void defineKeys();
+ virtual void update();
+ virtual void showContextMenu();
+
+signals:
+ void newVolume( int num, Volume volume );
+ void newMasterVolume( Volume volume );
+ void masterMuted( bool );
+ void newRecsrc( int num, bool on );
+
+protected slots:
+ void volumeChange( int );
+ virtual void setVolume( int channel, int volume );
+ virtual void setVolume( Volume volume );
+
+protected:
+ Mixer* m_mixer;
+ MixDevice* m_mixdevice;
+ KActionCollection* _mdwActions;
+ KGlobalAccel* m_keys;
+ ViewBase* m_mixerwidget;
+ bool m_disabled;
+ Qt::Orientation _orientation;
+ bool m_small;
+
+private:
+ void mousePressEvent( QMouseEvent *e );
+};
+
+#endif
diff --git a/kmix/mixer.cpp b/kmix/mixer.cpp
new file mode 100644
index 00000000..316625e0
--- /dev/null
+++ b/kmix/mixer.cpp
@@ -0,0 +1,753 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken - esken@kde.org
+ * 2002 Helio Chissini de Castro - helio@conectiva.com.br
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <qtimer.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <dcopobject.h>
+
+#include "mixer.h"
+#include "mixer_backend.h"
+#include "kmix-platforms.cpp"
+#include "volume.h"
+
+//#define MIXER_MASTER_DEBUG
+
+#ifdef MIXER_MASTER_DEBUG
+#warning MIXER_MASTER_DEBUG is enabled. DO NOT SHIP KMIX LIKE THIS !!!
+#endif
+
+/**
+ * Some general design hints. Hierachy is Mixer->MixDevice->Volume
+ */
+
+// !! Warning: Don't commit with "KMIX_DCOP_OBJID_TEST" #define'd (cesken)
+#undef KMIX_DCOP_OBJID_TEST
+int Mixer::_dcopID = 0;
+
+QPtrList<Mixer> Mixer::s_mixers;
+QString Mixer::_masterCard;
+QString Mixer::_masterCardDevice;
+
+int Mixer::numDrivers()
+{
+ MixerFactory *factory = g_mixerFactories;
+ int num = 0;
+ while( factory->getMixer!=0 )
+ {
+ num++;
+ factory++;
+ }
+
+ return num;
+}
+
+/*
+ * Returns a reference of the current mixer list.
+ */
+QPtrList<Mixer>& Mixer::mixers()
+{
+ return s_mixers;
+}
+
+
+Mixer::Mixer( int driver, int device ) : DCOPObject( "Mixer" )
+{
+ _pollingTimer = 0;
+
+ _mixerBackend = 0;
+ getMixerFunc *f = g_mixerFactories[driver].getMixer;
+ if( f!=0 ) {
+ _mixerBackend = f( device );
+ }
+
+ readSetFromHWforceUpdate(); // enforce an initial update on first readSetFromHW()
+
+ m_balance = 0;
+ m_profiles.setAutoDelete( true );
+
+ _pollingTimer = new QTimer(); // will be started on open() and stopped on close()
+ connect( _pollingTimer, SIGNAL(timeout()), this, SLOT(readSetFromHW()));
+
+ QCString objid;
+#ifndef KMIX_DCOP_OBJID_TEST
+ objid.setNum(_mixerBackend->m_devnum);
+#else
+// should use a nice name like the Unique-Card-ID instead !!
+ objid.setNum(Mixer::_dcopID);
+ Mixer::_dcopID ++;
+#endif
+ objid.prepend("Mixer");
+ DCOPObject::setObjId( objid );
+
+}
+
+Mixer::~Mixer() {
+ // Close the mixer. This might also free memory, depending on the called backend method
+ close();
+ delete _pollingTimer;
+}
+
+void Mixer::volumeSave( KConfig *config )
+{
+ // kdDebug(67100) << "Mixer::volumeSave()" << endl;
+ readSetFromHW();
+ QString grp("Mixer");
+ grp.append(mixerName());
+ _mixerBackend->m_mixDevices.write( config, grp );
+}
+
+void Mixer::volumeLoad( KConfig *config )
+{
+ QString grp("Mixer");
+ grp.append(mixerName());
+ if ( ! config->hasGroup(grp) ) {
+ // no such group. Volumes (of this mixer) were never saved beforehand.
+ // Thus don't restore anything (also see Bug #69320 for understanding the real reason)
+ return; // make sure to bail out immediately
+ }
+
+ // else restore the volumes
+ _mixerBackend->m_mixDevices.read( config, grp );
+
+ // set new settings
+ QPtrListIterator<MixDevice> it( _mixerBackend->m_mixDevices );
+ for(MixDevice *md=it.toFirst(); md!=0; md=++it )
+ {
+ // kdDebug(67100) << "Mixer::volumeLoad() writeVolumeToHW(" << md->num() << ", "<< md->getVolume() << ")" << endl;
+ // !! @todo Restore record source
+ //setRecordSource( md->num(), md->isRecSource() );
+ _mixerBackend->setRecsrcHW( md->num(), md->isRecSource() );
+ _mixerBackend->writeVolumeToHW( md->num(), md->getVolume() );
+ if ( md->isEnum() ) _mixerBackend->setEnumIdHW( md->num(), md->enumId() );
+ }
+}
+
+
+/**
+ * Opens the mixer.
+ * Also, starts the polling timer, for polling the Volumes from the Mixer.
+ *
+ * @return 0, if OK. An Mixer::ERR_ error code otherwise
+ */
+int Mixer::open()
+{
+ int err = _mixerBackend->open();
+ // A better ID is now calculated in mixertoolbox.cpp, and set via setID(),
+ // but we want a somhow usable fallback just in case.
+ _id = mixerName();
+
+ if( err == ERR_INCOMPATIBLESET ) // !!! When does this happen ?!?
+ {
+ // Clear the mixdevices list
+ _mixerBackend->m_mixDevices.clear();
+ // try again with fresh set
+ err = _mixerBackend->open();
+ }
+
+ MixDevice* recommendedMaster = _mixerBackend->recommendedMaster();
+ if ( recommendedMaster != 0 ) {
+ setMasterDevice(recommendedMaster->getPK() );
+ }
+ else {
+ kdError(67100) << "Mixer::open() no master detected." << endl;
+ QString noMaster = "---no-master-detected---";
+ setMasterDevice(noMaster); // no master
+ }
+ /*
+ // --------- Copy the hardware values to the MixDevice -------------------
+ MixSet &mset = _mixerBackend->m_mixDevices;
+ if( !mset.isEmpty() ) {
+ // Copy the initial mix set
+ // kdDebug(67100) << "Mixer::setupMixer() copy Set" << endl;
+ MixDevice* md;
+ for( md = mset.first(); md != 0; md = mset.next() )
+ {
+ MixDevice* mdCopy = _mixerBackend->m_mixDevices.first();
+ while( mdCopy!=0 && mdCopy->num() != md->num() ) {
+ mdCopy = _mixerBackend->m_mixDevices.next();
+ }
+ if ( mdCopy != 0 ) {
+ // The "mdCopy != 0" was not checked before, but its safer to do so
+ setRecordSource( md->num(), md->isRecSource() );
+ Volume &vol = mdCopy->getVolume();
+ vol.setVolume( md->getVolume() );
+ mdCopy->setMuted( md->isMuted() );
+
+ // !! might need writeVolumeToHW( mdCopy->num(), mdCopy->getVolume() );
+ }
+ }
+ }
+ */
+ if ( _mixerBackend->needsPolling() ) {
+ _pollingTimer->start(50);
+ }
+ else {
+ _mixerBackend->prepareSignalling(this);
+ // poll once to give the GUI a chance to rebuild it's info
+ QTimer::singleShot( 50, this, SLOT( readSetFromHW() ) );
+ }
+ return err;
+}
+
+
+/**
+ * Closes the mixer.
+ * Also, stops the polling timer.
+ *
+ * @return 0 (always)
+ */
+int Mixer::close()
+{
+ _pollingTimer->stop();
+ return _mixerBackend->close();
+}
+
+
+/* ------- WRAPPER METHODS. START ------------------------------ */
+unsigned int Mixer::size() const
+{
+ return _mixerBackend->m_mixDevices.count();
+}
+
+MixDevice* Mixer::operator[](int num)
+{
+ MixDevice* md = _mixerBackend->m_mixDevices.at( num );
+ Q_ASSERT( md );
+ return md;
+}
+
+MixSet Mixer::getMixSet()
+{
+ return _mixerBackend->m_mixDevices;
+}
+
+bool Mixer::isValid() {
+ return _mixerBackend->isValid();
+}
+
+bool Mixer::isOpen() const {
+ if ( _mixerBackend == 0 )
+ return false;
+ else
+ return _mixerBackend->isOpen();
+}
+
+/* ------- WRAPPER METHODS. END -------------------------------- */
+
+/**
+ * After calling this, readSetFromHW() will do a complete update. This will
+ * trigger emitting the appropriate signals like newVolumeLevels().
+ *
+ * This method is useful, if you need to get a "refresh signal" - used at:
+ * 1) Start of KMix - so that we can be sure an initial signal is emitted
+ * 2) When reconstructing any MixerWidget (e.g. DockIcon after applying preferences)
+ */
+void Mixer::readSetFromHWforceUpdate() const {
+ _readSetFromHWforceUpdate = true;
+}
+
+/**
+ You can call this to retrieve the freshest information from the mixer HW.
+ This method is also called regulary by the mixer timer.
+*/
+void Mixer::readSetFromHW()
+{
+ if ( ! _mixerBackend->isOpen() ) {
+ // bail out immediately, if the mixer is not open.
+ // This can happen currently only, if the user executes the DCOP close() call.
+ return;
+ }
+ bool updated = _mixerBackend->prepareUpdateFromHW();
+ if ( (! updated) && (! _readSetFromHWforceUpdate) ) {
+ // Some drivers (ALSA) are smart. We don't need to run the following
+ // time-consuming update loop if there was no change
+ return;
+ }
+ _readSetFromHWforceUpdate = false;
+ MixDevice* md;
+ for( md = _mixerBackend->m_mixDevices.first(); md != 0; md = _mixerBackend->m_mixDevices.next() )
+ {
+ Volume& vol = md->getVolume();
+ _mixerBackend->readVolumeFromHW( md->num(), vol );
+ md->setRecSource( _mixerBackend->isRecsrcHW( md->num() ) );
+ if (md->isEnum() ) {
+ md->setEnumId( _mixerBackend->enumIdHW(md->num()) );
+ }
+ }
+ // Trivial implementation. Without looking at the devices
+ // kdDebug(67100) << "Mixer::readSetFromHW(): emit newVolumeLevels()" << endl;
+ emit newVolumeLevels();
+ emit newRecsrc(); // cheap, but works
+}
+
+
+void Mixer::setBalance(int balance)
+{
+ // !! BAD, because balance only works on the master device. If you have not Master, the slider is a NOP
+ if( balance == m_balance ) {
+ // balance unchanged => return
+ return;
+ }
+
+ m_balance = balance;
+
+ MixDevice* master = masterDevice();
+ if ( master == 0 ) {
+ // no master device available => return
+ return;
+ }
+
+ Volume& vol = master->getVolume();
+ _mixerBackend->readVolumeFromHW( master->num(), vol );
+
+ int left = vol[ Volume::LEFT ];
+ int right = vol[ Volume::RIGHT ];
+ int refvol = left > right ? left : right;
+ if( balance < 0 ) // balance left
+ {
+ vol.setVolume( Volume::LEFT, refvol);
+ vol.setVolume( Volume::RIGHT, (balance * refvol) / 100 + refvol );
+ }
+ else
+ {
+ vol.setVolume( Volume::LEFT, -(balance * refvol) / 100 + refvol );
+ vol.setVolume( Volume::RIGHT, refvol);
+ }
+
+ _mixerBackend->writeVolumeToHW( master->num(), vol );
+
+ emit newBalance( vol );
+}
+
+QString Mixer::mixerName()
+{
+ return _mixerBackend->m_mixerName;
+}
+
+QString Mixer::driverName( int driver )
+{
+ getDriverNameFunc *f = g_mixerFactories[driver].getDriverName;
+ if( f!=0 )
+ return f();
+ else
+ return "unknown";
+}
+
+void Mixer::setID(QString& ref_id)
+{
+ _id = ref_id;
+}
+
+
+QString& Mixer::id()
+{
+ return _id;
+}
+
+void Mixer::setMasterCard(QString& ref_id)
+{
+ // The value is taken over without checking on existance. This allows the User to define
+ // a MasterCard that is not always available (e.g. it is an USB hotplugging device).
+ // Also you can set the master at any time you like, e.g. after reading the KMix configuration file
+ // and before actually constructing the Mixer instances (hint: this mehtod is static!).
+ _masterCard = ref_id;
+}
+
+Mixer* Mixer::masterCard()
+{
+ Mixer *mixer = 0;
+ kdDebug(67100) << "Mixer::masterCard() searching for id=" << _masterCard << "\n";
+ for (mixer=Mixer::mixers().first(); mixer!=0; mixer=Mixer::mixers().next())
+ {
+ if ( mixer->id() == _masterCard ) {
+#ifdef MIXER_MASTER_DEBUG
+ kdDebug(67100) << "Mixer::masterCard() found id=" << mixer->id() << "\n";
+#endif
+ break;
+ }
+ }
+#ifdef MIXER_MASTER_DEBUG
+ if ( mixer == 0) kdDebug(67100) << "Mixer::masterCard() found no Mixer* mixer \n";
+#endif
+ return mixer;
+}
+
+void Mixer::setMasterCardDevice(QString& ref_id)
+{
+ // The value is taken over without checking on existance. This allows the User to define
+ // a MasterCard that is not always available (e.g. it is an USB hotplugging device).
+ // Also you can set the master at any time you like, e.g. after reading the KMix configuration file
+ // and before actually constructing the Mixer instances (hint: this mehtod is static!).
+ _masterCardDevice = ref_id;
+#ifdef MIXER_MASTER_DEBUG
+ kdDebug(67100) << "Mixer::setMasterCardDevice(\"" << ref_id << "\")\n";
+#endif
+}
+
+MixDevice* Mixer::masterCardDevice()
+{
+ MixDevice* md = 0;
+ Mixer *mixer = masterCard();
+ if ( mixer != 0 ) {
+ for( md = mixer->_mixerBackend->m_mixDevices.first(); md != 0; md = mixer->_mixerBackend->m_mixDevices.next() ) {
+
+
+ if ( md->getPK() == _masterCardDevice )
+ {
+#ifdef MIXER_MASTER_DEBUG
+ kdDebug(67100) << "Mixer::masterCardDevice() getPK()="
+ << md->getPK() << " , _masterCardDevice="
+ << _masterCardDevice << "\n";
+#endif
+ break;
+ }
+ }
+ }
+
+#ifdef MIXER_MASTER_DEBUG
+ if ( md == 0) kdDebug(67100) << "Mixer::masterCardDevice() found no MixDevice* md" "\n";
+#endif
+
+ return md;
+}
+
+
+
+
+/**
+ Used internally by the Mixer class and as DCOP method
+*/
+void Mixer::setRecordSource( int devnum, bool on )
+{
+ if( !_mixerBackend->setRecsrcHW( devnum, on ) ) // others have to be updated
+ {
+ for( MixDevice* md = _mixerBackend->m_mixDevices.first(); md != 0; md = _mixerBackend->m_mixDevices.next() ) {
+ bool isRecsrc = _mixerBackend->isRecsrcHW( md->num() );
+// kdDebug(67100) << "Mixer::setRecordSource(): isRecsrcHW(" << md->num() << ") =" << isRecsrc << endl;
+ md->setRecSource( isRecsrc );
+ }
+ // emitting is done after read
+ //emit newRecsrc(); // like "emit newVolumeLevels()", but for record source
+ }
+ else {
+ // just the actual mixdevice
+ for( MixDevice* md = _mixerBackend->m_mixDevices.first(); md != 0; md = _mixerBackend->m_mixDevices.next() ) {
+ if( md->num() == devnum ) {
+ bool isRecsrc = _mixerBackend->isRecsrcHW( md->num() );
+ md->setRecSource( isRecsrc );
+ }
+ }
+ // emitting is done after read
+ //emit newRecsrc(); // like "emit newVolumeLevels()", but for record source
+ }
+
+}
+
+
+MixDevice* Mixer::masterDevice()
+{
+ return find( _masterDevicePK );
+}
+
+void Mixer::setMasterDevice(QString &devPK)
+{
+ _masterDevicePK = devPK;
+}
+
+
+MixDevice* Mixer::find(QString& devPK)
+{
+ MixDevice* md = 0;
+ for( md = _mixerBackend->m_mixDevices.first(); md != 0; md = _mixerBackend->m_mixDevices.next() ) {
+ if( devPK == md->getPK() ) {
+ break;
+ }
+ }
+ return md;
+}
+
+
+MixDevice *Mixer::mixDeviceByType( int deviceidx )
+{
+ unsigned int i=0;
+ while (i<size() && (*this)[i]->num()!=deviceidx) i++;
+ if (i==size()) return 0;
+
+ return (*this)[i];
+}
+
+// @dcop
+// Used also by the setMasterVolume() method.
+void Mixer::setVolume( int deviceidx, int percentage )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return;
+
+ Volume vol=mixdev->getVolume();
+ // @todo The next call doesn't handle negative volumes correctly.
+ vol.setAllVolumes( (percentage*vol.maxVolume())/100 );
+ _mixerBackend->writeVolumeToHW(deviceidx, vol);
+}
+
+/**
+ Call this if you have a *reference* to a Volume object and have modified that locally.
+ Pass the MixDevice associated to that Volume to this method for writing back
+ the changed value to the mixer.
+ Hint: Why do we do it this way?
+ - It is fast (no copying of Volume objects required)
+ - It is easy to understand ( read - modify - commit )
+*/
+void Mixer::commitVolumeChange( MixDevice* md ) {
+ _mixerBackend->writeVolumeToHW(md->num(), md->getVolume() );
+ _mixerBackend->setEnumIdHW(md->num(), md->enumId() );
+}
+
+// @dcop only
+void Mixer::setMasterVolume( int percentage )
+{
+ MixDevice *master = masterDevice();
+ if (master != 0 ) {
+ setVolume( master->num(), percentage );
+ }
+}
+
+// @dcop
+int Mixer::volume( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return 0;
+
+ Volume vol=mixdev->getVolume();
+ // @todo This will not work, if minVolume != 0 !!!
+ // e.g.: minVolume=5 or minVolume=-10
+ // The solution is to check two cases:
+ // volume < 0 => use minVolume for volumeRange
+ // volume > 0 => use maxVolume for volumeRange
+ // If chosen volumeRange==0 => return 0
+ // As this is potentially used often (Sliders, ...), it
+ // should beimplemented in the Volume class.
+
+ // For now we go with "maxVolume()", like in the rest of KMix.
+ long volumeRange = vol.maxVolume(); // -vol.minVolume() ;
+ if ( volumeRange == 0 )
+ {
+ return 0;
+ }
+ else
+ {
+ return ( vol.getVolume( Volume::LEFT )*100) / volumeRange ;
+ }
+}
+
+// @dcop , especially for use in KMilo
+void Mixer::setAbsoluteVolume( int deviceidx, long absoluteVolume ) {
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return;
+
+ Volume vol=mixdev->getVolume();
+ vol.setAllVolumes( absoluteVolume );
+ _mixerBackend->writeVolumeToHW(deviceidx, vol);
+}
+
+// @dcop , especially for use in KMilo
+long Mixer::absoluteVolume( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return 0;
+
+ Volume vol=mixdev->getVolume();
+ long avgVolume=vol.getAvgVolume((Volume::ChannelMask)(Volume::MLEFT | Volume::MRIGHT));
+ return avgVolume;
+}
+
+// @dcop , especially for use in KMilo
+long Mixer::absoluteVolumeMax( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return 0;
+
+ Volume vol=mixdev->getVolume();
+ long maxVolume=vol.maxVolume();
+ return maxVolume;
+}
+
+// @dcop , especially for use in KMilo
+long Mixer::absoluteVolumeMin( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return 0;
+
+ Volume vol=mixdev->getVolume();
+ long minVolume=vol.minVolume();
+ return minVolume;
+}
+
+// @dcop
+int Mixer::masterVolume()
+{
+ int vol = 0;
+ MixDevice *master = masterDevice();
+ if (master != 0 ) {
+ vol = volume( master->num() );
+ }
+ return vol;
+}
+
+// @dcop
+void Mixer::increaseVolume( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (mixdev != 0) {
+ Volume vol=mixdev->getVolume();
+ double fivePercent = (vol.maxVolume()-vol.minVolume()+1) / 20;
+ for (unsigned int i=Volume::CHIDMIN; i <= Volume::CHIDMAX; i++) {
+ int volToChange = vol.getVolume((Volume::ChannelID)i);
+ if ( fivePercent < 1 ) fivePercent = 1;
+ volToChange += (int)fivePercent;
+ vol.setVolume((Volume::ChannelID)i, volToChange);
+ }
+ _mixerBackend->writeVolumeToHW(deviceidx, vol);
+ }
+
+ /* see comment at the end of decreaseVolume()
+ int vol=volume(deviceidx);
+ setVolume(deviceidx, vol+5);
+ */
+}
+
+// @dcop
+void Mixer::decreaseVolume( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (mixdev != 0) {
+ Volume vol=mixdev->getVolume();
+ double fivePercent = (vol.maxVolume()-vol.minVolume()+1) / 20;
+ for (unsigned int i=Volume::CHIDMIN; i <= Volume::CHIDMAX; i++) {
+ int volToChange = vol.getVolume((Volume::ChannelID)i);
+ //std::cout << "Mixer::decreaseVolume(): before: volToChange " <<i<< "=" <<volToChange << std::endl;
+ if ( fivePercent < 1 ) fivePercent = 1;
+ volToChange -= (int)fivePercent;
+ //std::cout << "Mixer::decreaseVolume(): after: volToChange " <<i<< "=" <<volToChange << std::endl;
+ vol.setVolume((Volume::ChannelID)i, volToChange);
+ //int volChanged = vol.getVolume((Volume::ChannelID)i);
+ //std::cout << "Mixer::decreaseVolume(): check: volChanged " <<i<< "=" <<volChanged << std::endl;
+ } // for
+ _mixerBackend->writeVolumeToHW(deviceidx, vol);
+ }
+
+ /************************************************************
+ It is important, not to implement this method like this:
+ int vol=volume(deviceidx);
+ setVolume(deviceidx, vol-5);
+ It creates too big rounding errors. If you don't beleive me, then
+ do a decreaseVolume() and increaseVolume() with "vol.maxVolume() == 31".
+ ***********************************************************/
+}
+
+// @dcop
+void Mixer::setMute( int deviceidx, bool on )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return;
+
+ mixdev->setMuted( on );
+
+ _mixerBackend->writeVolumeToHW(deviceidx, mixdev->getVolume() );
+}
+
+// @dcop only
+void Mixer::setMasterMute( bool on )
+{
+ MixDevice *master = masterDevice();
+ if (master != 0 ) {
+ setMute( master->num(), on );
+ }
+}
+
+
+// @dcop
+void Mixer::toggleMute( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return;
+
+ bool previousState= mixdev->isMuted();
+
+ mixdev->setMuted( !previousState );
+
+ _mixerBackend->writeVolumeToHW(deviceidx, mixdev->getVolume() );
+}
+
+// @dcop only
+void Mixer::toggleMasterMute()
+{
+ MixDevice *master = masterDevice();
+ if (master != 0 ) {
+ toggleMute( master->num() );
+ }
+}
+
+
+// @dcop
+bool Mixer::mute( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return true;
+
+ return mixdev->isMuted();
+}
+
+// @dcop only
+bool Mixer::masterMute()
+{
+ MixDevice *master = masterDevice();
+ if (master != 0 ) {
+ return mute( master->num() );
+ }
+ return true;
+}
+
+// @dcop only
+int Mixer::masterDeviceIndex()
+{
+ return masterDevice()->num();
+}
+
+bool Mixer::isRecordSource( int deviceidx )
+{
+ MixDevice *mixdev= mixDeviceByType( deviceidx );
+ if (!mixdev) return false;
+
+ return mixdev->isRecSource();
+}
+
+/// @DCOP WHAT DOES THIS METHOD?!?!?
+bool Mixer::isAvailableDevice( int deviceidx )
+{
+ return mixDeviceByType( deviceidx );
+}
+
+#include "mixer.moc"
diff --git a/kmix/mixer.h b/kmix/mixer.h
new file mode 100644
index 00000000..b6d0917a
--- /dev/null
+++ b/kmix/mixer.h
@@ -0,0 +1,174 @@
+//-*-C++-*-
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ * 1996-2000 Christian Esken <esken@kde.org>
+ * Sven Fischer <herpes@kawo2.rwth-aachen.de>
+ * 2002 - Helio Chissini de Castro <helio@conectiva.com.br>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MIXER_H
+#define MIXER_H
+
+#include <qstring.h>
+#include <qtimer.h>
+#include <qobject.h>
+#include <qintdict.h>
+#include <qptrlist.h>
+
+#include "volume.h"
+class Mixer_Backend;
+#include "mixerIface.h"
+#include "mixset.h"
+#include "mixdevice.h"
+
+class Volume;
+class KConfig;
+
+class Mixer : public QObject, virtual public MixerIface
+{
+ Q_OBJECT
+
+ public:
+ enum MixerError { ERR_PERM=1, ERR_WRITE, ERR_READ, ERR_NODEV, ERR_NOTSUPP,
+ ERR_OPEN, ERR_LASTERR, ERR_NOMEM, ERR_INCOMPATIBLESET, ERR_MIXEROPEN };
+
+ Mixer( int driver, int device );
+ virtual ~Mixer();
+
+ static int numDrivers();
+
+ MixDevice* find(QString& devPK);
+
+ void volumeSave( KConfig *config );
+ void volumeLoad( KConfig *config );
+
+ /// Tells the number of the mixing devices
+ unsigned int size() const;
+
+ bool isValid();
+ bool isOpen() const;
+
+ /// Returns a pointer to the mix device with the given number
+ MixDevice* operator[](int val_i_num);
+
+ /// Returns a pointer to the mix device whose type matches the value
+ /// given by the parameter and the array MixerDevNames given in
+ /// mixer_oss.cpp (0 is Volume, 4 is PCM, etc.)
+ MixDevice *mixDeviceByType( int deviceidx );
+
+ /// Open/grab the mixer for further intraction
+ virtual int open();
+ /// Close/release the mixer
+ virtual int close();
+
+ /// Returns a detailed state message after errors. Only for diagnostic purposes, no i18n.
+ QString& stateMessage() const;
+
+ virtual QString mixerName();
+
+ // Returns the name of the driver, e.g. "OSS" or "ALSA0.9"
+ static QString driverName(int num);
+
+ /// Returns an unique ID of the Mixer. It currently looks like "<soundcard_descr>:<hw_number>@<driver>"
+ QString& id();
+ /// The owner/creator of the Mixer can set an unique name here. This key should never displayed to
+ /// the user, but can be used for referencing configuration items and such.
+ void setID(QString& ref_id);
+
+ /// The KMix global master card. Please note that KMix and KMixPanelApplet can have a
+ /// different MasterCard's at the moment (but actually KMixPanelApplet does not read/save this yet).
+ /// At the moment it is only used for selecting the Mixer to use in KMix's DockIcon.
+ static void setMasterCard(QString& ref_id);
+ static Mixer* masterCard();
+ /// The global Master Device inside the current MasterCard (as returned by masterCard()).
+ static void setMasterCardDevice(QString& ref_id);
+ static MixDevice* masterCardDevice();
+
+
+ /// get the actual MixSet
+ MixSet getMixSet();
+
+ /// Returns the master volume device (doesn't work out :-(. See masterCard() and masterCardDevice() instead)
+ MixDevice* masterDevice();
+ /// Sets the master volume device (doesn't work out :-(. See setMasterCard() and setMasterCardDevice() instead)
+ void setMasterDevice(QString&);
+
+ /// DCOP oriented methods (look at mixerIface.h for the descriptions)
+ virtual void setVolume( int deviceidx, int percentage );
+ virtual void setAbsoluteVolume( int deviceidx, long absoluteVolume );
+ virtual void setMasterVolume( int percentage );
+
+ virtual void increaseVolume( int deviceidx );
+ virtual void decreaseVolume( int deviceidx );
+
+ virtual long absoluteVolume( int deviceidx );
+ virtual long absoluteVolumeMin( int deviceidx );
+ virtual long absoluteVolumeMax( int deviceidx );
+ virtual int volume( int deviceidx );
+ virtual int masterVolume();
+ virtual int masterDeviceIndex();
+
+ virtual void setMute( int deviceidx, bool on );
+ virtual void setMasterMute( bool on );
+ virtual bool mute( int deviceidx );
+ virtual bool masterMute();
+ virtual void toggleMute( int deviceidx );
+ virtual void toggleMasterMute();
+ virtual bool isRecordSource( int deviceidx );
+
+ virtual bool isAvailableDevice( int deviceidx );
+
+ void commitVolumeChange( MixDevice* md );
+
+ public slots:
+ virtual void readSetFromHW();
+ void readSetFromHWforceUpdate() const;
+ virtual void setRecordSource( int deviceidx, bool on );
+
+ virtual void setBalance(int balance); // sets the m_balance (see there)
+
+ signals:
+ void newBalance( Volume& );
+ void newRecsrc( void );
+ void newVolumeLevels(void);
+
+ protected:
+ QTimer* _pollingTimer;
+
+ int m_balance; // from -100 (just left) to 100 (just right)
+
+ QPtrList<MixSet> m_profiles;
+ static QPtrList<Mixer> s_mixers;
+
+ public:
+ int setupMixer( MixSet set );
+ static QPtrList<Mixer>& mixers();
+
+ private:
+ Mixer_Backend *_mixerBackend;
+ mutable bool _readSetFromHWforceUpdate;
+ static int _dcopID;
+ QString _id;
+ QString _masterDevicePK;
+ static QString _masterCard;
+ static QString _masterCardDevice;
+};
+
+#endif
diff --git a/kmix/mixerIface.h b/kmix/mixerIface.h
new file mode 100644
index 00000000..6c8da9fd
--- /dev/null
+++ b/kmix/mixerIface.h
@@ -0,0 +1,135 @@
+#ifndef __MIXER_IFACE_H
+#define __MIXER_IFACE_H
+
+#include <dcopobject.h>
+
+class MixerIface : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+ /**
+ Sets the volume of the device with index deviceidx to the percentage
+ specified in the second parameter. The deviceidx is got from the array
+ at the start of mixer_oss.cpp .
+ */
+ virtual void setVolume( int deviceidx, int percentage )=0;
+ /**
+ A simpler way to access the master volume (which is deviceidx 0).
+ */
+ virtual void setMasterVolume( int percentage )=0;
+
+ /**
+ Increase the volume of the given device by a 5% .
+ */
+ virtual void increaseVolume( int deviceidx )=0;
+ /**
+ Decrease the volume of the given device by a 5% .
+ */
+ virtual void decreaseVolume( int deviceidx )=0;
+
+ /**
+ Returns the volume of the device (as a percentage, 0..100).
+ */
+ virtual int volume( int deviceidx )=0;
+ /**
+ Returns the volume of the master device (as a percentage, 0..100).
+ */
+ virtual int masterVolume()=0;
+
+
+ /**
+ Sets the absolute volume of the device. Lower bound is absoluteVolumeMin(),
+ upper bound is absoluteVolumeMax().
+ */
+ virtual void setAbsoluteVolume( int deviceidx, long absoluteVolume )=0;
+ /**
+ Returns the absolute volume of the device. The volume is in the range of
+ absoluteVolumeMin() <= absoluteVolume() <= absoluteVolumeMax()
+ */
+ virtual long absoluteVolume( int deviceidx )=0;
+ /**
+ Returns the absolute maximum volume of the device.
+ */
+ virtual long absoluteVolumeMin( int deviceidx )=0;
+ /**
+ Returns the absolute minimum volume of the device.
+ */
+ virtual long absoluteVolumeMax( int deviceidx )=0;
+
+ /**
+ Mutes or unmutes the specified device.
+ */
+ virtual void setMute( int deviceidx, bool on )=0;
+ /**
+ Mutes or unmutes the master device.
+ */
+ virtual void setMasterMute( bool on )=0;
+ /**
+ Toggles mute-state for the given device.
+ */
+ virtual void toggleMute( int deviceidx )=0;
+ /**
+ Toggles mute-state for the master device.
+ */
+ virtual void toggleMasterMute()=0;
+ /**
+ Returns if the given device is muted or not. If the device is not
+ available in this mixer, it is reported as muted.
+ */
+ virtual bool mute( int deviceidx )=0;
+ /**
+ Returns if the master device is muted or not. If the device is not
+ available in this mixer, it is reported as muted.
+ */
+ virtual bool masterMute()=0;
+
+ /**
+ Returns the index of the master device
+ */
+ virtual int masterDeviceIndex()=0;
+
+ /**
+ Makes the given device a record source.
+ */
+ virtual void setRecordSource( int deviceidx, bool on )=0;
+
+ /**
+ Returns if the given device is a record source.
+ */
+ virtual bool isRecordSource( int deviceidx )=0;
+
+ /**
+ Sets the balance of the master device (negative means balanced to the left
+ speaker and positive to the right one)
+ */
+ virtual void setBalance( int balance )=0;
+
+ /**
+ Returns true if the given device is available in the current mixer
+ and false if it's not.
+ */
+ virtual bool isAvailableDevice( int deviceidx )=0;
+
+ /**
+ Returns the name of the mixer.
+ */
+ virtual QString mixerName()=0;
+
+ /**
+ * Open/grab the mixer for further intraction
+ * You should use this method after a prior call of close(). See close() for usage directions.
+ */
+ virtual int open()=0;
+
+ /**
+ * Close/release the mixer
+ * This method SHOULD NOT be used via DCOP. You MAY use it if you really need to close the mixer device,
+ * for example when a software suspend action (ACPI) takes place, and the soundcard driver
+ * doesn't handle this situation gracefully.
+ */
+ virtual int close()=0;
+
+};
+
+#endif
diff --git a/kmix/mixer_alsa.h b/kmix/mixer_alsa.h
new file mode 100644
index 00000000..da04e372
--- /dev/null
+++ b/kmix/mixer_alsa.h
@@ -0,0 +1,53 @@
+#ifndef MIXER_ALSA_H
+#define MIXER_ALSA_H
+
+// QT includes
+#include <qvaluelist.h>
+
+// Forward QT includes
+class QString;
+class QSocketNotifier;
+
+#include "mixer_backend.h"
+
+class Mixer_ALSA : public Mixer_Backend
+{
+ public:
+ Mixer_ALSA( int device = -1 );
+ ~Mixer_ALSA();
+
+ virtual int readVolumeFromHW( int devnum, Volume &vol );
+ virtual int writeVolumeToHW( int devnum, Volume &vol );
+ virtual bool setRecsrcHW( int devnum, bool on);
+ virtual bool isRecsrcHW( int devnum );
+ virtual void setEnumIdHW(int mixerIdx, unsigned int);
+ virtual unsigned int enumIdHW(int mixerIdx);
+ virtual bool prepareUpdateFromHW();
+ virtual bool needsPolling() { return false; }
+ virtual void prepareSignalling( Mixer *mixer );
+
+ protected:
+ virtual int open();
+ virtual int close();
+
+ private:
+ int identify( snd_mixer_selem_id_t *sid );
+ snd_mixer_elem_t* getMixerElem(int devnum);
+ void removeSignalling();
+
+ virtual QString errorText(int mixer_error);
+ typedef QValueList<snd_mixer_selem_id_t *>AlsaMixerSidList;
+ AlsaMixerSidList mixer_sid_list;
+ typedef QValueList<snd_mixer_elem_t *> AlsaMixerElemList; // !! remove
+ AlsaMixerElemList mixer_elem_list; // !! remove
+
+ bool _initialUpdate;
+ snd_mixer_t *_handle;
+ QString devName;
+ struct pollfd *m_fds;
+ QSocketNotifier **m_sns;
+ int m_count;
+
+};
+
+#endif
diff --git a/kmix/mixer_alsa9.cpp b/kmix/mixer_alsa9.cpp
new file mode 100644
index 00000000..e55f6112
--- /dev/null
+++ b/kmix/mixer_alsa9.cpp
@@ -0,0 +1,828 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ * Alsa 0.9x and 1.0 - Based on original alsamixer code
+ * from alsa-project ( www/alsa-project.org )
+ *
+ *
+ * Copyright (C) 2002 Helio Chissini de Castro <helio@conectiva.com.br>
+ * 2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+// STD Headers
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <assert.h>
+#include <qsocketnotifier.h>
+
+extern "C"
+{
+ #include <alsa/asoundlib.h>
+}
+
+// KDE Headers
+#include <klocale.h>
+#include <kdebug.h>
+
+// Local Headers
+#include "mixer_alsa.h"
+//#include "mixer.h"
+#include "volume.h"
+// #define if you want MUCH debugging output
+//#define ALSA_SWITCH_DEBUG
+//#define KMIX_ALSA_VOLUME_DEBUG
+
+Mixer_Backend*
+ALSA_getMixer( int device )
+{
+ Mixer_Backend *l_mixer;
+ l_mixer = new Mixer_ALSA( device );
+ return l_mixer;
+}
+
+Mixer_ALSA::Mixer_ALSA( int device ) : Mixer_Backend( device )
+{
+ m_fds = 0;
+ m_sns = 0;
+ _handle = 0;
+ _initialUpdate = true;
+}
+
+Mixer_ALSA::~Mixer_ALSA()
+{
+ close();
+}
+
+int
+Mixer_ALSA::identify( snd_mixer_selem_id_t *sid )
+{
+ QString name = snd_mixer_selem_id_get_name( sid );
+
+ if ( name == "Master" ) return MixDevice::VOLUME;
+ if ( name == "Capture" ) return MixDevice::RECMONITOR;
+ if ( name == "Master Mono" ) return MixDevice::VOLUME;
+ if ( name == "PC Speaker" ) return MixDevice::VOLUME;
+ if ( name == "Music" || name == "Synth" || name == "FM" ) return MixDevice::MIDI;
+ if ( name.find( "Headphone", 0, false ) != -1 ) return MixDevice::HEADPHONE;
+ if ( name == "Bass" ) return MixDevice::BASS;
+ if ( name == "Treble" ) return MixDevice::TREBLE;
+ if ( name == "CD" ) return MixDevice::CD;
+ if ( name == "Video" ) return MixDevice::VIDEO;
+ if ( name == "PCM" || name == "Wave" ) return MixDevice::AUDIO;
+ if ( name == "Surround" ) return MixDevice::SURROUND_BACK;
+ if ( name == "Center" ) return MixDevice::SURROUND_CENTERFRONT;
+ if ( name.find( "ac97", 0, false ) != -1 ) return MixDevice::AC97;
+ if ( name.find( "coaxial", 0, false ) != -1 ) return MixDevice::DIGITAL;
+ if ( name.find( "optical", 0, false ) != -1 ) return MixDevice::DIGITAL;
+ if ( name.find( "IEC958", 0, false ) != -1 ) return MixDevice::DIGITAL;
+ if ( name.find( "Mic" ) != -1 ) return MixDevice::MICROPHONE;
+ if ( name.find( "LFE" ) != -1 ) return MixDevice::SURROUND_LFE;
+ if ( name.find( "Monitor" ) != -1 ) return MixDevice::RECMONITOR;
+ if ( name.find( "3D", 0, false ) != -1 ) return MixDevice::SURROUND; // Should be probably some own icon
+
+ return MixDevice::EXTERNAL;
+}
+
+int
+Mixer_ALSA::open()
+{
+ bool virginOpen = m_mixDevices.isEmpty();
+ bool validDevice = false;
+ bool masterChosen = false;
+ int err;
+
+ snd_ctl_t *ctl_handle;
+ snd_ctl_card_info_t *hw_info;
+ snd_ctl_card_info_alloca(&hw_info);
+
+ snd_mixer_elem_t *elem;
+ snd_mixer_selem_id_t *sid;
+ snd_mixer_selem_id_alloca( &sid );
+
+ // Card information
+ if( m_devnum == -1 )
+ m_devnum = 0;
+ if ( (unsigned)m_devnum > 31 )
+ devName = "default";
+ else
+ devName = QString( "hw:%1" ).arg( m_devnum );
+
+ QString probeMessage;
+
+ if (virginOpen)
+ probeMessage += "Trying ALSA Device '" + devName + "': ";
+
+ if ( ( err = snd_ctl_open ( &ctl_handle, devName.latin1(), 0 ) ) < 0 )
+ {
+ kdDebug(67100) << probeMessage << "not found: snd_ctl_open err=" << snd_strerror(err) << endl;
+ //_stateMessage = errorText( Mixer::ERR_NODEV );
+ return Mixer::ERR_OPEN;
+ }
+
+ if ( ( err = snd_ctl_card_info ( ctl_handle, hw_info ) ) < 0 )
+ {
+ kdDebug(67100) << probeMessage << "not found: snd_ctl_card_info err=" << snd_strerror(err) << endl;
+ //_stateMessage = errorText( Mixer::ERR_READ );
+ snd_ctl_close( ctl_handle );
+ return Mixer::ERR_READ;
+ }
+
+ // Device and mixer names
+ const char* mixer_card_name = snd_ctl_card_info_get_name( hw_info );
+ //mixer_device_name = snd_ctl_card_info_get_mixername( hw_info );
+ // Copy the name of kmix mixer from card name (mixername is rumoured to be not that good)
+ m_mixerName = mixer_card_name;
+
+ snd_ctl_close( ctl_handle );
+
+ /* open mixer device */
+
+ //kdDebug(67100) << "IN Mixer_ALSA snd_mixer_open()" << endl;
+ if ( ( err = snd_mixer_open ( &_handle, 0 ) ) < 0 )
+ {
+ kdDebug(67100) << probeMessage << "not found: snd_mixer_open err=" << snd_strerror(err) << endl;
+ //errormsg( Mixer::ERR_NODEV );
+ _handle = 0;
+ return Mixer::ERR_NODEV; // if we cannot open the mixer, we have no devices
+ }
+ //kdDebug(67100) << "OUT Mixer_ALSA snd_mixer_open()" << endl;
+
+ if ( ( err = snd_mixer_attach ( _handle, devName.latin1() ) ) < 0 )
+ {
+ kdDebug(67100) << probeMessage << "not found: snd_mixer_attach err=" << snd_strerror(err) << endl;
+ //errormsg( Mixer::ERR_PERM );
+ return Mixer::ERR_OPEN;
+ }
+
+ if ( ( err = snd_mixer_selem_register ( _handle, NULL, NULL ) ) < 0 )
+ {
+ kdDebug(67100) << probeMessage << "not found: snd_mixer_selem_register err=" << snd_strerror(err) << endl;
+ //errormsg( Mixer::ERR_READ );
+ return Mixer::ERR_READ;
+ }
+
+ if ( ( err = snd_mixer_load ( _handle ) ) < 0 )
+ {
+ kdDebug(67100) << probeMessage << "not found: snd_mixer_load err=" << snd_strerror(err) << endl;
+ //errormsg( Mixer::ERR_READ );
+ close();
+ return Mixer::ERR_READ;
+ }
+
+ kdDebug(67100) << probeMessage << "found" << endl;
+
+ unsigned int mixerIdx = 0;
+ for ( elem = snd_mixer_first_elem( _handle ); elem; elem = snd_mixer_elem_next( elem ), mixerIdx++ )
+ {
+ // If element is not active, just skip
+ if ( ! snd_mixer_selem_is_active ( elem ) ) {
+ // ...but we still want to insert a null value into our mixer element
+ // list so that the list indexes match up.
+ mixer_elem_list.append( 0 );
+ mixer_sid_list.append( 0 );
+ continue;
+ }
+
+
+ sid = (snd_mixer_selem_id_t*)malloc(snd_mixer_selem_id_sizeof()); // I believe *we* must malloc it for ourself
+ snd_mixer_selem_get_id( elem, sid );
+
+ bool canRecord = false;
+ bool canMute = false;
+ bool canCapture = false;
+ long maxVolumePlay= 0, minVolumePlay= 0;
+ long maxVolumeRec = 0, minVolumeRec = 0;
+ validDevice = true;
+
+ snd_mixer_selem_get_playback_volume_range( elem, &minVolumePlay, &maxVolumePlay );
+ snd_mixer_selem_get_capture_volume_range( elem, &minVolumeRec , &maxVolumeRec );
+ // New mix device
+ MixDevice::ChannelType ct = (MixDevice::ChannelType)identify( sid );
+/*
+ if (!masterChosen && ct==MixDevice::VOLUME) {
+ // Determine a nicer MasterVolume
+ m_masterDevice = mixerIdx;
+ masterChosen = true;
+ }
+*/
+ if( virginOpen )
+ {
+ MixDevice::DeviceCategory cc = MixDevice::UNDEFINED;
+
+ //kdDebug() << "--- Loop: name=" << snd_mixer_selem_id_get_name( sid ) << " , mixerIdx=" << mixerIdx << "------------" << endl;
+
+ Volume* volPlay = 0, *volCapture = 0;
+ QPtrList<QString> enumList;
+ if ( snd_mixer_selem_is_enumerated(elem) ) {
+ cc = MixDevice::ENUM;
+ volPlay = new Volume(); // Dummy, unused
+ volCapture = new Volume();
+ mixer_elem_list.append( elem );
+ mixer_sid_list.append( sid );
+
+ // --- get Enum names START ---
+ int numEnumitems = snd_mixer_selem_get_enum_items(elem);
+ if ( numEnumitems > 0 ) {
+ // OK. no error
+ for (int iEnum = 0; iEnum<numEnumitems; iEnum++ ) {
+ char buffer[100];
+ int ret = snd_mixer_selem_get_enum_item_name(elem, iEnum, 99, buffer);
+ if ( ret == 0 ) {
+ QString* enumName = new QString(buffer);
+ //enumName->append(buffer);
+ enumList.append( enumName);
+ } // enumName could be read succesfully
+ } // for all enum items of this device
+ } // no error in reading enum list
+ else {
+ // 0 items or Error code => ignore this entry
+ }
+ // --- get Enum names END ---
+ } // is an enum
+
+ else {
+ Volume::ChannelMask chn = Volume::MNONE;
+ Volume::ChannelMask chnTmp;
+ if ( snd_mixer_selem_has_playback_volume(elem) ) {
+ //kdDebug(67100) << "has_playback_volume()" << endl;
+ chnTmp = snd_mixer_selem_is_playback_mono ( elem )
+ ? Volume::MLEFT : (Volume::ChannelMask)(Volume::MLEFT | Volume::MRIGHT);
+ chn = (Volume::ChannelMask) (chn | chnTmp);
+ cc = MixDevice::SLIDER;
+ volPlay = new Volume( chn, maxVolumePlay, minVolumePlay );
+ } else {
+ volPlay = new Volume();
+ }
+ if ( snd_mixer_selem_has_capture_volume(elem) ) {
+ //kdDebug(67100) << "has_capture_volume()" << endl;
+ chnTmp = snd_mixer_selem_is_capture_mono( elem )
+ ? Volume::MLEFT : (Volume::ChannelMask)(Volume::MLEFT | Volume::MRIGHT );
+ chn = (Volume::ChannelMask) (chn | chnTmp);
+ cc = MixDevice::SLIDER;
+ canCapture = true;
+ volCapture = new Volume( chn, maxVolumeRec, minVolumeRec, true );
+ } else {
+ volCapture = new Volume();
+ }
+
+ /* Create Volume object. If there is no volume on this device,
+ * it will be created with maxVolume == 0 && minVolume == 0 */
+ mixer_elem_list.append( elem );
+ mixer_sid_list.append( sid );
+
+ if ( snd_mixer_selem_has_playback_switch ( elem ) ) {
+ //kdDebug(67100) << "has_playback_switch()" << endl;
+ canMute = true;
+ }
+ if ( snd_mixer_selem_has_capture_switch ( elem ) ) {
+ //kdDebug(67100) << "has_capture_switch()" << endl;
+ canRecord = true;
+ }
+ if ( snd_mixer_selem_has_common_switch ( elem ) ) {
+ //kdDebug(67100) << "has_common_switch()" << endl;
+ canMute = true;
+ canRecord = true;
+ }
+
+ if ( /*snd_mixer_selem_has_common_switch ( elem ) || */
+ cc == MixDevice::UNDEFINED )
+ {
+ // Everything unknown is handled as switch
+ cc = MixDevice::SWITCH;
+ }
+ } // is ordinary mixer element (NOT an enum)
+
+ MixDevice* md = new MixDevice( mixerIdx,
+ *volPlay,
+ canRecord,
+ canMute,
+ snd_mixer_selem_id_get_name( sid ),
+ ct,
+ cc );
+
+ m_mixDevices.append( md );
+
+
+ if (!masterChosen && ct==MixDevice::VOLUME) {
+ // Determine a nicer MasterVolume
+ m_recommendedMaster = md;
+ masterChosen = true;
+ }
+
+ if ( canCapture && !canRecord ) {
+ MixDevice *mdCapture =
+ new MixDevice( mixerIdx,
+ *volCapture,
+ true,
+ canMute,
+ snd_mixer_selem_id_get_name( sid ),
+ ct,
+ cc );
+ m_mixDevices.append( mdCapture );
+ }
+
+ if ( enumList.count() > 0 ) {
+ int maxEnumId= enumList.count();
+ QPtrList<QString>& enumValuesRef = md->enumValues(); // retrieve a ref
+ for (int i=0; i<maxEnumId; i++ ) {
+ // we have an enum. Lets set the names of the enum items in the MixDevice
+ // the enum names are assumed to be static!
+ enumValuesRef.append(enumList.at(i) );
+ }
+ }
+ //kdDebug(67100) << "ALSA create MDW, vol= " << *vol << endl;
+ delete volPlay;
+ delete volCapture;
+ } // virginOpen
+ else
+ {
+ MixDevice* md;
+ bool found = false;
+ for ( md = m_mixDevices.first(); md != 0; md = m_mixDevices.next() ) {
+ if ( md->num() == mixerIdx ) {
+ found = true;
+ writeVolumeToHW( mixerIdx, md->getVolume() );
+ }
+ }
+ if( !found )
+ {
+ return Mixer::ERR_INCOMPATIBLESET;
+ }
+ } // !virginOpen
+ } // for all elems
+
+ /**************************************************************************************
+ // If no devices are supported by this soundcard, return "NO Devices"
+ It is VERY important to return THIS error code, so that the caller knows, that the
+ the device exists.
+ This is used for scanning for existing soundcard devices, see MixerToolBox::initMixer().
+ ***************************************************************************************/
+ if ( !validDevice )
+ {
+ return Mixer::ERR_NODEV;
+ }
+
+ // Copy the name of kmix mixer from card name
+ // Real name of mixer is not too good
+ m_mixerName = mixer_card_name;
+
+ // return with success
+ m_isOpen = true;
+
+ /* setup for select on stdin and the mixer fd */
+ if ((m_count = snd_mixer_poll_descriptors_count(_handle)) < 0) {
+ kdDebug(67100) << "Mixer_ALSA::poll() , snd_mixer_poll_descriptors_count() err=" << m_count << "\n";
+ return Mixer::ERR_OPEN;
+ }
+
+ //kdDebug(67100) << "Mixer_ALSA::prepareUpdate() 2\n";
+
+ m_fds = (struct pollfd*)calloc(m_count, sizeof(struct pollfd));
+ if (m_fds == NULL) {
+ kdDebug(67100) << "Mixer_ALSA::poll() , calloc() = null" << "\n";
+ return Mixer::ERR_OPEN;
+ }
+
+ m_fds->events = POLLIN;
+ if ((err = snd_mixer_poll_descriptors(_handle, m_fds, m_count)) < 0) {
+ kdDebug(67100) << "Mixer_ALSA::poll() , snd_mixer_poll_descriptors_count() err=" << err << "\n";
+ return Mixer::ERR_OPEN;
+ }
+ if (err != m_count) {
+ kdDebug(67100) << "Mixer_ALSA::poll() , snd_mixer_poll_descriptors_count() err=" << err << " m_count=" << m_count << "\n";
+ return Mixer::ERR_OPEN;
+ }
+
+ return 0;
+}
+
+void Mixer_ALSA::prepareSignalling( Mixer *mixer )
+{
+ assert( !m_sns );
+
+ m_sns = new QSocketNotifier*[m_count];
+ for ( int i = 0; i < m_count; ++i )
+ {
+ kdDebug() << "socket " << i << endl;
+ m_sns[i] = new QSocketNotifier(m_fds[i].fd, QSocketNotifier::Read);
+ mixer->connect(m_sns[i], SIGNAL(activated(int)), mixer, SLOT(readSetFromHW()));
+ }
+}
+
+void Mixer_ALSA::removeSignalling()
+{
+ if ( m_fds )
+ free( m_fds );
+ m_fds = 0;
+
+ if ( m_sns )
+ {
+ for ( int i = 0; i < m_count; i++ )
+ delete m_sns[i];
+ delete [] m_sns;
+ m_sns = 0;
+ }
+}
+
+int
+Mixer_ALSA::close()
+{
+ int ret=0;
+ m_isOpen = false;
+ if ( _handle != 0 )
+ {
+ //kdDebug(67100) << "IN Mixer_ALSA::close()" << endl;
+ snd_mixer_free ( _handle );
+ if ( ( ret = snd_mixer_detach ( _handle, devName.latin1() ) ) < 0 )
+ {
+ kdDebug(67100) << "snd_mixer_detach err=" << snd_strerror(ret) << endl;
+ }
+ int ret2 = 0;
+ if ( ( ret2 = snd_mixer_close ( _handle ) ) < 0 )
+ {
+ kdDebug(67100) << "snd_mixer_close err=" << snd_strerror(ret2) << endl;
+ if ( ret == 0 ) ret = ret2; // no error before => use current error code
+ }
+
+ _handle = 0;
+ //kdDebug(67100) << "OUT Mixer_ALSA::close()" << endl;
+
+ }
+
+ mixer_elem_list.clear();
+ mixer_sid_list.clear();
+ m_mixDevices.clear();
+
+ removeSignalling();
+
+ return ret;
+}
+
+
+snd_mixer_elem_t* Mixer_ALSA::getMixerElem(int devnum) {
+ snd_mixer_elem_t* elem = 0;
+ if ( ! m_isOpen ) return elem; // unplugging guard
+
+ if ( int( mixer_sid_list.count() ) > devnum ) {
+ snd_mixer_selem_id_t * sid = mixer_sid_list[ devnum ];
+ // The next line (hopefully) only finds selem's, not elem's.
+ elem = snd_mixer_find_selem(_handle, sid);
+
+ if ( elem == 0 ) {
+ // !! Check, whether the warning should be omitted. Probably
+ // Route controls are non-simple elements.
+ kdDebug(67100) << "Error finding mixer element " << devnum << endl;
+ }
+ }
+ return elem;
+
+/*
+ I would have liked to use the following trivial implementation instead of the
+ code above. But it will also return elem's. which are not selem's. As there is
+ no way to check an elem's type (e.g. elem->type == SND_MIXER_ELEM_SIMPLE), callers
+ of getMixerElem() cannot check the type. :-(
+ snd_mixer_elem_t* elem = mixer_elem_list[ devnum ];
+ return elem;
+ */
+}
+
+bool Mixer_ALSA::prepareUpdateFromHW()
+{
+ if ( !m_fds || !m_isOpen )
+ return false;
+
+ //kdDebug(67100) << "Mixer_ALSA::prepareUpdate() 1\n";
+
+ // Poll on fds with 10ms timeout
+ // Hint: alsamixer has an infinite timeout, but we cannot do this because we would block
+ // the X11 event handling (Qt event loop) with this.
+ //kdDebug(67100) << "Mixer_ALSA::prepareUpdate() 3\n";
+ int finished = poll(m_fds, m_count, 10);
+ //kdDebug(67100) << "Mixer_ALSA::prepareUpdate() 4\n";
+
+ bool updated = false;
+ if (finished > 0) {
+ //kdDebug(67100) << "Mixer_ALSA::prepareUpdate() 5\n";
+
+ unsigned short revents;
+
+ if (snd_mixer_poll_descriptors_revents(_handle, m_fds, m_count, &revents) >= 0) {
+ //kdDebug(67100) << "Mixer_ALSA::prepareUpdate() 6\n";
+
+ if (revents & POLLNVAL) {
+ /* Bug 127294 shows, that we receieve POLLNVAL when the user
+ unplugs an USB soundcard. Lets close the card. */
+ kdDebug(67100) << "Mixer_ALSA::poll() , Error: poll() returns POLLNVAL\n";
+ close(); // Card was unplugged (unplug, driver unloaded)
+ return false;
+ }
+ if (revents & POLLERR) {
+ kdDebug(67100) << "Mixer_ALSA::poll() , Error: poll() returns POLLERR\n";
+ return false;
+ }
+ if (revents & POLLIN) {
+ //kdDebug(67100) << "Mixer_ALSA::prepareUpdate() 7\n";
+
+ snd_mixer_handle_events(_handle);
+ updated = true;
+ }
+ }
+
+ }
+ //kdDebug(67100) << "Mixer_ALSA::prepareUpdate() " << updated << endl;;
+ return updated;
+}
+
+bool
+Mixer_ALSA::isRecsrcHW( int devnum )
+{
+ bool isCurrentlyRecSrc = false;
+ snd_mixer_elem_t *elem = getMixerElem( devnum );
+
+ if ( !elem ) {
+ return false;
+ }
+
+ if ( snd_mixer_selem_has_capture_switch( elem ) ) {
+ // Has a on-off switch
+ // Yes, this element can be record source. But the user can switch it off, so lets see if it is switched on.
+ int swLeft;
+ int ret = snd_mixer_selem_get_capture_switch( elem, SND_MIXER_SCHN_FRONT_LEFT, &swLeft );
+ if ( ret != 0 ) {
+ kdDebug(67100) << "snd_mixer_selem_get_capture_switch() failed 1\n";
+ }
+
+ if (snd_mixer_selem_has_capture_switch_joined( elem ) ) {
+ isCurrentlyRecSrc = (swLeft != 0);
+#ifdef ALSA_SWITCH_DEBUG
+ kdDebug(67100) << "Mixer_ALSA::isRecsrcHW() has_switch joined: #" << devnum << " >>> " << swLeft << " : " << isCurrentlyRecSrc << endl;
+#endif
+ }
+ else {
+ int swRight;
+ snd_mixer_selem_get_capture_switch( elem, SND_MIXER_SCHN_FRONT_RIGHT, &swRight );
+ isCurrentlyRecSrc = ( (swLeft != 0) || (swRight != 0) );
+#ifdef ALSA_SWITCH_DEBUG
+ kdDebug(67100) << "Mixer_ALSA::isRecsrcHW() has_switch non-joined, state " << isCurrentlyRecSrc << endl;
+#endif
+ }
+ }
+ else {
+ // Has no on-off switch
+ if ( snd_mixer_selem_has_capture_volume( elem ) ) {
+ // Has a volume, but has no OnOffSwitch => We assume that this is a fixed record source (always on). (esken)
+ isCurrentlyRecSrc = true;
+#ifdef ALSA_SWITCH_DEBUG
+ kdDebug(67100) << "Mixer_ALSA::isRecsrcHW() has_no_switch, state " << isCurrentlyRecSrc << endl;
+#endif
+ }
+ }
+
+ return isCurrentlyRecSrc;
+}
+
+bool
+Mixer_ALSA::setRecsrcHW( int devnum, bool on )
+{
+ int sw = 0;
+ if (on)
+ sw = !sw;
+
+ snd_mixer_elem_t *elem = getMixerElem( devnum );
+ if ( !elem )
+ {
+ return 0;
+ }
+
+ if (snd_mixer_selem_has_capture_switch_joined( elem ) )
+ {
+ int before, after;
+ int ret = snd_mixer_selem_get_capture_switch( elem, SND_MIXER_SCHN_FRONT_LEFT, &before );
+ if ( ret != 0 ) {
+ kdDebug(67100) << "snd_mixer_selem_get_capture_switch() failed 1\n";
+ }
+
+ ret = snd_mixer_selem_set_capture_switch_all( elem, sw );
+ if ( ret != 0 ) {
+ kdDebug(67100) << "snd_mixer_selem_set_capture_switch_all() failed 2: errno=" << ret << "\n";
+ }
+ ret = snd_mixer_selem_get_capture_switch( elem, SND_MIXER_SCHN_FRONT_LEFT, &after );
+ if ( ret != 0 ) {
+ kdDebug(67100) << "snd_mixer_selem_get_capture_switch() failed 3: errno=" << ret << "\n";
+ }
+
+#ifdef ALSA_SWITCH_DEBUG
+ kdDebug(67100) << "Mixer_ALSA::setRecsrcHW(" << devnum << "," << on << ")joined. Before=" << before << " Set=" << sw << " After=" << after <<"\n";
+#endif
+
+ }
+ else
+ {
+#ifdef ALSA_SWITCH_DEBUG
+ kdDebug(67100) << "Mixer_ALSA::setRecsrcHW LEFT\n";
+#endif
+ snd_mixer_selem_set_capture_switch( elem, SND_MIXER_SCHN_FRONT_LEFT, sw );
+#ifdef ALSA_SWITCH_DEBUG
+ kdDebug(67100) << "Mixer_ALSA::setRecsrcHW RIGHT\n";
+#endif
+ snd_mixer_selem_set_capture_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, sw);
+ }
+
+#ifdef ALSA_SWITCH_DEBUG
+ kdDebug(67100) << "EXIT Mixer_ALSA::setRecsrcHW(" << devnum << "," << on << ")\n";
+#endif
+ return false; // we should always return false, so that other devnum's get updated
+ // The ALSA polling has been implemented some time ago. So it should be safe to
+ // return "true" here.
+ // The other devnum's Rec-Sources won't get update by KMix code, but ALSA will send
+ // us an event, if neccesary. But OTOH it is possibly better not to trust alsalib fully,
+ // because the old code is working also well (just takes more processing time).
+ // return true;
+}
+
+/**
+ * Sets the ID of the currently selected Enum entry.
+ * Warning: ALSA supports to have different enums selected on each channel
+ * of the SAME snd_mixer_elem_t. KMix does NOT support that and
+ * always sets both channels (0 and 1).
+ */
+void Mixer_ALSA::setEnumIdHW(int mixerIdx, unsigned int idx) {
+ //kdDebug(67100) << "Mixer_ALSA::setEnumIdHW(" << mixerIdx << ", idx=" << idx << ") 1\n";
+ snd_mixer_elem_t *elem = getMixerElem( mixerIdx );
+ if ( elem==0 || ( !snd_mixer_selem_is_enumerated(elem)) )
+ {
+ return;
+ }
+
+ //kdDebug(67100) << "Mixer_ALSA::setEnumIdHW(" << mixerIdx << ", idx=" << idx << ") 2\n";
+ int ret = snd_mixer_selem_set_enum_item(elem,SND_MIXER_SCHN_FRONT_LEFT,idx);
+ if (ret < 0) {
+ kdError(67100) << "Mixer_ALSA::setEnumIdHW(" << mixerIdx << "), errno=" << ret << "\n";
+ }
+ snd_mixer_selem_set_enum_item(elem,SND_MIXER_SCHN_FRONT_RIGHT,idx);
+ // we don't care about possible error codes on channel 1
+ return;
+}
+
+/**
+ * Return the ID of the currently selected Enum entry.
+ * Warning: ALSA supports to have different enums selected on each channel
+ * of the SAME snd_mixer_elem_t. KMix does NOT support that and
+ * always shows the value of the first channel.
+ */
+unsigned int Mixer_ALSA::enumIdHW(int mixerIdx) {
+ snd_mixer_elem_t *elem = getMixerElem( mixerIdx );
+ if ( elem==0 || ( !snd_mixer_selem_is_enumerated(elem)) )
+ {
+ return 0;
+ }
+
+ unsigned int idx = 0;
+ int ret = snd_mixer_selem_get_enum_item(elem,SND_MIXER_SCHN_FRONT_LEFT,&idx);
+ //kdDebug(67100) << "Mixer_ALSA::enumIdHW(" << mixerIdx << ") idx=" << idx << "\n";
+ if (ret < 0) {
+ idx = 0;
+ kdError(67100) << "Mixer_ALSA::enumIdHW(" << mixerIdx << "), errno=" << ret << "\n";
+ }
+ return idx;
+}
+
+
+int
+Mixer_ALSA::readVolumeFromHW( int mixerIdx, Volume &volume )
+{
+ int elem_sw;
+ long left, right;
+
+ snd_mixer_elem_t *elem = getMixerElem( mixerIdx );
+ if ( !elem )
+ {
+ return 0;
+ }
+
+
+ // *** READ PLAYBACK VOLUMES *************
+ if ( snd_mixer_selem_has_playback_volume( elem ) && !volume.isCapture() )
+ {
+ int ret = snd_mixer_selem_get_playback_volume( elem, SND_MIXER_SCHN_FRONT_LEFT, &left );
+ if ( ret != 0 ) kdDebug(67100) << "readVolumeFromHW(" << mixerIdx << ") [has_playback_volume,R] failed, errno=" << ret << endl;
+ if ( snd_mixer_selem_is_playback_mono ( elem )) {
+ volume.setVolume( Volume::LEFT , left );
+ volume.setVolume( Volume::RIGHT, left );
+ }
+ else {
+ int ret = snd_mixer_selem_get_playback_volume( elem, SND_MIXER_SCHN_FRONT_RIGHT, &right );
+ if ( ret != 0 ) kdDebug(67100) << "readVolumeFromHW(" << mixerIdx << ") [has_playback_volume,R] failed, errno=" << ret << endl;
+ volume.setVolume( Volume::LEFT , left );
+ volume.setVolume( Volume::RIGHT, right );
+ }
+ }
+ else
+ if ( snd_mixer_selem_has_capture_volume ( elem ) && volume.isCapture() )
+ {
+ int ret = snd_mixer_selem_get_capture_volume ( elem, SND_MIXER_SCHN_FRONT_LEFT, &left );
+ if ( ret != 0 ) kdDebug(67100) << "readVolumeFromHW(" << mixerIdx << ") [get_capture_volume,L] failed, errno=" << ret << endl;
+ if ( snd_mixer_selem_is_capture_mono ( elem )) {
+ volume.setVolume( Volume::LEFT , left );
+ volume.setVolume( Volume::RIGHT, left );
+ }
+ else
+ {
+ int ret = snd_mixer_selem_get_capture_volume( elem, SND_MIXER_SCHN_FRONT_RIGHT, &right );
+ if ( ret != 0 ) kdDebug(67100) << "readVolumeFromHW(" << mixerIdx << ") [has_capture_volume,R] failed, errno=" << ret << endl;
+ volume.setVolume( Volume::LEFT , left );
+ volume.setVolume( Volume::RIGHT, right );
+ }
+ }
+
+ //kdDebug() << "snd_mixer_selem_has_playback_volume " << mixerIdx << " " << snd_mixer_selem_has_playback_switch( elem ) << endl;
+ if ( snd_mixer_selem_has_playback_switch( elem ) )
+ {
+ snd_mixer_selem_get_playback_switch( elem, SND_MIXER_SCHN_FRONT_LEFT, &elem_sw );
+ volume.setMuted( elem_sw == 0 );
+ }
+
+ return 0;
+}
+
+int
+Mixer_ALSA::writeVolumeToHW( int devnum, Volume& volume )
+{
+ int left, right;
+
+ snd_mixer_elem_t *elem = getMixerElem( devnum );
+ if ( !elem )
+ {
+ return 0;
+ }
+
+ // --- VOLUME - WE HAVE JUST ONE TYPE OF VOLUME A TIME,
+ // CAPTURE OR PLAYBACK, SO IT"S JUST USE VOLUME ------------
+ left = volume[ Volume::LEFT ];
+ right = volume[ Volume::RIGHT ];
+
+ if (snd_mixer_selem_has_playback_volume( elem ) && !volume.isCapture() ) {
+ snd_mixer_selem_set_playback_volume ( elem, SND_MIXER_SCHN_FRONT_LEFT, left );
+ if ( ! snd_mixer_selem_is_playback_mono ( elem ) )
+ snd_mixer_selem_set_playback_volume ( elem, SND_MIXER_SCHN_FRONT_RIGHT, right );
+ }
+ else if ( snd_mixer_selem_has_capture_volume( elem ) && volume.isCapture() ) {
+ snd_mixer_selem_set_capture_volume ( elem, SND_MIXER_SCHN_FRONT_LEFT, left );
+ if ( ! snd_mixer_selem_is_playback_mono ( elem ) )
+ snd_mixer_selem_set_capture_volume ( elem, SND_MIXER_SCHN_FRONT_RIGHT, right );
+ }
+
+ if ( snd_mixer_selem_has_playback_switch( elem ) )
+ {
+ int sw = 0;
+ if (! volume.isMuted())
+ sw = !sw;
+ snd_mixer_selem_set_playback_switch_all(elem, sw);
+ }
+
+ return 0;
+}
+
+QString
+Mixer_ALSA::errorText( int mixer_error )
+{
+ QString l_s_errmsg;
+ switch ( mixer_error )
+ {
+ case Mixer::ERR_PERM:
+ l_s_errmsg = i18n("You do not have permission to access the alsa mixer device.\n" \
+ "Please verify if all alsa devices are properly created.");
+ break;
+ case Mixer::ERR_OPEN:
+ l_s_errmsg = i18n("Alsa mixer cannot be found.\n" \
+ "Please check that the soundcard is installed and the\n" \
+ "soundcard driver is loaded.\n" );
+ break;
+ default:
+ l_s_errmsg = Mixer_Backend::errorText( mixer_error );
+ }
+ return l_s_errmsg;
+}
+
+
+QString
+ALSA_getDriverName()
+{
+ return "ALSA";
+}
+
+
diff --git a/kmix/mixer_backend.cpp b/kmix/mixer_backend.cpp
new file mode 100644
index 00000000..2eb61089
--- /dev/null
+++ b/kmix/mixer_backend.cpp
@@ -0,0 +1,147 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <klocale.h>
+
+#include "mixer_backend.h"
+// for the "ERR_" declartions, #include mixer.h
+#include "mixer.h"
+
+Mixer_Backend::Mixer_Backend(int device) :
+ m_devnum (device) , m_isOpen(false), m_recommendedMaster(0)
+{
+ m_mixDevices.setAutoDelete( true );
+}
+
+Mixer_Backend::~Mixer_Backend()
+{
+}
+
+
+bool Mixer_Backend::isValid() {
+ bool valid = false;
+ int ret = open();
+ if ( ret == 0 && m_mixDevices.count() > 0) {
+ valid = true;
+ }
+ close();
+ return valid;
+}
+
+bool Mixer_Backend::isOpen() {
+ return m_isOpen;
+}
+
+/**
+ * Queries the backend driver whether there are new changes in any of the controls.
+ * If you cannot find out for a backend, return "true" - this is also the default implementation.
+ * @return true, if there are changes. Otherwise false is returned.
+ */
+bool Mixer_Backend::prepareUpdateFromHW() {
+ return true;
+}
+
+/**
+ * Return the MixDevice, that would qualify best as MasterDevice. The default is to return the
+ * first device in the device list. Backends can override this (i.e. the ALSA Backend does so).
+ * The users preference is NOT returned by this method - see the Mixer class for that.
+ */
+MixDevice* Mixer_Backend::recommendedMaster() {
+ MixDevice* recommendedMixDevice = 0;
+ if ( m_recommendedMaster != 0 ) {
+ recommendedMixDevice = m_recommendedMaster;
+ } // recommendation from Backend
+ else {
+ if ( m_mixDevices.count() > 0 ) {
+ recommendedMixDevice = m_mixDevices.at(0);
+ } //first device (if exists)
+ }
+ return recommendedMixDevice;
+}
+
+/**
+ * Sets the ID of the currently selected Enum entry.
+ * This is a dummy implementation - if the Mixer backend
+ * wants to support it, it must implement the driver specific
+ * code in its subclass (see Mixer_ALSA.cpp for an example).
+ */
+void Mixer_Backend::setEnumIdHW(int, unsigned int) {
+ return;
+}
+
+/**
+ * Return the ID of the currently selected Enum entry.
+ * This is a dummy implementation - if the Mixer backend
+ * wants to support it, it must implement the driver specific
+ * code in its subclass (see Mixer_ALSA.cpp for an example).
+ */
+unsigned int Mixer_Backend::enumIdHW(int) {
+ return 0;
+}
+
+void Mixer_Backend::errormsg(int mixer_error)
+{
+ QString l_s_errText;
+ l_s_errText = errorText(mixer_error);
+ kdError() << l_s_errText << "\n";
+}
+
+QString Mixer_Backend::errorText(int mixer_error)
+{
+ QString l_s_errmsg;
+ switch (mixer_error)
+ {
+ case Mixer::ERR_PERM:
+ l_s_errmsg = i18n("kmix:You do not have permission to access the mixer device.\n" \
+ "Please check your operating systems manual to allow the access.");
+ break;
+ case Mixer::ERR_WRITE:
+ l_s_errmsg = i18n("kmix: Could not write to mixer.");
+ break;
+ case Mixer::ERR_READ:
+ l_s_errmsg = i18n("kmix: Could not read from mixer.");
+ break;
+ case Mixer::ERR_NODEV:
+ l_s_errmsg = i18n("kmix: Your mixer does not control any devices.");
+ break;
+ case Mixer::ERR_NOTSUPP:
+ l_s_errmsg = i18n("kmix: Mixer does not support your platform. See mixer.cpp for porting hints (PORTING).");
+ break;
+ case Mixer::ERR_NOMEM:
+ l_s_errmsg = i18n("kmix: Not enough memory.");
+ break;
+ case Mixer::ERR_OPEN:
+ case Mixer::ERR_MIXEROPEN:
+ // ERR_MIXEROPEN means: Soundcard could be opened, but has no mixer. ERR_MIXEROPEN is normally never
+ // passed to the errorText() method, because KMix handles that case explicitely
+ l_s_errmsg = i18n("kmix: Mixer cannot be found.\n" \
+ "Please check that the soundcard is installed and that\n" \
+ "the soundcard driver is loaded.\n");
+ break;
+ case Mixer::ERR_INCOMPATIBLESET:
+ l_s_errmsg = i18n("kmix: Initial set is incompatible.\n" \
+ "Using a default set.\n");
+ break;
+ default:
+ l_s_errmsg = i18n("kmix: Unknown error. Please report how you produced this error.");
+ break;
+ }
+ return l_s_errmsg;
+}
+
diff --git a/kmix/mixer_backend.h b/kmix/mixer_backend.h
new file mode 100644
index 00000000..8132ea04
--- /dev/null
+++ b/kmix/mixer_backend.h
@@ -0,0 +1,104 @@
+//-*-C++-*-
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MIXER_BACKEND_H
+#define MIXER_BACKEND_H
+
+#include "mixer.h"
+
+class Mixer_Backend
+{
+// The Mixer Backend's may only be accessed from the Mixer class.
+friend class Mixer;
+
+protected:
+ Mixer_Backend(int devnum);
+ virtual ~Mixer_Backend();
+
+ /// Derived classes MUST implement this to open the mixer. Returns a KMix error code (O=OK).
+ virtual int open() = 0;
+ virtual int close() = 0;
+
+ /** Returns, whether this Mixer object contains a valid Mixer. You should return "false", when
+ * the Mixer with the devnum given in the constructor is not supported by the Backend. The two
+ * typical cases are:
+ * (1) No such hardware installed
+ * (2) The hardware exists, but has no mixer support (e.g. external soundcard with only mechanical volume knobs)
+ * The default implementation calls open(), checks the return code and whether the number of
+ * supported channels is > 0. Then it calls close().
+ * You should reimplement this method in your backend, when there is a less time-consuming method than
+ * calling open() and close() for checking the existance of a Mixer.
+ */
+ virtual bool isValid();
+
+ /** @return true, if the Mixer is open (and thus can be operated) */
+ bool isOpen();
+
+ virtual bool prepareUpdateFromHW();
+
+ /// Volume Read
+ virtual int readVolumeFromHW( int devnum, Volume &vol ) = 0;
+ /// Volume Write
+ virtual int writeVolumeToHW( int devnum, Volume &volume ) = 0;
+
+ /// Enums
+ virtual void setEnumIdHW(int mixerIdx, unsigned int);
+ virtual unsigned int enumIdHW(int mixerIdx);
+
+ /// Recording Switches
+ virtual bool setRecsrcHW( int devnum, bool on) = 0;
+ virtual bool isRecsrcHW( int devnum ) = 0;
+
+ /// Overwrite in the backend if the backend can see changes without polling
+ virtual bool needsPolling() { return true; }
+
+ /** overwrite this if you need to connect to slots in the mixer (e.g. readSetFromHW)
+ this called in the very beginning and only if !needsPolling
+ */
+ virtual void prepareSignalling( Mixer * ) {}
+
+ MixDevice* recommendedMaster();
+
+ /** Return a translated error text for the given error number.
+ * Subclasses can override this method to produce platform
+ * specific error descriptions.
+ */
+ virtual QString errorText(int mixer_error);
+ /// Prints out a translated error text for the given error number on stderr
+ void errormsg(int mixer_error);
+
+
+ int m_devnum;
+ /// User friendly name of the Mixer (e.g. "IRIX Audio Mixer"). If your mixer API
+ /// gives you a usable name, use that name.
+ QString m_mixerName;
+ // All mix devices of this phyisical device.
+ MixSet m_mixDevices;
+
+ /******************************************************************************************
+ * Please don't access the next vars from the Mixer class (even though Mixer is a friend).
+ * There are proper accesor methods for them.
+ ******************************************************************************************/
+ bool m_isOpen;
+ // The MixDevice that would qualify best as MasterDevice (according to the taste of the Backend developer)
+ MixDevice* m_recommendedMaster;
+};
+
+#endif
diff --git a/kmix/mixer_hpux.cpp b/kmix/mixer_hpux.cpp
new file mode 100644
index 00000000..e7ca0a83
--- /dev/null
+++ b/kmix/mixer_hpux.cpp
@@ -0,0 +1,257 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2000 Christian Esken
+ * esken@kde.org
+ *
+ * HP/UX-Port: Copyright (C) 1999 by Helge Deller
+ * deller@gmx.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mixer_hpux.h"
+
+#warning "HP/UX mixer (maybe) doesn't work yet !"
+
+#define HPUX_ERROR_OFFSET 1024
+
+#define myGain AUnityGain /* AUnityGain or AZeroGain */
+
+#define GAIN_OUT_DIFF ((long) ((int)aMaxOutputGain(audio) - (int)aMinOutputGain(audio)))
+#define GAIN_OUT_MIN ((long) aMinOutputGain(audio))
+#define GAIN_IN_DIFF ((long) ((int)aMaxInputGain(audio) - (int)aMinInputGain(audio)))
+#define GAIN_IN_MIN ((long) aMinOutputGain(audio))
+
+/* standard */
+#define ID_PCM 4
+
+/* AInputSrcType: */ /*OSS:*/
+#define ID_IN_MICROPHONE 7 /* AISTMonoMicrophone */
+#define ID_IN_AUX 6 /* AISTLeftAuxiliary, AISTRightAuxiliary */
+
+/* AOutputDstType: */
+#define ID_OUT_INT_SPEAKER 0 /* AODTMonoIntSpeaker */
+
+/* not yet implemented:
+ AODTLeftJack, AODTRightJack,
+ AODTLeftLineOut, AODTRightLineOut,
+ AODTLeftHeadphone, AODTRightHeadphone
+
+const char* MixerDevNames[32]={"Volume" , "Bass" , "Treble" , "Synth" , "Pcm" , \
+ "Speaker" , "Line" , "Microphone", "CD" , "Mix" , \
+ "Pcm2" , "RecMon" , "IGain" , "OGain" , "Line1", \
+ "Line2" , "Line3" , "Digital1" , "Digital2", "Digital3", \
+ "PhoneIn" , "PhoneOut", "Video" , "Radio" , "Monitor", \
+ "3D-depth", "3D-center", "unknown" , "unknown" , "unknown", \
+ "unknown" , "unused" };
+*/
+
+
+
+Mixer_HPUX::Mixer_HPUX(int devnum) : Mixer_Backend(devnum)
+{
+ char ServerName[10];
+ ServerName[0] = 0;
+ audio = AOpenAudio(ServerName,NULL);
+}
+
+Mixer_HPUX::~Mixer_HPUX()
+{
+ if (audio) {
+ ACloseAudio(audio,0);
+ audio = 0;
+ }
+}
+
+
+int Mixer_HPUX::open()
+{
+ if (audio==0) {
+ return Mixer::ERR_OPEN;
+ }
+ else
+ {
+ /* Mixer is open. Now define properties */
+ stereodevs = devmask = (1<<ID_PCM); /* activate pcm */
+ recmask = 0;
+
+ /* check Input devices... */
+ if (AInputSources(audio) & AMonoMicrophoneMask) {
+ devmask |= (1<<ID_IN_MICROPHONE);
+ recmask |= (1<<ID_IN_MICROPHONE);
+ }
+ if (AInputSources(audio) & (ALeftAuxiliaryMask|ARightAuxiliaryMask)) {
+ devmask |= (1<<ID_IN_AUX);
+ recmask |= (1<<ID_IN_AUX);
+ stereodevs |= (1<<ID_IN_AUX);
+ }
+
+ /* check Output devices... */
+ if (AOutputDestinations(audio) & AMonoIntSpeakerMask) {
+ devmask |= (1<<ID_OUT_INT_SPEAKER);
+ stereodevs |= (1<<ID_OUT_INT_SPEAKER);
+ }
+
+/* implement later:
+ ----------------
+ if (AOutputDestinations(audio) & AMonoLineOutMask) devmask |= 64; // Line
+ if (AOutputDestinations(audio) & AMonoJackMask) devmask |= (1<<14); // Line1
+ if (AOutputDestinations(audio) & AMonoHeadphoneMask) devmask |= (1<<15); // Line2
+*/
+
+ MaxVolume = 255;
+
+ long error = 0;
+ ASetSystemPlayGain(audio, myGain, &error);
+ if (error) errorText(error + HPUX_ERROR_OFFSET);
+ ASetSystemRecordGain(audio, myGain, &error);
+ if (error) errorText(error + HPUX_ERROR_OFFSET);
+
+ i_recsrc = 0;
+ m_isOpen = true;
+
+ m_mixerName = "HP Mixer"; /* AAudioString(audio); */
+ return 0;
+ }
+}
+
+int Mixer_HPUX::close()
+{
+ m_isOpen = false;
+ m_mixDevices.clear();
+ return 0;
+}
+
+
+/*
+void Mixer_HPUX::setDevNumName_I(int devnum)
+{
+ devname = "HP Mixer";
+}
+*/
+bool Mixer_HPUX::setRecsrcHW( int devnum, bool on )
+{
+ return FALSE;
+}
+
+bool Mixer_HPUX::isRecsrcHW( int devnum )
+{
+ return FALSE;
+}
+
+int Mixer_HPUX::readVolumeFromHW( int devnum, Volume &vol )
+{
+ long Gain;
+ long error = 0;
+ int vl,vr;
+
+ switch (devnum) {
+ case ID_OUT_INT_SPEAKER: /* AODTMonoIntSpeaker */
+ AGetSystemChannelGain(audio, ASGTPlay, ACTMono, &Gain, &error );
+ vl = vr = (Gain-GAIN_OUT_MIN)*255 / GAIN_OUT_DIFF;
+ vol.setVolume( Volume::LEFT, vl);
+ vol.setVolume( Volume::RIGHT, vr);
+printf("READ - Devnum: %d, Left: %d, Right: %d\n", devnum, vl, vr );
+ break;
+
+ case ID_IN_AUX: /* AISTLeftAuxiliary, AISTRightAuxiliary */
+ case ID_IN_MICROPHONE: /* AISTMonoMicrophone */
+ AGetSystemChannelGain(audio, ASGTRecord, ACTMono, &Gain, &error );
+ vl = vr = (Gain-GAIN_IN_MIN)*255 / GAIN_IN_DIFF;
+ vol.setVolume( Volume::LEFT, vl);
+ vol.setVolume( Volume::RIGHT, vr);
+ break;
+
+ default:
+ error = Mixer::ERR_NODEV - HPUX_ERROR_OFFSET;
+ break;
+ };
+
+ return (error ? (error+HPUX_ERROR_OFFSET) : 0);
+}
+
+/*
+ ASystemGainType = ASGTPlay, ASGTRecord, ASGTMonitor
+ AChType = ACTMono, ACTLeft, ACTRight
+*/
+
+int Mixer_HPUX::writeVolumeToHW( int devnum, Volume& vol )
+{
+ long Gain;
+ long error = 0;
+ int vl = vol.getVolume(Volume::LEFT);
+ int vr = vol.getVolume(Volume::RIGHT);
+
+ switch (devnum) {
+ case ID_OUT_INT_SPEAKER: /* AODTMonoIntSpeaker */
+printf("WRITE - Devnum: %d, Left: %d, Right: %d\n", devnum, vl, vr);
+ Gain = vl; // only left Volume
+ Gain = (Gain*GAIN_OUT_DIFF) / 255 - GAIN_OUT_MIN;
+ ASetSystemChannelGain(audio, ASGTPlay, ACTMono, (AGainDB) Gain, &error );
+ break;
+
+ case ID_IN_MICROPHONE: /* AISTMonoMicrophone */
+ Gain = vl; // only left Volume
+ Gain = (Gain*GAIN_IN_DIFF) / 255 - GAIN_IN_MIN;
+ ASetSystemChannelGain(audio, ASGTRecord, ACTMono, (AGainDB) Gain, &error );
+ break;
+
+ case ID_IN_AUX: /* AISTLeftAuxiliary, AISTRightAuxiliary */
+ Gain = (vl*GAIN_IN_DIFF) / 255 - GAIN_IN_MIN;
+ ASetSystemChannelGain(audio, ASGTRecord, ACTLeft, (AGainDB) Gain, &error );
+ Gain = (vr*GAIN_IN_DIFF) / 255 - GAIN_IN_MIN;
+ ASetSystemChannelGain(audio, ASGTRecord, ACTRight, (AGainDB) Gain, &error );
+ break;
+
+ default:
+ error = Mixer::ERR_NODEV - HPUX_ERROR_OFFSET;
+ break;
+ };
+ return (error ? (error+HPUX_ERROR_OFFSET) : 0);
+}
+
+
+QString Mixer_HPUX::errorText(int mixer_error)
+{
+ QString l_s_errmsg;
+ if (mixer_error >= HPUX_ERROR_OFFSET) {
+ char errorstr[200];
+ AGetErrorText(audio, (AError) (mixer_error-HPUX_ERROR_OFFSET),
+ errorstr, sizeof(errorstr));
+ printf("kmix: %s: %s\n",mixerName().data(), errorstr);
+ l_s_errmsg = errorstr;
+ } else
+ switch (mixer_error)
+ {
+ case Mixer::ERR_OPEN:
+ // should use i18n...
+ l_s_errmsg = "kmix: HP-UX Alib-Mixer cannot be found.\n" \
+ "Please check that you have:\n" \
+ " 1. Installed the libAlib package and\n" \
+ " 2. started the Aserver program from the /opt/audio/bin directory\n";
+ break;
+ default:
+ l_s_errmsg = Mixer_Backend::errorText(mixer_error);
+ break;
+ }
+ return l_s_errmsg;
+}
+
+QString HPUX_getDriverName() {
+ return "HPUX";
+}
+
diff --git a/kmix/mixer_hpux.h b/kmix/mixer_hpux.h
new file mode 100644
index 00000000..bdc0d3d7
--- /dev/null
+++ b/kmix/mixer_hpux.h
@@ -0,0 +1,36 @@
+#ifndef MIXER_HPUX_H
+#define MIXER_HPUX_H
+
+#define DEFAULT_MIXER "HP-UX Mixer"
+#ifdef HAVE_ALIB_H
+#include <Alib.h>
+#define HPUX_MIXER
+#endif
+
+#include "mixer_backend.h"
+
+class Mixer_HPUX : public Mixer_Backend
+{
+public:
+ Mixer_HPUX(int devnum);
+ virtual ~Mixer_HPUX();
+
+ virtual QString errorText(int mixer_error);
+
+ virtual int readVolumeFromHW( int devnum, Volume &vol );
+ virtual int writeVolumeToHW( int devnum, Volume &vol );
+
+protected:
+ virtual bool setRecsrcHW( int devnum, bool on = true );
+ virtual bool isRecsrcHW( int devnum );
+
+ virtual int open();
+ virtual int close();
+
+ Audio *audio;
+ unsigned int stereodevs,devmask, recmask, MaxVolume, i_recsrc;
+
+
+};
+
+#endif
diff --git a/kmix/mixer_irix.cpp b/kmix/mixer_irix.cpp
new file mode 100644
index 00000000..9c88b6f4
--- /dev/null
+++ b/kmix/mixer_irix.cpp
@@ -0,0 +1,133 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2000 Christian Esken
+ * esken@kde.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mixer_irix.h"
+
+Mixer_Backend* IRIX_getMixer(int devnum)
+{
+ Mixer_Backend *l_mixer;
+ l_mixer = new Mixer_IRIX( devnum);
+ l_mixer->init(devnum);
+ return l_mixer;
+}
+
+
+
+Mixer_IRIX::Mixer_IRIX(int devnum) : Mixer_Backend(devnum)
+{
+ close();
+}
+
+int Mixer_IRIX::open()
+{
+ // Create config
+ m_config = ALnewconfig();
+ if (m_config == (ALconfig)0) {
+ cerr << "OpenAudioDevice(): ALnewconfig() failed\n";
+ return Mixer::ERR_OPEN;
+ }
+ // Open audio device
+ m_port = ALopenport("XVDOPlayer", "w", m_config);
+ if (m_port == (ALport)0) {
+ return Mixer::ERR_OPEN;
+ }
+ else {
+ // Mixer is open. Now define properties
+ devmask = 1+128+2048;
+ recmask = 128;
+ i_recsrc = 128;
+ stereodevs = 1+128+2048;
+ MaxVolume = 255;
+
+ i_s_mixer_name = "HPUX Audio Mixer";
+
+ isOpen = true;
+ return 0;
+ }
+}
+
+int Mixer_IRIX::close()
+{
+ m_isOpen = false;
+ ALfreeconfig(m_config);
+ ALcloseport(m_port);
+ m_mixDevices.clear();
+ return 0;
+}
+
+int Mixer_IRIX::readVolumeFromHW( int devnum, int *VolLeft, int *VolRight )
+{
+ long in_buf[4];
+ switch( devnum() ) {
+ case 0: // Speaker Output
+ in_buf[0] = AL_RIGHT_SPEAKER_GAIN;
+ in_buf[2] = AL_LEFT_SPEAKER_GAIN;
+ break;
+ case 7: // Microphone Input (actually selectable).
+ in_buf[0] = AL_RIGHT_INPUT_ATTEN;
+ in_buf[2] = AL_LEFT_INPUT_ATTEN;
+ break;
+ case 11: // Record monitor
+ in_buf[0] = AL_RIGHT_MONITOR_ATTEN;
+ in_buf[2] = AL_LEFT_MONITOR_ATTEN;
+ break;
+ default:
+ printf("Unknown device %d\n", MixPtr->num() );
+ }
+ ALgetparams(AL_DEFAULT_DEVICE, in_buf, 4);
+ *VolRight = in_buf[1]*100/255;
+ *VolLeft = in_buf[3]*100/255;
+
+ return 0;
+}
+
+int Mixer_IRIX::writeVolumeToHW( int devnum, int volLeft, int volRight )
+{
+ // Set volume (right&left)
+ long out_buf[4] =
+ {
+ 0, volRight,
+ 0, volLeft
+ };
+ switch( mixdevice->num() ) {
+ case 0: // Speaker
+ out_buf[0] = AL_RIGHT_SPEAKER_GAIN;
+ out_buf[2] = AL_LEFT_SPEAKER_GAIN;
+ break;
+ case 7: // Microphone (Input)
+ out_buf[0] = AL_RIGHT_INPUT_ATTEN;
+ out_buf[2] = AL_LEFT_INPUT_ATTEN;
+ break;
+ case 11: // Record monitor
+ out_buf[0] = AL_RIGHT_MONITOR_ATTEN;
+ out_buf[2] = AL_LEFT_MONITOR_ATTEN;
+ break;
+ }
+ ALsetparams(AL_DEFAULT_DEVICE, out_buf, 4);
+
+ return 0;
+}
+
+QString IRIX_getDriverName() {
+ return "IRIX";
+}
+
diff --git a/kmix/mixer_irix.h b/kmix/mixer_irix.h
new file mode 100644
index 00000000..decf143c
--- /dev/null
+++ b/kmix/mixer_irix.h
@@ -0,0 +1,28 @@
+#ifndef MIXER_IRIX_H
+#define MIXER_IRIX_H
+
+#define _LANGUAGE_C_PLUS_PLUS
+#include <dmedia/audio.h>
+
+#include "mixer_backend.h"
+
+class Mixer_IRIX : public Mixer_Backend
+{
+public:
+ Mixer_IRIX(int devnum);
+ virtual ~Mixer_IRIX();
+
+ virtual void setRecsrc(unsigned int newRecsrc);
+ virtual int readVolumeFromHW( int devnum, int *VolLeft, int *VolRight );
+ virtual int writeVolumeToHW( int devnum, int volLeft, int volRight );
+
+protected:
+ virtual void setDevNumName_I(int devnum);
+ virtual int open();
+ virtual int close();
+
+ ALport m_port;
+ ALconfig m_config;
+};
+
+#endif
diff --git a/kmix/mixer_none.cpp b/kmix/mixer_none.cpp
new file mode 100644
index 00000000..41e3d9b3
--- /dev/null
+++ b/kmix/mixer_none.cpp
@@ -0,0 +1,78 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2000 Christian Esken
+ * esken@kde.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mixer_none.h"
+
+// This static method must be implemented (as fallback)
+Mixer_Backend* Mixer::getMixer(int devnum)
+{
+ Mixer_Backend *l_mixer;
+ l_mixer = new Mixer_None( devnum);
+ return l_mixer;
+}
+
+Mixer_None::Mixer_None(int devnum) : Mixer_Backend( device )
+{
+}
+
+Mixer_None::~Mixer_None()
+{
+ close();
+}
+
+int Mixer_None::open()
+{
+ //i_s_mixer_name = "No mixer";
+ return Mixer::ERR_NOTSUPP;
+}
+
+int Mixer_None::close()
+{
+ m_isOpen = false;
+ m_mixDevices.clear();
+ return Mixer::ERR_NOTSUPP;
+}
+
+int Mixer_None::readVolumeFromHW( int , Volume &vol )
+{
+ return Mixer::ERR_NOTSUPP;
+}
+
+int Mixer_None::writeVolumeToHW( int , Volume &vol )
+{
+ return Mixer::ERR_NOTSUPP;
+}
+
+bool Mixer_None::setRecsrcHW( int devnum, bool on)
+{
+ return false;
+}
+
+bool Mixer_None::isRecsrcHW( int devnum )
+{
+ return false;
+}
+
+QString NONE_getDriverName() {
+ return "None";
+}
+
diff --git a/kmix/mixer_none.h b/kmix/mixer_none.h
new file mode 100644
index 00000000..35d5dc93
--- /dev/null
+++ b/kmix/mixer_none.h
@@ -0,0 +1,22 @@
+#ifndef MIXER_NONE_H
+#define MIXER_NONE_H
+
+#include "mixer_backend.h"
+
+class Mixer_None : public Mixer_Backend
+{
+public:
+ Mixer_None(int devnum);
+ virtual ~Mixer_None();
+
+ virtual int readVolumeFromHW( int devnum, Volume& vol );
+ virtual int writeVolumeToHW( int devnum, Volume& vol );
+ virtual bool setRecsrcHW( int devnum, bool on);
+ virtual bool isRecsrcHW( int devnum );
+
+protected:
+ virtual int open();
+ virtual int close();
+};
+
+#endif
diff --git a/kmix/mixer_oss.cpp b/kmix/mixer_oss.cpp
new file mode 100644
index 00000000..6991c1aa
--- /dev/null
+++ b/kmix/mixer_oss.cpp
@@ -0,0 +1,330 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ * Copyright (C) 1996-2000 Christian Esken
+ * esken@kde.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+// Since we're guaranteed an OSS setup here, let's make life easier
+#if !defined(__NetBSD__) && !defined(__OpenBSD__)
+ #include <sys/soundcard.h>
+#else
+ #include <soundcard.h>
+#endif
+
+#include "mixer_oss.h"
+#include <klocale.h>
+
+/*
+ I am using a fixed MAX_MIXDEVS #define here.
+ People might argue, that I should rather use the SOUND_MIXER_NRDEVICES
+ #define used by OSS. But using this #define is not good, because it is
+ evaluated during compile time. Compiling on one platform and running
+ on another with another version of OSS with a different value of
+ SOUND_MIXER_NRDEVICES is very bad. Because of this, usage of
+ SOUND_MIXER_NRDEVICES should be discouraged.
+
+ The #define below is only there for internal reasons.
+ In other words: Don't play around with this value
+ */
+#define MAX_MIXDEVS 32
+
+const char* MixerDevNames[32]={
+ I18N_NOOP("Volume"), I18N_NOOP("Bass"), I18N_NOOP("Treble"),
+ I18N_NOOP("Synth"), I18N_NOOP("Pcm"), I18N_NOOP("Speaker"),
+ I18N_NOOP("Line"), I18N_NOOP("Microphone"), I18N_NOOP("CD"),
+ I18N_NOOP("Mix"), I18N_NOOP("Pcm2"), I18N_NOOP("RecMon"),
+ I18N_NOOP("IGain"), I18N_NOOP("OGain"), I18N_NOOP("Line1"),
+ I18N_NOOP("Line2"), I18N_NOOP("Line3"), I18N_NOOP("Digital1"),
+ I18N_NOOP("Digital2"), I18N_NOOP("Digital3"), I18N_NOOP("PhoneIn"),
+ I18N_NOOP("PhoneOut"), I18N_NOOP("Video"), I18N_NOOP("Radio"),
+ I18N_NOOP("Monitor"), I18N_NOOP("3D-depth"), I18N_NOOP("3D-center"),
+ I18N_NOOP("unknown"), I18N_NOOP("unknown"), I18N_NOOP("unknown"),
+ I18N_NOOP("unknown") , I18N_NOOP("unused") };
+
+const MixDevice::ChannelType MixerChannelTypes[32] = {
+ MixDevice::VOLUME, MixDevice::BASS, MixDevice::TREBLE, MixDevice::MIDI,
+ MixDevice::AUDIO, MixDevice::EXTERNAL, MixDevice::EXTERNAL, MixDevice::MICROPHONE,
+ MixDevice::CD, MixDevice::VOLUME, MixDevice::AUDIO, MixDevice::RECMONITOR,
+ MixDevice::VOLUME, MixDevice::RECMONITOR, MixDevice::EXTERNAL, MixDevice::EXTERNAL,
+ MixDevice::EXTERNAL, MixDevice::AUDIO, MixDevice::AUDIO, MixDevice::AUDIO,
+ MixDevice::EXTERNAL, MixDevice::EXTERNAL, MixDevice::EXTERNAL, MixDevice::EXTERNAL,
+ MixDevice::EXTERNAL, MixDevice::VOLUME, MixDevice::VOLUME, MixDevice::UNKNOWN,
+ MixDevice::UNKNOWN, MixDevice::UNKNOWN, MixDevice::UNKNOWN, MixDevice::UNKNOWN };
+
+Mixer_Backend* OSS_getMixer( int device )
+{
+ Mixer_Backend *l_mixer;
+ l_mixer = new Mixer_OSS( device );
+ return l_mixer;
+}
+
+Mixer_OSS::Mixer_OSS(int device) : Mixer_Backend(device)
+{
+ if( device == -1 ) m_devnum = 0;
+}
+
+Mixer_OSS::~Mixer_OSS()
+{
+ close();
+}
+
+int Mixer_OSS::open()
+{
+ if ((m_fd= ::open( deviceName( m_devnum ).latin1(), O_RDWR)) < 0)
+ {
+ if ( errno == EACCES )
+ return Mixer::ERR_PERM;
+ else {
+ if ((m_fd= ::open( deviceNameDevfs( m_devnum ).latin1(),
+ O_RDWR)) < 0)
+ {
+ if ( errno == EACCES )
+ return Mixer::ERR_PERM;
+ else
+ return Mixer::ERR_OPEN;
+ }
+ }
+ }
+
+ int devmask, recmask, i_recsrc, stereodevs;
+ // Mixer is open. Now define properties
+ if (ioctl(m_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
+ return Mixer::ERR_READ;
+ if (ioctl(m_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
+ return Mixer::ERR_READ;
+ if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1)
+ return Mixer::ERR_READ;
+ if (ioctl(m_fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs) == -1)
+ return Mixer::ERR_READ;
+ if (!devmask)
+ return Mixer::ERR_NODEV;
+ int maxVolume =100;
+
+ if( m_mixDevices.isEmpty() )
+ {
+ int idx = 0;
+ while( devmask && idx < MAX_MIXDEVS )
+ {
+ if( devmask & ( 1 << idx ) ) // device active?
+ {
+ Volume vol( stereodevs & ( 1 << idx ) ? 2 : 1, maxVolume);
+ readVolumeFromHW( idx, vol );
+ MixDevice* md =
+ new MixDevice( idx, vol, recmask & ( 1 << idx ), true,
+ i18n(MixerDevNames[idx]),
+ MixerChannelTypes[idx]);
+ md->setRecSource( isRecsrcHW( idx ) );
+ m_mixDevices.append( md );
+ }
+ idx++;
+ }
+ }
+ else
+ for( unsigned int idx = 0; idx < m_mixDevices.count(); idx++ )
+ {
+ MixDevice* md = m_mixDevices.at( idx );
+ if( !md )
+ return Mixer::ERR_INCOMPATIBLESET;
+ writeVolumeToHW( idx, md->getVolume() );
+ }
+
+#if !defined(__FreeBSD__)
+ struct mixer_info l_mix_info;
+ if (ioctl(m_fd, SOUND_MIXER_INFO, &l_mix_info) != -1)
+ {
+ m_mixerName = l_mix_info.name;
+ }
+ else
+#endif
+
+ m_mixerName = "OSS Audio Mixer";
+
+ m_isOpen = true;
+ return 0;
+}
+
+int Mixer_OSS::close()
+{
+ m_isOpen = false;
+ int l_i_ret = ::close(m_fd);
+ m_mixDevices.clear();
+ return l_i_ret;
+}
+
+
+QString Mixer_OSS::deviceName(int devnum)
+{
+ switch (devnum) {
+ case 0:
+ return QString("/dev/mixer");
+ break;
+
+ default:
+ QString devname("/dev/mixer");
+ devname += ('0'+devnum);
+ return devname;
+ }
+}
+
+QString Mixer_OSS::deviceNameDevfs(int devnum)
+{
+ switch (devnum) {
+ case 0:
+ return QString("/dev/sound/mixer");
+ break;
+
+ default:
+ QString devname("/dev/sound/mixer");
+ devname += ('0'+devnum);
+ return devname;
+ }
+}
+
+QString Mixer_OSS::errorText(int mixer_error)
+{
+ QString l_s_errmsg;
+ switch (mixer_error)
+ {
+ case Mixer::ERR_PERM:
+ l_s_errmsg = i18n("kmix: You do not have permission to access the mixer device.\n" \
+ "Login as root and do a 'chmod a+rw /dev/mixer*' to allow the access.");
+ break;
+ case Mixer::ERR_OPEN:
+ l_s_errmsg = i18n("kmix: Mixer cannot be found.\n" \
+ "Please check that the soundcard is installed and the\n" \
+ "soundcard driver is loaded.\n" \
+ "On Linux you might need to use 'insmod' to load the driver.\n" \
+ "Use 'soundon' when using commercial OSS.");
+ break;
+ default:
+ l_s_errmsg = Mixer_Backend::errorText(mixer_error);
+ }
+ return l_s_errmsg;
+}
+
+
+bool Mixer_OSS::setRecsrcHW( int devnum, bool on )
+{
+ int i_recsrc, oldrecsrc;
+ if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1)
+ errormsg(Mixer::ERR_READ);
+
+ oldrecsrc = i_recsrc = on ?
+ (i_recsrc | (1 << devnum )) :
+ (i_recsrc & ~(1 << devnum ));
+
+ // Change status of record source(s)
+ if (ioctl(m_fd, SOUND_MIXER_WRITE_RECSRC, &i_recsrc) == -1)
+ errormsg (Mixer::ERR_WRITE);
+ // Re-read status of record source(s). Just in case, OSS does not like
+ // my settings. And with this line mix->recsrc gets its new value. :-)
+ if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1)
+ errormsg(Mixer::ERR_READ);
+
+ /* The following if {} patch was submitted by Tim McCormick <tim@pcbsd.org>. */
+ /* Comment (cesken): This patch fixes an issue with mutual exclusive recording sources.
+ Actually the kernel soundcard driver *could* "do the right thing" by examining the change
+ (old-recsrc XOR new-recsrc), and knowing which sources are mutual exclusive.
+ The OSS v3 API docs indicate that the behaviour is undefined for this case, and it is not
+ clearly documented how and whether SOUND_MIXER_CAP_EXCL_INPUT is evaluated in the OSS driver.
+ Evaluating that in the application (KMix) could help, but the patch will work independent
+ on whether SOUND_MIXER_CAP_EXCL_INPUT ist set or not.
+
+ In any case this patch is a superb workaround for a shortcoming of the OSS v3 API.
+ */
+ // If the record source is supposed to be on, but wasn't set, explicitly
+ // set the record source. Not all cards support multiple record sources.
+ // As a result, we also need to do the read & write again.
+ if (((i_recsrc & ( 1<<devnum)) == 0) && on)
+ {
+ // Setting the new device failed => Try to enable it *exclusively*
+ oldrecsrc = i_recsrc = 1 << devnum;
+ if (ioctl(m_fd, SOUND_MIXER_WRITE_RECSRC, &i_recsrc) == -1)
+ errormsg (Mixer::ERR_WRITE);
+ if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1)
+ errormsg(Mixer::ERR_READ);
+ }
+
+ // PORTING: Hint: Do not forget to set i_recsrc to the new valid
+ // record source mask.
+
+ return i_recsrc == oldrecsrc;
+}
+
+bool Mixer_OSS::isRecsrcHW( int devnum )
+{
+ bool isRecsrc = false;
+ int recsrcMask;
+ if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &recsrcMask) == -1)
+ errormsg(Mixer::ERR_READ);
+ else {
+ // test if device bit is set in record bit mask
+ isRecsrc = ( (recsrcMask & ( 1<<devnum)) != 0 );
+ }
+ return isRecsrc;
+}
+
+int Mixer_OSS::readVolumeFromHW( int devnum, Volume &vol )
+{
+ if( vol.isMuted() ) return 0; // Don't alter volume when muted
+
+ int volume;
+ if (ioctl(m_fd, MIXER_READ( devnum ), &volume) == -1)
+ {
+ /* Oops, can't read mixer */
+ return(Mixer::ERR_READ);
+ }
+ else
+ {
+ vol.setVolume( Volume::LEFT, (volume & 0x7f));
+ if( vol.count() > 1 )
+ vol.setVolume( Volume::RIGHT, ((volume>>8) & 0x7f));
+ //fprintf(stderr, "Mixer_OSS::readVolumeFromHW(%i,vol) set vol %i %i\n", devnum, vol.getVolume(Volume::LEFT), vol.getVolume(Volume::RIGHT));
+ return 0;
+ }
+}
+
+
+
+int Mixer_OSS::writeVolumeToHW( int devnum, Volume &vol )
+{
+ int volume;
+ if( vol.isMuted() ) volume = 0;
+ else
+ if ( vol.count() > 1 )
+ volume = (vol[ Volume::LEFT ]) + ((vol[ Volume::RIGHT ])<<8);
+ else
+ volume = vol[ Volume::LEFT ];
+
+ if (ioctl(m_fd, MIXER_WRITE( devnum ), &volume) == -1)
+ return Mixer::ERR_WRITE;
+
+ return 0;
+}
+
+QString OSS_getDriverName() {
+ return "OSS";
+}
+
diff --git a/kmix/mixer_oss.h b/kmix/mixer_oss.h
new file mode 100644
index 00000000..592802ea
--- /dev/null
+++ b/kmix/mixer_oss.h
@@ -0,0 +1,33 @@
+//-*-C++-*-
+
+#ifndef MIXER_OSS_H
+#define MIXER_OSS_H
+
+#include <qstring.h>
+
+#include "mixer_backend.h"
+
+class Mixer_OSS : public Mixer_Backend
+{
+public:
+ Mixer_OSS(int device = -1);
+ virtual ~Mixer_OSS();
+
+ virtual QString errorText(int mixer_error);
+ virtual int readVolumeFromHW( int devnum, Volume &vol );
+ virtual int writeVolumeToHW( int devnum, Volume &vol );
+
+protected:
+ virtual bool setRecsrcHW( int devnum, bool on = true );
+ virtual bool isRecsrcHW( int devnum );
+
+ virtual int open();
+ virtual int close();
+
+ virtual QString deviceName( int );
+ virtual QString deviceNameDevfs( int );
+ int m_fd;
+ QString m_deviceName;
+};
+
+#endif
diff --git a/kmix/mixer_oss4.cpp b/kmix/mixer_oss4.cpp
new file mode 100644
index 00000000..dccea0be
--- /dev/null
+++ b/kmix/mixer_oss4.cpp
@@ -0,0 +1,670 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ * Copyright (C) 1996-2000 Christian Esken
+ * esken@kde.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+//OSS4 mixer backend for KMix by Yoper Team released under GPL v2 or later
+
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <qregexp.h>
+#include <kdebug.h>
+
+// Since we're guaranteed an OSS setup here, let's make life easier
+#if !defined(__NetBSD__) && !defined(__OpenBSD__)
+#include <sys/soundcard.h>
+#else
+#include <soundcard.h>
+#endif
+
+#include "mixer_oss4.h"
+#include <klocale.h>
+
+Mixer_Backend* OSS4_getMixer(int device)
+{
+ Mixer_Backend *l_mixer;
+ l_mixer = new Mixer_OSS4(device);
+ return l_mixer;
+}
+
+Mixer_OSS4::Mixer_OSS4(int device) : Mixer_Backend(device)
+{
+ if ( device == -1 ) m_devnum = 0;
+ m_numExtensions = 0;
+}
+
+Mixer_OSS4::~Mixer_OSS4()
+{
+ close();
+}
+
+bool Mixer_OSS4::setRecsrcHW(int ctrlnum, bool on)
+{
+ return true;
+}
+
+//dummy implementation only
+bool Mixer_OSS4::isRecsrcHW(int ctrlnum)
+{
+ return false;
+}
+
+//classifies mixexts according to their name, last classification wins
+MixDevice::ChannelType Mixer_OSS4::classifyAndRename(QString &name, int flags)
+{
+ MixDevice::ChannelType cType = MixDevice::UNKNOWN;
+ QStringList classes = QStringList::split ( QRegExp ( "[-,.]" ), name );
+
+
+ if ( flags & MIXF_PCMVOL ||
+ flags & MIXF_MONVOL ||
+ flags & MIXF_MAINVOL )
+ {
+ cType = MixDevice::VOLUME;
+ }
+
+ for ( QStringList::Iterator it = classes.begin(); it != classes.end(); ++it )
+ {
+ if ( *it == "line" )
+ {
+ *it = "Line";
+ cType = MixDevice::EXTERNAL;
+
+ } else
+ if ( *it == "mic" )
+ {
+ *it = "Microphone";
+ cType = MixDevice::MICROPHONE;
+ } else
+ if ( *it == "vol" )
+ {
+ *it = "Volume";
+ cType = MixDevice::VOLUME;
+ } else
+ if ( *it == "surr" )
+ {
+ *it = "Surround";
+ cType = MixDevice::SURROUND;
+ } else
+ if ( *it == "bass" )
+ {
+ *it = "Bass";
+ cType = MixDevice::BASS;
+ } else
+ if ( *it == "treble" )
+ {
+ *it = "Treble";
+ cType = MixDevice::TREBLE;
+ } else
+ if ( (*it).startsWith ( "pcm" ) )
+ {
+ (*it).replace ( "pcm","PCM" );
+ cType = MixDevice::AUDIO;
+ } else
+ if ( *it == "src" )
+ {
+ *it = "Source";
+ } else
+ if ( *it == "rec" )
+ {
+ *it = "Recording";
+ } else
+ if ( *it == "cd" )
+ {
+ *it = (*it).upper();
+ cType = MixDevice::CD;
+ }
+ if ( (*it).startsWith("vmix") )
+ {
+ (*it).replace("vmix","Virtual Mixer");
+ cType = MixDevice::VOLUME;
+ } else
+ if ( (*it).endsWith("vol") )
+ {
+ QChar &ref = (*it).ref(0);
+ ref = ref.upper();
+ cType = MixDevice::VOLUME;
+ }
+ else
+ {
+ QChar &ref = (*it).ref(0);
+ ref = ref.upper();
+ }
+ }
+ name = classes.join( " ");
+ return cType;
+}
+
+int Mixer_OSS4::open()
+{
+ if ( (m_fd= ::open("/dev/mixer", O_RDWR)) < 0 )
+ {
+ if ( errno == EACCES )
+ return Mixer::ERR_PERM;
+ else
+ return Mixer::ERR_OPEN;
+ }
+
+ if (wrapIoctl( ioctl (m_fd, OSS_GETVERSION, &m_ossVersion) ) < 0)
+ {
+ return Mixer::ERR_READ;
+ }
+ if (m_ossVersion < 0x040000)
+ {
+ return Mixer::ERR_NOTSUPP;
+ }
+
+
+ wrapIoctl( ioctl (m_fd, SNDCTL_MIX_NRMIX, &m_numMixers) );
+
+ if ( m_mixDevices.isEmpty() )
+ {
+ if ( m_devnum >= 0 && m_devnum < m_numMixers )
+ {
+ m_numExtensions = m_devnum;
+ bool masterChosen = false;
+ oss_mixext ext;
+ ext.dev = m_devnum;
+
+ if ( wrapIoctl( ioctl (m_fd, SNDCTL_MIX_NREXT, &m_numExtensions) ) < 0 )
+ {
+ //TODO: more specific error handling here
+ if ( errno == ENODEV ) return Mixer::ERR_NODEV;
+ return Mixer::ERR_READ;
+ }
+
+ if( m_numExtensions == 0 )
+ {
+ return Mixer::ERR_NODEV;
+ }
+
+ ext.ctrl = 0;
+
+ //read MIXT_DEVROOT, return Mixer::NODEV on error
+ if ( wrapIoctl ( ioctl( m_fd, SNDCTL_MIX_EXTINFO, &ext) ) < 0 )
+ {
+ return Mixer::ERR_NODEV;
+ }
+
+ oss_mixext_root *root = (oss_mixext_root *) ext.data;
+ m_mixerName = root->name;
+
+ for ( int i = 1; i < m_numExtensions; i++ )
+ {
+ bool isCapture = false;
+
+ ext.dev = m_devnum;
+ ext.ctrl = i;
+
+ //wrapIoctl handles reinitialization, cancel loading on EIDRM
+ if ( wrapIoctl( ioctl( m_fd, SNDCTL_MIX_EXTINFO, &ext) ) == EIDRM )
+ {
+ return 0;
+ }
+
+ QString name = ext.extname;
+
+ //skip vmix volume controls and mute controls
+ if ( (name.find("vmix") > -1 && name.find( "pcm") > -1) ||
+ name.find("mute") > -1
+#ifdef MIXT_MUTE
+ || (ext.type == MIXT_MUTE)
+#endif
+ )
+ {
+ continue;
+ }
+
+ //fix for old legacy names, according to Hannu's suggestions
+ if ( name.contains('_') )
+ {
+ name = name.section('_',1,1).lower();
+ }
+
+ if ( ext.flags & MIXF_RECVOL || ext.flags & MIXF_MONVOL || name.find(".in") > -1 )
+ {
+ isCapture = true;
+ }
+
+ Volume::ChannelMask chMask = Volume::MNONE;
+
+ MixDevice::ChannelType cType = classifyAndRename(name, ext.flags);
+
+ if ( ext.type == MIXT_STEREOSLIDER16 ||
+ ext.type == MIXT_STEREOSLIDER ||
+ ext.type == MIXT_MONOSLIDER16 ||
+ ext.type == MIXT_MONOSLIDER ||
+ ext.type == MIXT_SLIDER
+ )
+ {
+ if ( ext.type == MIXT_STEREOSLIDER16 ||
+ ext.type == MIXT_STEREOSLIDER
+ )
+ {
+ if ( isCapture )
+ {
+ chMask = Volume::ChannelMask(Volume::MLEFT|Volume::MRIGHT);
+ }
+ else
+ {
+ chMask = Volume::ChannelMask(Volume::MLEFT|Volume::MRIGHT );
+ }
+ }
+ else
+ {
+ if ( isCapture )
+ {
+ chMask = Volume::MLEFT;
+ }
+ else
+ {
+ chMask = Volume::MLEFT;
+ }
+ }
+
+ Volume vol (chMask, ext.maxvalue, ext.minvalue, isCapture);
+
+ MixDevice* md = new MixDevice(i, vol, isCapture, true,
+ name, cType, MixDevice::SLIDER);
+
+ m_mixDevices.append(md);
+
+ if ( !masterChosen && ext.flags & MIXF_MAINVOL )
+ {
+ m_recommendedMaster = md;
+ masterChosen = true;
+ }
+ }
+ else if ( ext.type == MIXT_ONOFF )
+ {
+ Volume vol;
+ vol.setMuted(true);
+ MixDevice* md = new MixDevice(i, vol, false, true, name, MixDevice::VOLUME, MixDevice::SWITCH);
+ m_mixDevices.append(md);
+ }
+ else if ( ext.type == MIXT_ENUM )
+ {
+ oss_mixer_enuminfo ei;
+ ei.dev = m_devnum;
+ ei.ctrl = i;
+
+ if ( wrapIoctl( ioctl (m_fd, SNDCTL_MIX_ENUMINFO, &ei) ) != -1 )
+ {
+ Volume vol(Volume::MLEFT, ext.maxvalue, ext.minvalue, false);
+
+ MixDevice* md = new MixDevice (i, vol, false, false,
+ name, MixDevice::UNKNOWN,
+ MixDevice::ENUM);
+
+ QPtrList<QString> &enumValuesRef = md->enumValues();
+ QString thisElement;
+
+ for ( int i = 0; i < ei.nvalues; i++ )
+ {
+ thisElement = &ei.strings[ ei.strindex[i] ];
+
+ if ( thisElement.isEmpty() )
+ {
+ thisElement = QString::number(i);
+ }
+ enumValuesRef.append( new QString(thisElement) );
+ }
+ m_mixDevices.append(md);
+ }
+ }
+
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ m_isOpen = true;
+ return 0;
+}
+
+int Mixer_OSS4::close()
+{
+ m_isOpen = false;
+ int l_i_ret = ::close(m_fd);
+ m_mixDevices.clear();
+ return l_i_ret;
+}
+
+QString Mixer_OSS4::errorText(int mixer_error)
+{
+ QString l_s_errmsg;
+
+ switch( mixer_error )
+ {
+ case Mixer::ERR_PERM:
+ l_s_errmsg = i18n("kmix: You do not have permission to access the mixer device.\n" \
+ "Login as root and do a 'chmod a+rw /dev/mixer*' to allow the access.");
+ break;
+ case Mixer::ERR_OPEN:
+ l_s_errmsg = i18n("kmix: Mixer cannot be found.\n" \
+ "Please check that the soundcard is installed and the\n" \
+ "soundcard driver is loaded.\n" \
+ "On Linux you might need to use 'insmod' to load the driver.\n" \
+ "Use 'soundon' when using OSS4 from 4front.");
+ break;
+ case Mixer::ERR_NOTSUPP:
+ l_s_errmsg = i18n("kmix expected an OSSv4 mixer module,\n" \
+ "but instead found an older version.");
+ break;
+ default:
+ l_s_errmsg = Mixer_Backend::errorText(mixer_error);
+ }
+ return l_s_errmsg;
+}
+
+int Mixer_OSS4::readVolumeFromHW(int ctrlnum, Volume &vol)
+{
+
+ oss_mixext extinfo;
+ oss_mixer_value mv;
+
+ extinfo.dev = m_devnum;
+ extinfo.ctrl = ctrlnum;
+
+ if ( wrapIoctl( ioctl(m_fd, SNDCTL_MIX_EXTINFO, &extinfo) ) < 0 )
+ {
+ //TODO: more specific error handling
+ return Mixer::ERR_READ;
+ }
+
+ mv.dev = extinfo.dev;
+ mv.ctrl = extinfo.ctrl;
+ mv.timestamp = extinfo.timestamp;
+
+ if ( wrapIoctl ( ioctl (m_fd, SNDCTL_MIX_READ, &mv) ) < 0 )
+ {
+ /* Oops, can't read mixer */
+ return Mixer::ERR_READ;
+ }
+ else
+ {
+ if ( vol.isMuted() && extinfo.type != MIXT_ONOFF )
+ {
+ return 0;
+ }
+
+ if ( vol.isCapture() )
+ {
+ switch ( extinfo.type )
+ {
+ case MIXT_ONOFF:
+ vol.setMuted(mv.value != extinfo.maxvalue);
+ break;
+
+ case MIXT_MONOSLIDER:
+ vol.setVolume(Volume::LEFT, mv.value & 0xff);
+ break;
+
+ case MIXT_STEREOSLIDER:
+ vol.setVolume(Volume::LEFT, mv.value & 0xff);
+ vol.setVolume(Volume::RIGHT, ( mv.value >> 8 ) & 0xff);
+ break;
+
+ case MIXT_SLIDER:
+ vol.setVolume(Volume::LEFT, mv.value);
+ break;
+
+ case MIXT_MONOSLIDER16:
+ vol.setVolume(Volume::LEFT, mv.value & 0xffff);
+ break;
+
+ case MIXT_STEREOSLIDER16:
+ vol.setVolume(Volume::LEFT, mv.value & 0xffff);
+ vol.setVolume(Volume::RIGHT, ( mv.value >> 16 ) & 0xffff);
+ break;
+ }
+ }
+ else
+ {
+ switch( extinfo.type )
+ {
+ case MIXT_ONOFF:
+ vol.setMuted(mv.value != extinfo.maxvalue);
+ break;
+ case MIXT_MONOSLIDER:
+ vol.setVolume(Volume::LEFT, mv.value & 0xff);
+ break;
+
+ case MIXT_STEREOSLIDER:
+ vol.setVolume(Volume::LEFT, mv.value & 0xff);
+ vol.setVolume(Volume::RIGHT, ( mv.value >> 8 ) & 0xff);
+ break;
+
+ case MIXT_SLIDER:
+ vol.setVolume(Volume::LEFT, mv.value);
+ break;
+
+ case MIXT_MONOSLIDER16:
+ vol.setVolume(Volume::LEFT, mv.value & 0xffff);
+ break;
+
+ case MIXT_STEREOSLIDER16:
+ vol.setVolume(Volume::LEFT, mv.value & 0xffff);
+ vol.setVolume(Volume::RIGHT, ( mv.value >> 16 ) & 0xffff);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+int Mixer_OSS4::writeVolumeToHW(int ctrlnum, Volume &vol)
+{
+ int volume = 0;
+
+ oss_mixext extinfo;
+ oss_mixer_value mv;
+
+ extinfo.dev = m_devnum;
+ extinfo.ctrl = ctrlnum;
+
+ if ( wrapIoctl( ioctl(m_fd, SNDCTL_MIX_EXTINFO, &extinfo) ) < 0 )
+ {
+ //TODO: more specific error handling
+ kdDebug ( 67100 ) << "failed to read info for control " << ctrlnum << endl;
+ return Mixer::ERR_READ;
+ }
+
+ if ( vol.isMuted() && extinfo.type != MIXT_ONOFF )
+ {
+ volume = 0;
+ }
+ else
+ {
+ switch ( extinfo.type )
+ {
+ case MIXT_ONOFF:
+ volume = (vol.isMuted()) ? (extinfo.minvalue) : (extinfo.maxvalue);
+ break;
+ case MIXT_MONOSLIDER:
+ volume = vol[Volume::LEFT];
+ break;
+
+ case MIXT_STEREOSLIDER:
+ volume = vol[Volume::LEFT] | ( vol[Volume::RIGHT] << 8 );
+ break;
+
+ case MIXT_SLIDER:
+ volume = vol[Volume::LEFT];
+ break;
+
+ case MIXT_MONOSLIDER16:
+ volume = vol[Volume::LEFT];
+ break;
+
+ case MIXT_STEREOSLIDER16:
+ volume = vol[Volume::LEFT] | ( vol[Volume::RIGHT] << 16 );
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ mv.dev = extinfo.dev;
+ mv.ctrl = extinfo.ctrl;
+ mv.timestamp = extinfo.timestamp;
+ mv.value = volume;
+
+ if ( wrapIoctl ( ioctl (m_fd, SNDCTL_MIX_WRITE, &mv) ) < 0 )
+ {
+ kdDebug ( 67100 ) << "error writing: " << endl;
+ return Mixer::ERR_WRITE;
+ }
+ return 0;
+}
+
+void Mixer_OSS4::setEnumIdHW(int ctrlnum, unsigned int idx)
+{
+ oss_mixext extinfo;
+ oss_mixer_value mv;
+
+ extinfo.dev = m_devnum;
+ extinfo.ctrl = ctrlnum;
+
+ if ( wrapIoctl ( ioctl(m_fd, SNDCTL_MIX_EXTINFO, &extinfo) ) < 0 )
+ {
+ //TODO: more specific error handling
+ kdDebug ( 67100 ) << "failed to read info for control " << ctrlnum << endl;
+ return;
+ }
+
+ if ( extinfo.type != MIXT_ENUM )
+ {
+ return;
+ }
+
+
+ //according to oss docs maxVal < minVal could be true - strange...
+ unsigned int maxVal = (unsigned int) extinfo.maxvalue;
+ unsigned int minVal = (unsigned int) extinfo.minvalue;
+
+ if ( maxVal < minVal )
+ {
+ int temp;
+ temp = maxVal;
+ maxVal = minVal;
+ minVal = temp;
+ }
+
+ if ( idx > maxVal || idx < minVal )
+ idx = minVal;
+
+ mv.dev = extinfo.dev;
+ mv.ctrl = extinfo.ctrl;
+ mv.timestamp = extinfo.timestamp;
+ mv.value = idx;
+
+ if ( wrapIoctl ( ioctl (m_fd, SNDCTL_MIX_WRITE, &mv) ) < 0 )
+ {
+ /* Oops, can't write to mixer */
+ kdDebug ( 67100 ) << "error writing: " << endl;
+ }
+}
+
+unsigned int Mixer_OSS4::enumIdHW(int ctrlnum)
+{
+ oss_mixext extinfo;
+ oss_mixer_value mv;
+
+ extinfo.dev = m_devnum;
+ extinfo.ctrl = ctrlnum;
+
+ if ( wrapIoctl ( ioctl(m_fd, SNDCTL_MIX_EXTINFO, &extinfo) ) < 0 )
+ {
+ //TODO: more specific error handling
+ //TODO: check whether those return values are actually possible
+ return Mixer::ERR_READ;
+ }
+
+ if ( extinfo.type != MIXT_ENUM )
+ {
+ return Mixer::ERR_READ;
+ }
+
+ mv.dev = extinfo.dev;
+ mv.ctrl = extinfo.ctrl;
+ mv.timestamp = extinfo.timestamp;
+
+ if ( wrapIoctl ( ioctl (m_fd, SNDCTL_MIX_READ, &mv) ) < 0 )
+ {
+ /* Oops, can't read mixer */
+ return Mixer::ERR_READ;
+ }
+ return mv.value;
+}
+
+int Mixer_OSS4::wrapIoctl(int ioctlRet)
+{
+ switch( ioctlRet )
+ {
+ case EIO:
+ {
+ kdDebug ( 67100 ) << "A hardware level error occured" << endl;
+ break;
+ }
+ case EINVAL:
+ {
+ kdDebug ( 67100 ) << "Operation caused an EINVAL. You may have found a bug in kmix OSS4 module or in OSS4 itself" << endl;
+ break;
+ }
+ case ENXIO:
+ {
+ kdDebug ( 67100 ) << "Operation index out of bounds or requested device does not exist - you likely found a bug in the kmix OSS4 module" << endl;
+ break;
+ }
+ case EPERM:
+ case EACCES:
+ {
+ kdDebug ( 67100 ) << errorText ( Mixer::ERR_PERM ) << endl;
+ break;
+ }
+ case ENODEV:
+ {
+ kdDebug ( 67100 ) << "kmix received an ENODEV errors - are the OSS4 drivers loaded?" << endl;
+ break;
+ }
+ case EPIPE:
+ case EIDRM:
+ {
+ reinitialize();
+ }
+
+ }
+ return ioctlRet;
+}
+
+
+QString OSS4_getDriverName()
+{
+ return "OSS4";
+}
+
diff --git a/kmix/mixer_oss4.h b/kmix/mixer_oss4.h
new file mode 100644
index 00000000..07a927d0
--- /dev/null
+++ b/kmix/mixer_oss4.h
@@ -0,0 +1,42 @@
+//-*-C++-*-
+
+#ifndef MIXER_OSS4_H
+#define MIXER_OSS4_H
+
+#include <qstring.h>
+
+#include "mixer_backend.h"
+#include <sys/soundcard.h>
+
+class Mixer_OSS4 : public Mixer_Backend
+{
+public:
+ Mixer_OSS4(int device = -1);
+ virtual ~Mixer_OSS4();
+
+ virtual QString errorText(int mixer_error);
+ virtual int readVolumeFromHW( int ctrlnum, Volume &vol );
+ virtual int writeVolumeToHW( int ctrlnum, Volume &vol );
+ virtual void setEnumIdHW(int ctrlnum, unsigned int idx);
+ virtual unsigned int enumIdHW(int ctrlnum);
+ virtual bool setRecsrcHW( int ctrlnum, bool on);
+ virtual bool isRecsrcHW( int ctrlnum );
+
+protected:
+
+ MixDevice::ChannelType classifyAndRename(QString &name, int flags);
+
+ int wrapIoctl(int ioctlRet);
+
+ void reinitialize() { open(); close(); };
+ virtual int open();
+ virtual int close();
+ virtual bool needsPolling() { return true; };
+
+ int m_ossVersion;
+ int m_fd;
+ int m_numExtensions;
+ int m_numMixers;
+ QString m_deviceName;
+};
+#endif
diff --git a/kmix/mixer_sun.cpp b/kmix/mixer_sun.cpp
new file mode 100644
index 00000000..542fdcc8
--- /dev/null
+++ b/kmix/mixer_sun.cpp
@@ -0,0 +1,473 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2000 Christian Esken <esken@kde.org>
+ * 2000 Brian Hanson <bhanson@hotmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/audioio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "mixer_sun.h"
+
+
+//======================================================================
+// CONSTANT/ENUM DEFINITIONS
+//======================================================================
+
+//
+// Mixer Device Numbers
+//
+// Note: We can't just use the Sun port #defines because :
+// 1) Some logical devices don't correspond to ports (master&recmon)
+// 2) The play and record port definitions reuse the same values
+//
+enum MixerDevs
+{
+ MIXERDEV_MASTER_VOLUME,
+ MIXERDEV_INTERNAL_SPEAKER,
+ MIXERDEV_HEADPHONE,
+ MIXERDEV_LINE_OUT,
+ MIXERDEV_RECORD_MONITOR,
+ MIXERDEV_MICROPHONE,
+ MIXERDEV_LINE_IN,
+ MIXERDEV_CD,
+ // Insert new devices before this marker
+ MIXERDEV_END_MARKER
+};
+const int numDevs = MIXERDEV_END_MARKER;
+
+//
+// Device name strings
+//
+const char* MixerDevNames[] =
+{
+ I18N_NOOP("Master Volume"),
+ I18N_NOOP("Internal Speaker"),
+ I18N_NOOP("Headphone"),
+ I18N_NOOP("Line Out"),
+ I18N_NOOP("Record Monitor"),
+ I18N_NOOP("Microphone"),
+ I18N_NOOP("Line In"),
+ I18N_NOOP("CD")
+};
+
+//
+// Channel types (this specifies which icon to display)
+//
+const MixDevice::ChannelType MixerChannelTypes[] =
+{
+ MixDevice::VOLUME, // MASTER_VOLUME
+ MixDevice::AUDIO, // INTERNAL_SPEAKER
+ MixDevice::EXTERNAL, // HEADPHONE (we really need an icon for this)
+ MixDevice::EXTERNAL, // LINE_OUT
+ MixDevice::RECMONITOR, // RECORD_MONITOR
+ MixDevice::MICROPHONE, // MICROPHONE
+ MixDevice::EXTERNAL, // LINE_IN
+ MixDevice::CD // CD
+};
+
+//
+// Mapping from device numbers to Sun port mask values
+//
+const uint_t MixerSunPortMasks[] =
+{
+ 0, // MASTER_VOLUME - no associated port
+ AUDIO_SPEAKER,
+ AUDIO_HEADPHONE,
+ AUDIO_LINE_OUT,
+ 0, // RECORD_MONITOR - no associated port
+ AUDIO_MICROPHONE,
+ AUDIO_LINE_IN,
+ AUDIO_CD
+};
+
+
+//======================================================================
+// FUNCTION/METHOD DEFINITIONS
+//======================================================================
+
+
+//======================================================================
+// FUNCTION : SUN_getMixer
+// DESCRIPTION : Creates and returns a new mixer object.
+//======================================================================
+Mixer_Backend* SUN_getMixer( int devnum )
+{
+ Mixer_Backend *l_mixer;
+ l_mixer = new Mixer_SUN( devnum );
+ return l_mixer;
+}
+
+
+//======================================================================
+// FUNCTION : Mixer::Mixer
+// DESCRIPTION : Class constructor.
+//======================================================================
+Mixer_SUN::Mixer_SUN(int devnum) : Mixer_Backend(devnum)
+{
+ if ( devnum == -1 )
+ m_devnum = 0;
+}
+
+//======================================================================
+// FUNCTION : Mixer::Mixer
+// DESCRIPTION : Class destructor.
+//======================================================================
+Mixer_SUN::~Mixer_SUN()
+{
+ close();
+}
+
+//======================================================================
+// FUNCTION : Mixer::open
+// DESCRIPTION : Initialize the mixer and open the hardware driver.
+//======================================================================
+int Mixer_SUN::open()
+{
+ //
+ // We don't support multiple devices
+ //
+ if ( m_devnum !=0 )
+ return Mixer::ERR_OPEN;
+
+ //
+ // Open the mixer hardware driver
+ //
+ QCString audiodev(getenv("AUDIODEV"));
+ if(audiodev.isNull())
+ audiodev = "/dev/audio";
+ audiodev += "ctl";
+ if ( ( fd = ::open( audiodev.data(), O_RDWR ) ) < 0 )
+ {
+ if ( errno == EACCES )
+ return Mixer::ERR_PERM;
+ else
+ return Mixer::ERR_OPEN;
+ }
+ else
+ {
+ //
+ // Mixer is open. Now define all of the mix devices.
+ //
+
+ if( m_mixDevices.isEmpty() )
+ {
+ for ( int idx = 0; idx < numDevs; idx++ )
+ {
+ Volume vol( 2, AUDIO_MAX_GAIN );
+ readVolumeFromHW( idx, vol );
+ MixDevice* md = new MixDevice( idx, vol, false, true,
+ QString(MixerDevNames[idx]), MixerChannelTypes[idx]);
+ md->setRecSource( isRecsrcHW( idx ) );
+ m_mixDevices.append( md );
+ }
+ }
+ else
+ {
+ for( unsigned int idx = 0; idx < m_mixDevices.count(); idx++ )
+ {
+ MixDevice* md = m_mixDevices.at( idx );
+ if( !md )
+ return Mixer::ERR_INCOMPATIBLESET;
+ writeVolumeToHW( idx, md->getVolume() );
+ }
+ }
+
+ m_mixerName = "SUN Audio Mixer";
+ m_isOpen = true;
+
+ return 0;
+ }
+}
+
+//======================================================================
+// FUNCTION : Mixer::close
+// DESCRIPTION : Close the hardware driver.
+//======================================================================
+int Mixer_SUN::close()
+{
+ m_isOpen = false;
+ int l_i_ret = ::close( fd );
+ m_mixDevices.clear();
+ return l_i_ret;
+}
+
+//======================================================================
+// FUNCTION : Mixer::errorText
+// DESCRIPTION : Convert an error code enum to a text string.
+//======================================================================
+QString Mixer_SUN::errorText( int mixer_error )
+{
+ QString errmsg;
+ switch (mixer_error)
+ {
+ case Mixer::ERR_PERM:
+ errmsg = i18n(
+ "kmix: You do not have permission to access the mixer device.\n"
+ "Ask your system administrator to fix /dev/audioctl to allow access."
+ );
+ break;
+ default:
+ errmsg = Mixer_Backend::errorText( mixer_error );
+ }
+ return errmsg;
+}
+
+
+//======================================================================
+// FUNCTION : Mixer::readVolumeFrmoHW
+// DESCRIPTION : Read the audio information from the driver.
+//======================================================================
+int Mixer_SUN::readVolumeFromHW( int devnum, Volume& volume )
+{
+ audio_info_t audioinfo;
+ uint_t devMask = MixerSunPortMasks[devnum];
+
+ //
+ // Read the current audio information from the driver
+ //
+ if ( ioctl( fd, AUDIO_GETINFO, &audioinfo ) < 0 )
+ {
+ return( Mixer::ERR_READ );
+ }
+ else
+ {
+ //
+ // Extract the appropriate fields based on the requested device
+ //
+ switch ( devnum )
+ {
+ case MIXERDEV_MASTER_VOLUME :
+ volume.setMuted( audioinfo.output_muted );
+ GainBalanceToVolume( audioinfo.play.gain,
+ audioinfo.play.balance,
+ volume );
+ break;
+
+ case MIXERDEV_RECORD_MONITOR :
+ volume.setMuted(FALSE);
+ volume.setAllVolumes( audioinfo.monitor_gain );
+ break;
+
+ case MIXERDEV_INTERNAL_SPEAKER :
+ case MIXERDEV_HEADPHONE :
+ case MIXERDEV_LINE_OUT :
+ volume.setMuted( (audioinfo.play.port & devMask) ? FALSE : TRUE );
+ GainBalanceToVolume( audioinfo.play.gain,
+ audioinfo.play.balance,
+ volume );
+ break;
+
+ case MIXERDEV_MICROPHONE :
+ case MIXERDEV_LINE_IN :
+ case MIXERDEV_CD :
+ volume.setMuted( (audioinfo.record.port & devMask) ? FALSE : TRUE );
+ GainBalanceToVolume( audioinfo.record.gain,
+ audioinfo.record.balance,
+ volume );
+ break;
+
+ default :
+ return Mixer::ERR_NODEV;
+ }
+ return 0;
+ }
+}
+
+//======================================================================
+// FUNCTION : Mixer::writeVolumeToHW
+// DESCRIPTION : Write the specified audio settings to the hardware.
+//======================================================================
+int Mixer_SUN::writeVolumeToHW( int devnum, Volume &volume )
+{
+ uint_t gain;
+ uchar_t balance;
+ uchar_t mute;
+
+ //
+ // Convert the Volume(left vol, right vol) to the Gain/Balance Sun uses
+ //
+ VolumeToGainBalance( volume, gain, balance );
+ mute = volume.isMuted() ? 1 : 0;
+
+ //
+ // Read the current audio settings from the hardware
+ //
+ audio_info_t audioinfo;
+ if ( ioctl( fd, AUDIO_GETINFO, &audioinfo ) < 0 )
+ {
+ return( Mixer::ERR_READ );
+ }
+
+ //
+ // Now, based on the devnum that we are writing to, update the appropriate
+ // volume field and twiddle the appropriate bitmask to enable/mute the
+ // device as necessary.
+ //
+ switch ( devnum )
+ {
+ case MIXERDEV_MASTER_VOLUME :
+ audioinfo.play.gain = gain;
+ audioinfo.play.balance = balance;
+ audioinfo.output_muted = mute;
+ break;
+
+ case MIXERDEV_RECORD_MONITOR :
+ audioinfo.monitor_gain = gain;
+ // no mute or balance for record monitor
+ break;
+
+ case MIXERDEV_INTERNAL_SPEAKER :
+ case MIXERDEV_HEADPHONE :
+ case MIXERDEV_LINE_OUT :
+ audioinfo.play.gain = gain;
+ audioinfo.play.balance = balance;
+ if ( mute )
+ audioinfo.play.port &= ~MixerSunPortMasks[devnum];
+ else
+ audioinfo.play.port |= MixerSunPortMasks[devnum];
+ break;
+
+ case MIXERDEV_MICROPHONE :
+ case MIXERDEV_LINE_IN :
+ case MIXERDEV_CD :
+ audioinfo.record.gain = gain;
+ audioinfo.record.balance = balance;
+ if ( mute )
+ audioinfo.record.port &= ~MixerSunPortMasks[devnum];
+ else
+ audioinfo.record.port |= MixerSunPortMasks[devnum];
+ break;
+
+ default :
+ return Mixer::ERR_NODEV;
+ }
+
+ //
+ // Now that we've updated the audioinfo struct, write it back to the hardware
+ //
+ if ( ioctl( fd, AUDIO_SETINFO, &audioinfo ) < 0 )
+ {
+ return( Mixer::ERR_WRITE );
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+//======================================================================
+// FUNCTION : Mixer::setRecsrcHW
+// DESCRIPTION :
+//======================================================================
+bool Mixer_SUN::setRecsrcHW( int /* devnum */, bool /* on */ )
+{
+ return FALSE;
+}
+
+//======================================================================
+// FUNCTION : Mixer::isRecsrcHW
+// DESCRIPTION : Returns true if the specified device is a record source.
+//======================================================================
+bool Mixer_SUN::isRecsrcHW( int devnum )
+{
+ switch ( devnum )
+ {
+ case MIXERDEV_MICROPHONE :
+ case MIXERDEV_LINE_IN :
+ case MIXERDEV_CD :
+ return TRUE;
+
+ default :
+ return FALSE;
+ }
+}
+
+//======================================================================
+// FUNCTION : Mixer::VolumeToGainBalance
+// DESCRIPTION : Converts a Volume(left vol + right vol) into the
+// Gain/Balance values used by Sun.
+//======================================================================
+void Mixer_SUN::VolumeToGainBalance( Volume& volume, uint_t& gain, uchar_t& balance )
+{
+ if ( ( volume.count() == 1 ) ||
+ ( volume[Volume::LEFT] == volume[Volume::RIGHT] ) )
+ {
+ gain = volume[Volume::LEFT];
+ balance = AUDIO_MID_BALANCE;
+ }
+ else
+ {
+ if ( volume[Volume::LEFT] > volume[Volume::RIGHT] )
+ {
+ gain = volume[Volume::LEFT];
+ balance = AUDIO_LEFT_BALANCE +
+ ( AUDIO_MID_BALANCE - AUDIO_LEFT_BALANCE ) *
+ volume[Volume::RIGHT] / volume[Volume::LEFT];
+ }
+ else
+ {
+ gain = volume[Volume::RIGHT];
+ balance = AUDIO_RIGHT_BALANCE -
+ ( AUDIO_RIGHT_BALANCE - AUDIO_MID_BALANCE ) *
+ volume[Volume::LEFT] / volume[Volume::RIGHT];
+ }
+ }
+}
+
+//======================================================================
+// FUNCTION : Mixer::GainBalanceToVolume
+// DESCRIPTION : Converts Gain/Balance returned by Sun driver to the
+// Volume(left vol + right vol) format used by kmix.
+//======================================================================
+void Mixer_SUN::GainBalanceToVolume( uint_t& gain, uchar_t& balance, Volume& volume )
+{
+ if ( volume.count() == 1 )
+ {
+ volume.setVolume( Volume::LEFT, gain );
+ }
+ else
+ {
+ if ( balance <= AUDIO_MID_BALANCE )
+ {
+ volume.setVolume( Volume::LEFT, gain );
+ volume.setVolume( Volume::RIGHT, gain *
+ ( balance - AUDIO_LEFT_BALANCE ) /
+ ( AUDIO_MID_BALANCE - AUDIO_LEFT_BALANCE ) );
+ }
+ else
+ {
+ volume.setVolume( Volume::RIGHT, gain );
+ volume.setVolume( Volume::LEFT, gain *
+ ( AUDIO_RIGHT_BALANCE - balance ) /
+ ( AUDIO_RIGHT_BALANCE - AUDIO_MID_BALANCE ) );
+ }
+ }
+}
+
+QString SUN_getDriverName() {
+ return "SUNAudio";
+}
+
diff --git a/kmix/mixer_sun.h b/kmix/mixer_sun.h
new file mode 100644
index 00000000..cd1ef76a
--- /dev/null
+++ b/kmix/mixer_sun.h
@@ -0,0 +1,52 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2000 Christian Esken <esken@kde.org>
+ * 2000 Brian Hanson <bhanson@hotmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MIXER_SUN_H
+#define MIXER_SUN_H
+
+#include <qstring.h>
+
+#include "mixer_backend.h"
+
+class Mixer_SUN : public Mixer_Backend
+{
+public:
+ Mixer_SUN(int devnum);
+ virtual ~Mixer_SUN();
+
+ virtual QString errorText(int mixer_error);
+ virtual int readVolumeFromHW( int devnum, Volume& volume );
+ virtual int writeVolumeToHW( int devnum, Volume& volume );
+ bool setRecsrcHW( int devnum, bool on );
+ bool isRecsrcHW( int devnum );
+
+protected:
+ virtual int open();
+ virtual int close();
+
+ void VolumeToGainBalance( Volume& volume, uint_t& gain, uchar_t& balance );
+ void GainBalanceToVolume( uint_t& gain, uchar_t& balance, Volume& volume );
+
+ int fd;
+};
+
+#endif
diff --git a/kmix/mixertoolbox.cpp b/kmix/mixertoolbox.cpp
new file mode 100644
index 00000000..9b6ee943
--- /dev/null
+++ b/kmix/mixertoolbox.cpp
@@ -0,0 +1,226 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include "qwidget.h"
+#include "qstring.h"
+
+//#include <kdebug.h>
+#include <klocale.h>
+
+#include "mixdevice.h"
+#include "mixer.h"
+
+#include "mixertoolbox.h"
+
+/***********************************************************************************
+ Attention:
+ This MixerToolBox is linked to the KMix Main Program, the KMix Applet and kmixctrl.
+ As we do not want to link in more than neccesary to kmixctrl, you are asked
+ not to put any GUI classes in here.
+ In the case where it is unavoidable, please put them in KMixToolBox.
+ ***********************************************************************************/
+
+/**
+ * Scan for Mixers in the System. This is the method that implicitely fills the
+ * list of Mixer's, which is accesible via the static Mixer::mixer() method.
+ * @par mixers The list where to add the found Mixers. This parameter is superfluous
+ * nowadays, as it is now really trivial to get it - just call the static
+ * Mixer::mixer() method.
+ * @par multiDriverMode Whether the Mixer scan should try more all backendends.
+ * 'true' means to scan all backends. 'false' means: After scanning the
+ * current backend the next backend is only scanned if no Mixers were found yet.
+ */
+void MixerToolBox::initMixer(QPtrList<Mixer> &mixers, bool multiDriverMode, QString& ref_hwInfoString)
+{
+ //kdDebug(67100) << "IN MixerToolBox::initMixer()"<<endl;
+
+ // Find all mixers and initalize them
+ QMap<QString,int> mixerNums;
+ int drvNum = Mixer::numDrivers();
+
+ int driverWithMixer = -1;
+ bool multipleDriversActive = false;
+
+ QString driverInfo = "";
+ QString driverInfoUsed = "";
+
+ for( int drv1=0; drv1<drvNum; drv1++ )
+ {
+ QString driverName = Mixer::driverName(drv1);
+ if ( driverInfo.length() > 0 )
+ driverInfo += " + ";
+ driverInfo += driverName;
+ }
+ /* Run a loop over all drivers. The loop will terminate after the first driver which
+ has mixers. And here is the reason:
+ - If you run ALSA with ALSA-OSS-Emulation enabled, mixers will show up twice: once
+ as native ALSA mixer, once as OSS mixer (emulated by ALSA). This is bad and WILL
+ confuse users. So it is a design decision that we can compile in multiple drivers
+ but we can run only one driver.
+ - For special usage scenarios, people will still want to run both drivers at the
+ same time. We allow them to hack their Config-File, where they can enable a
+ multi-driver mode.
+ - Another remark: For KMix3.0 or so, we should allow multiple-driver, for allowing
+ addition of special-use drivers, e.g. an Jack-Mixer-Backend, or a CD-Rom volume Backend.
+ */
+
+ bool autodetectionFinished = false;
+ for( int drv=0; drv<drvNum; drv++ )
+ {
+ QString driverName = Mixer::driverName(drv);
+
+ if ( autodetectionFinished ) {
+ // sane exit from loop
+ break;
+ }
+
+ bool drvInfoAppended = false;
+ // The "19" below is just a "silly" number:
+ // (Old: The loop will break as soon as an error is detected - e.g. on 3rd loop when 2 soundcards are installed)
+ // New: We don't try be that clever anymore. We now blindly scan 20 cards, as the clever
+ // approach doesn't work for the one or other user.
+ int devNumMax = 19;
+ for( int dev=0; dev<=devNumMax; dev++ )
+ {
+ Mixer *mixer = new Mixer( drv, dev );
+ if ( mixer->isValid() ) {
+ mixer->open();
+ mixers.append( mixer );
+ // Count mixer nums for every mixer name to identify mixers with equal names.
+ // This is for creating persistent (reusable) primary keys, which can safely
+ // be referenced (especially for config file access, so it is meant to be persistent!).
+ mixerNums[mixer->mixerName()]++;
+ // Create a useful PK
+ /* As we use "::" and ":" as separators, the parts %1,%2 and %3 may not
+ * contain it.
+ * %1, the driver name is from the KMix backends, it does not contain colons.
+ * %2, the mixer name, is typically coming from an OS driver. It could contain colons.
+ * %3, the mixer number, is a number: it does not contain colons.
+ */
+ QString mixerName = mixer->mixerName();
+ mixerName.replace(":","_");
+ QString primaryKeyOfMixer = QString("%1::%2:%3")
+ .arg(driverName)
+ .arg(mixerName)
+ .arg(mixerNums[mixer->mixerName()]);
+ // The following 3 replaces are for not messing up the config file
+ primaryKeyOfMixer.replace("]","_");
+ primaryKeyOfMixer.replace("[","_"); // not strictly neccesary, but lets play safe
+ primaryKeyOfMixer.replace(" ","_");
+ primaryKeyOfMixer.replace("=","_");
+
+ mixer->setID(primaryKeyOfMixer);
+
+ } // valid
+ else
+ {
+ delete mixer;
+ mixer = 0;
+ } // invalid
+
+ /* Lets decide if we the autoprobing shall continue: */
+ if ( multiDriverMode ) {
+ // trivial case: In multiDriverMode, we scan ALL 20 devs of ALL drivers
+ // so we have to do "nothing" in this case
+ } // multiDriver
+ else {
+ // In No-multiDriver-mode we only need to check after we reached devNumMax
+ if ( dev == devNumMax ) {
+ if ( Mixer::mixers().count() != 0 ) {
+ // highest device number of driver and a Mixer => finished
+ autodetectionFinished = true;
+ }
+ }
+ } // !multiDriver
+
+ // append driverName (used drivers)
+ if ( !drvInfoAppended )
+ {
+ drvInfoAppended = true;
+ QString driverName = Mixer::driverName(drv);
+ if ( drv!= 0 && mixers.count() > 0) {
+ driverInfoUsed += " + ";
+ }
+ driverInfoUsed += driverName;
+ }
+
+ // Check whether there are mixers in different drivers, so that the user can be warned
+ if (!multipleDriversActive)
+ {
+ if ( driverWithMixer == -1 )
+ {
+ // Aha, this is the very first detected device
+ driverWithMixer = drv;
+ }
+ else
+ {
+ if ( driverWithMixer != drv )
+ {
+ // Got him: There are mixers in different drivers
+ multipleDriversActive = true;
+ }
+ }
+ } // !multipleDriversActive
+
+ } // loop over sound card devices of current driver
+ } // loop over soundcard drivers
+
+ if ( Mixer::masterCard() == 0 ) {
+ // We have no master card yet. This actually only happens when there was
+ // not one defined in the kmixrc.
+ // So lets just set the first card as master card.
+ if ( Mixer::mixers().count() > 0 ) {
+ Mixer::setMasterCard( Mixer::mixers().first()->id());
+ }
+ }
+
+ ref_hwInfoString = i18n("Sound drivers supported:");
+ ref_hwInfoString.append(" ").append( driverInfo ).append( "\n").append(i18n("Sound drivers used:")) .append(" ").append(driverInfoUsed);
+
+ if ( multipleDriversActive )
+ {
+ // this will only be possible by hacking the config-file, as it will not be officially supported
+ ref_hwInfoString += "\nExperimental multiple-Driver mode activated";
+ }
+
+ kdDebug(67100) << ref_hwInfoString << endl << "Total number of detected Mixers: " << Mixer::mixers().count() << endl;
+ //kdDebug(67100) << "OUT MixerToolBox::initMixer()"<<endl;
+
+}
+
+
+/*
+ * Clean up and free all ressources of all found Mixers, which were found in the initMixer() call
+ */
+void MixerToolBox::deinitMixer()
+{
+ //kdDebug(67100) << "IN MixerToolBox::deinitMixer()"<<endl;
+ Mixer *mixer;
+ while ( (mixer=Mixer::mixers().first()) != 0)
+ {
+ //kdDebug(67100) << "MixerToolBox::deinitMixer() Remove Mixer" << endl;
+ mixer->close();
+ Mixer::mixers().remove(mixer);
+ delete mixer;
+ }
+ // kdDebug(67100) << "OUT MixerToolBox::deinitMixer()"<<endl;
+}
diff --git a/kmix/mixertoolbox.h b/kmix/mixertoolbox.h
new file mode 100644
index 00000000..1af4f22c
--- /dev/null
+++ b/kmix/mixertoolbox.h
@@ -0,0 +1,22 @@
+#ifndef MIXERTOOLBOX_H
+#define MIXERTOOLBOX_H
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+class Mixer;
+
+/**
+ * This toolbox contains various static methods that are shared throughout KMix.
+ * It only contains no-GUI code. The shared with-GUI code is in KMixToolBox
+ * The reason, why it is not put in a common base class is, that the classes are
+ * very different and cannot be changed (e.g. KPanelApplet) without major headache.
+ */
+class MixerToolBox {
+ public:
+ static void initMixer(QPtrList<Mixer>&, bool, QString&);
+ static void deinitMixer();
+};
+
+
+#endif
diff --git a/kmix/mixset.cpp b/kmix/mixset.cpp
new file mode 100644
index 00000000..c1b2a73f
--- /dev/null
+++ b/kmix/mixset.cpp
@@ -0,0 +1,71 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <kconfig.h>
+
+#include "mixdevice.h"
+#include "mixset.h"
+
+void MixSet::clone( MixSet &set )
+{
+ clear();
+
+ for( MixDevice *md=set.first(); md!=0; md=set.next() )
+ {
+ append( new MixDevice( *md ) );
+ }
+}
+
+void MixSet::read( KConfig *config, const QString& grp )
+{
+ kdDebug(67100) << "MixSet::read() of group " << grp << endl;
+ config->setGroup(grp);
+ m_name = config->readEntry( "name", m_name );
+
+ MixDevice* md;
+ for( md=first(); md!=0; md=next() )
+ {
+ md->read( config, grp );
+ }
+}
+
+void MixSet::write( KConfig *config, const QString& grp )
+{
+ kdDebug(67100) << "MixSet::write() of group " << grp << endl;
+ config->setGroup(grp);
+ config->writeEntry( "name", m_name );
+
+ MixDevice* md;
+ for( md=first(); md!=0; md=next() )
+ {
+ md->write( config, grp );
+ }
+}
+
+void MixSet::setName( const QString &name )
+{
+ m_name = name;
+}
+
diff --git a/kmix/mixset.h b/kmix/mixset.h
new file mode 100644
index 00000000..24448883
--- /dev/null
+++ b/kmix/mixset.h
@@ -0,0 +1,21 @@
+#ifndef MixSet_h
+#define MixSet_h
+
+#include "mixdevice.h"
+
+class MixSet : public QPtrList<MixDevice>
+{
+ public:
+ void read( KConfig *config, const QString& grp );
+ void write( KConfig *config, const QString& grp );
+
+ void clone( MixSet &orig );
+
+ QString name() { return m_name; };
+ void setName( const QString &name );
+
+ private:
+ QString m_name;
+};
+
+#endif
diff --git a/kmix/pics/Listener.png b/kmix/pics/Listener.png
new file mode 100644
index 00000000..4f195914
--- /dev/null
+++ b/kmix/pics/Listener.png
Binary files differ
diff --git a/kmix/pics/Makefile.am b/kmix/pics/Makefile.am
new file mode 100644
index 00000000..bd1d3ee8
--- /dev/null
+++ b/kmix/pics/Makefile.am
@@ -0,0 +1,14 @@
+
+picsdir = $(kde_datadir)/kmix/pics
+pics_DATA = mix_audio.png mix_bass.png mix_cd.png mix_ext.png \
+ mix_microphone.png mix_midi.png mix_recmon.png mix_treble.png \
+ mix_unknown.png mix_volume.png mix_surround.png mix_video.png \
+ mix_headphone.png mix_digital.png mix_ac97.png \
+ kmixdocked.png kmixdocked_mute.png kmixdocked_error.png \
+ mix_record.png \
+ SpeakerFrontLeft.png SpeakerRearLeft.png SpeakerFrontRight.png SpeakerRearRight.png Listener.png
+
+
+EXTRA_DIST = $(pics_DATA)
+
+KDE_ICON=kmix
diff --git a/kmix/pics/SpeakerFrontLeft.png b/kmix/pics/SpeakerFrontLeft.png
new file mode 100644
index 00000000..21f7795e
--- /dev/null
+++ b/kmix/pics/SpeakerFrontLeft.png
Binary files differ
diff --git a/kmix/pics/SpeakerFrontRight.png b/kmix/pics/SpeakerFrontRight.png
new file mode 100644
index 00000000..33cee57e
--- /dev/null
+++ b/kmix/pics/SpeakerFrontRight.png
Binary files differ
diff --git a/kmix/pics/SpeakerRearLeft.png b/kmix/pics/SpeakerRearLeft.png
new file mode 100644
index 00000000..375fe8df
--- /dev/null
+++ b/kmix/pics/SpeakerRearLeft.png
Binary files differ
diff --git a/kmix/pics/SpeakerRearRight.png b/kmix/pics/SpeakerRearRight.png
new file mode 100644
index 00000000..e16af4c8
--- /dev/null
+++ b/kmix/pics/SpeakerRearRight.png
Binary files differ
diff --git a/kmix/pics/hi128-app-kmix.png b/kmix/pics/hi128-app-kmix.png
new file mode 100644
index 00000000..5543818b
--- /dev/null
+++ b/kmix/pics/hi128-app-kmix.png
Binary files differ
diff --git a/kmix/pics/hi16-app-kmix.png b/kmix/pics/hi16-app-kmix.png
new file mode 100644
index 00000000..a422967e
--- /dev/null
+++ b/kmix/pics/hi16-app-kmix.png
Binary files differ
diff --git a/kmix/pics/hi32-app-kmix.png b/kmix/pics/hi32-app-kmix.png
new file mode 100644
index 00000000..2036faa5
--- /dev/null
+++ b/kmix/pics/hi32-app-kmix.png
Binary files differ
diff --git a/kmix/pics/hi48-app-kmix.png b/kmix/pics/hi48-app-kmix.png
new file mode 100644
index 00000000..dc766a89
--- /dev/null
+++ b/kmix/pics/hi48-app-kmix.png
Binary files differ
diff --git a/kmix/pics/hi64-app-kmix.png b/kmix/pics/hi64-app-kmix.png
new file mode 100644
index 00000000..f7679b27
--- /dev/null
+++ b/kmix/pics/hi64-app-kmix.png
Binary files differ
diff --git a/kmix/pics/kmixdocked.png b/kmix/pics/kmixdocked.png
new file mode 100644
index 00000000..367ff42e
--- /dev/null
+++ b/kmix/pics/kmixdocked.png
Binary files differ
diff --git a/kmix/pics/kmixdocked_error.png b/kmix/pics/kmixdocked_error.png
new file mode 100644
index 00000000..e9b68f2e
--- /dev/null
+++ b/kmix/pics/kmixdocked_error.png
Binary files differ
diff --git a/kmix/pics/kmixdocked_mute.png b/kmix/pics/kmixdocked_mute.png
new file mode 100644
index 00000000..31f21541
--- /dev/null
+++ b/kmix/pics/kmixdocked_mute.png
Binary files differ
diff --git a/kmix/pics/mix_ac97.png b/kmix/pics/mix_ac97.png
new file mode 100644
index 00000000..ad4f3219
--- /dev/null
+++ b/kmix/pics/mix_ac97.png
Binary files differ
diff --git a/kmix/pics/mix_audio.png b/kmix/pics/mix_audio.png
new file mode 100644
index 00000000..74fc2764
--- /dev/null
+++ b/kmix/pics/mix_audio.png
Binary files differ
diff --git a/kmix/pics/mix_bass.png b/kmix/pics/mix_bass.png
new file mode 100644
index 00000000..5952d8b8
--- /dev/null
+++ b/kmix/pics/mix_bass.png
Binary files differ
diff --git a/kmix/pics/mix_cd.png b/kmix/pics/mix_cd.png
new file mode 100644
index 00000000..77ac81e9
--- /dev/null
+++ b/kmix/pics/mix_cd.png
Binary files differ
diff --git a/kmix/pics/mix_digital.png b/kmix/pics/mix_digital.png
new file mode 100644
index 00000000..739e60f5
--- /dev/null
+++ b/kmix/pics/mix_digital.png
Binary files differ
diff --git a/kmix/pics/mix_ext.png b/kmix/pics/mix_ext.png
new file mode 100644
index 00000000..c49f08ba
--- /dev/null
+++ b/kmix/pics/mix_ext.png
Binary files differ
diff --git a/kmix/pics/mix_headphone.png b/kmix/pics/mix_headphone.png
new file mode 100644
index 00000000..de62b2fd
--- /dev/null
+++ b/kmix/pics/mix_headphone.png
Binary files differ
diff --git a/kmix/pics/mix_microphone.png b/kmix/pics/mix_microphone.png
new file mode 100644
index 00000000..ca747403
--- /dev/null
+++ b/kmix/pics/mix_microphone.png
Binary files differ
diff --git a/kmix/pics/mix_midi.png b/kmix/pics/mix_midi.png
new file mode 100644
index 00000000..0b8477cc
--- /dev/null
+++ b/kmix/pics/mix_midi.png
Binary files differ
diff --git a/kmix/pics/mix_recmon.png b/kmix/pics/mix_recmon.png
new file mode 100644
index 00000000..dba5c968
--- /dev/null
+++ b/kmix/pics/mix_recmon.png
Binary files differ
diff --git a/kmix/pics/mix_record.png b/kmix/pics/mix_record.png
new file mode 100644
index 00000000..f4aa7401
--- /dev/null
+++ b/kmix/pics/mix_record.png
Binary files differ
diff --git a/kmix/pics/mix_surround.png b/kmix/pics/mix_surround.png
new file mode 100644
index 00000000..d02d02c6
--- /dev/null
+++ b/kmix/pics/mix_surround.png
Binary files differ
diff --git a/kmix/pics/mix_toslink.png b/kmix/pics/mix_toslink.png
new file mode 100644
index 00000000..6766e613
--- /dev/null
+++ b/kmix/pics/mix_toslink.png
Binary files differ
diff --git a/kmix/pics/mix_treble.png b/kmix/pics/mix_treble.png
new file mode 100644
index 00000000..9871ab72
--- /dev/null
+++ b/kmix/pics/mix_treble.png
Binary files differ
diff --git a/kmix/pics/mix_unknown.png b/kmix/pics/mix_unknown.png
new file mode 100644
index 00000000..7c904971
--- /dev/null
+++ b/kmix/pics/mix_unknown.png
Binary files differ
diff --git a/kmix/pics/mix_video.png b/kmix/pics/mix_video.png
new file mode 100644
index 00000000..59efde57
--- /dev/null
+++ b/kmix/pics/mix_video.png
Binary files differ
diff --git a/kmix/pics/mix_volume.png b/kmix/pics/mix_volume.png
new file mode 100644
index 00000000..d17a85d2
--- /dev/null
+++ b/kmix/pics/mix_volume.png
Binary files differ
diff --git a/kmix/resource.h b/kmix/resource.h
new file mode 100644
index 00000000..57461096
--- /dev/null
+++ b/kmix/resource.h
@@ -0,0 +1,30 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef RESOURCE_H
+#define RESOURCE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#endif // RESOURCE_H
diff --git a/kmix/restore_kmix_volumes.desktop b/kmix/restore_kmix_volumes.desktop
new file mode 100644
index 00000000..fed5e90d
--- /dev/null
+++ b/kmix/restore_kmix_volumes.desktop
@@ -0,0 +1,58 @@
+[Desktop Entry]
+X-KDE-autostart-phase=1
+X-KDE-autostart-condition=kmixrc::startkdeRestore:true
+Type=Application
+Exec=kmixctrl --restore
+OnlyShowIn=KDE;
+Name=Restore Mixer Volumes
+Name[bg]=Възстановяване на стойностите на миксера
+Name[bn]=মিক্সার ভলিউম পুনঃস্থাপন করে
+Name[br]=Assav pep tolzennad mesker
+Name[bs]=Vrati jačine miksera
+Name[ca]=Restaura els volums del mesclador
+Name[cs]=Obnovit nastavení hlasitosti
+Name[cy]=Adfer Lefelau Sain y Cymysgydd
+Name[da]=Genopret mikser lydstyrke
+Name[de]=Lautstärken wiederherstellen
+Name[el]=Επαναφορά των εντάσεων του μείκτη
+Name[eo]=Restarigu Miksilagordon
+Name[es]=Restaurar opciones del mezclador
+Name[et]=Mikseri helitugevuste taastamine
+Name[eu]=Nahasgailuaren bolumenak berreskuratu
+Name[fa]=باز‌گردانی حجم صداهای مخلوط‌کن
+Name[fi]=Palauta mikserin äänivoimakkuudet
+Name[fr]=Restaurer les volumes du mixage
+Name[gl]=Restaurar os Volumes do Mesturador
+Name[he]=שיחזור עוצמות הקול של המערבל
+Name[hu]=A hangkeverő hangerőinek visszaállítása
+Name[is]=Sækja aftur stillingar hljóðrása
+Name[it]=Ripristina i volumi del Mixer
+Name[ja]=ミキサーの音量設定を復元する
+Name[kk]=Микшер деңгейлерін қалпына келтіру
+Name[km]=ស្ដារ​សំឡេង​ឧបករណ៍​លាយ
+Name[ko]=믹서 음량 복원
+Name[lt]=Atstatyti maišytuvo garso lygius
+Name[mk]=Враќање на гласностите на миксетата
+Name[nb]=Gjenopprett lydstyrkene til mikser
+Name[nds]=Mischerluutstärken wedderherstellen
+Name[ne]=मिक्सर भोल्युम पूर्वावस्थामा ल्यानुहोस्
+Name[nl]=Mixervolumes herstellen
+Name[nn]=Gjenopprett miksarlydstyrkar
+Name[pl]=Odtwarzanie głośności miksera
+Name[pt]=Repor os Volumes
+Name[pt_BR]=Restaurar volumes do mixer
+Name[ro]=Reface volumele mixerului
+Name[ru]=Восстановление настроек микшера
+Name[sk]=Obnoviť nastavenia mixéra
+Name[sl]=Obnovi nastavitve mešalnika
+Name[sr]=Обнови јачине миксете
+Name[sr@Latn]=Obnovi jačine miksete
+Name[sv]=Återställ mixervolymer
+Name[ta]=ஒன்றுசேர்க்கும் ஒலியளவு மீட்கவும்
+Name[th]=เรียกคืนระดับเสียงของมิกเซอร์
+Name[tr]=Karıştırıcı Seslerini Yenile
+Name[uk]=Відновити параметри мікшера
+Name[zh_CN]=恢复混音器设置
+Name[zh_HK]=回復混音器音量
+Name[zh_TW]=回復混音器音量
+
diff --git a/kmix/version.h b/kmix/version.h
new file mode 100644
index 00000000..c80dd2f6
--- /dev/null
+++ b/kmix/version.h
@@ -0,0 +1,21 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#define APP_VERSION "2.6.1"
diff --git a/kmix/verticaltext.cpp b/kmix/verticaltext.cpp
new file mode 100644
index 00000000..490e4c91
--- /dev/null
+++ b/kmix/verticaltext.cpp
@@ -0,0 +1,57 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 2003-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "verticaltext.h"
+#include <qpainter.h>
+#include <kdebug.h>
+
+
+VerticalText::VerticalText(QWidget * parent, const char * name, WFlags f) : QWidget(parent,name,f)
+{
+ resize(20,100 /*parent->height() */ );
+ setMinimumSize(20,10); // neccesary for smooth integration into layouts (we only care for the widths).
+}
+
+VerticalText::~VerticalText() {
+}
+
+
+void VerticalText::paintEvent ( QPaintEvent * /*event*/ ) {
+ //kdDebug(67100) << "paintEvent(). height()=" << height() << "\n";
+ QPainter paint(this);
+ paint.rotate(270);
+ paint.translate(0,-4); // Silly "solution" to make underlengths work
+
+ // Fix for bug 72520
+ //- paint.drawText(-height()+2,width(),name());
+ //+ paint.drawText( -height()+2, width(), QString::fromUtf8(name()) );
+ paint.drawText( -height()+2, width(), QString::fromUtf8(name()) );
+}
+
+QSize VerticalText::sizeHint() const {
+ return QSize(20,100); // !! UGLY. Should be reworked
+}
+
+QSizePolicy VerticalText::sizePolicy () const
+{
+ return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+}
+
diff --git a/kmix/verticaltext.h b/kmix/verticaltext.h
new file mode 100644
index 00000000..7b1c07e0
--- /dev/null
+++ b/kmix/verticaltext.h
@@ -0,0 +1,19 @@
+#ifndef VerticalText_h
+#define VerticalText_h
+
+#include <qwidget.h>
+
+class VerticalText : public QWidget
+{
+public:
+ VerticalText(QWidget * parent, const char * name, WFlags f = 0);
+ ~VerticalText();
+
+ QSize sizeHint() const;
+ QSizePolicy sizePolicy () const;
+
+protected:
+ void paintEvent ( QPaintEvent * event );
+};
+
+#endif
diff --git a/kmix/viewapplet.cpp b/kmix/viewapplet.cpp
new file mode 100644
index 00000000..23599190
--- /dev/null
+++ b/kmix/viewapplet.cpp
@@ -0,0 +1,242 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewapplet.h"
+
+// Qt
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qsize.h>
+
+// KDE
+#include <kactioncollection.h>
+#include <kdebug.h>
+#include <kpanelapplet.h>
+#include <kstdaction.h>
+
+// KMix
+#include "kmixtoolbox.h"
+#include "mdwslider.h"
+#include "mixer.h"
+
+ViewApplet::ViewApplet(QWidget* parent, const char* name, Mixer* mixer, ViewBase::ViewFlags vflags, KPanelApplet::Position position )
+ : ViewBase(parent, name, QString::null, mixer, WStyle_Customize|WStyle_NoBorder, vflags)
+{
+ setBackgroundOrigin(AncestorOrigin);
+ // remove the menu bar action, that is put by the "ViewBase" constructor in _actions.
+ //KToggleAction *m = static_cast<KToggleAction*>(KStdAction::showMenubar( this, SLOT(toggleMenuBarSlot()), _actions ));
+ _actions->remove( KStdAction::showMenubar(this, SLOT(toggleMenuBarSlot()), _actions) );
+
+
+ if ( position == KPanelApplet::pLeft || position == KPanelApplet::pRight ) {
+ //kdDebug(67100) << "ViewApplet() isVertical" << "\n";
+ _viewOrientation = Qt::Vertical;
+ }
+ else {
+ //kdDebug(67100) << "ViewApplet() isHorizontal" << "\n";
+ _viewOrientation = Qt::Horizontal;
+ }
+
+ if ( _viewOrientation == Qt::Horizontal ) {
+ _layoutMDW = new QHBoxLayout( this );
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ }
+ else {
+ _layoutMDW = new QVBoxLayout( this );
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ }
+
+
+ //_layoutMDW->setResizeMode(QLayout::Fixed);
+ init();
+}
+
+ViewApplet::~ViewApplet() {
+}
+
+void ViewApplet::setMixSet(MixSet *mixset)
+{
+ MixDevice* md;
+ for ( md = mixset->first(); md != 0; md = mixset->next() ) {
+ if ( (! md->isSwitch()) && ( ! md->isEnum() ) ) {
+ _mixSet->append(md);
+ }
+ }
+}
+
+int ViewApplet::count()
+{
+ return ( _mixSet->count() );
+}
+
+int ViewApplet::advice() {
+ if ( _mixSet->count() > 0 ) {
+ // The standard input and output views are always advised, if there are devices in it
+ return 100;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+
+QWidget* ViewApplet::add(MixDevice *md)
+{
+ /**
+ Slider orientation is exactly the other way round. If the applet stretches horzontally,
+ the sliders must be vertical
+ */
+ Qt::Orientation sliderOrientation;
+ if (_viewOrientation == Qt::Horizontal )
+ sliderOrientation = Qt::Vertical;
+ else
+ sliderOrientation = Qt::Horizontal;
+
+ // kdDebug(67100) << "ViewApplet::add()\n";
+ MixDeviceWidget *mdw =
+ new MDWSlider(
+ _mixer, // the mixer for this device
+ md, // MixDevice (parameter)
+ false, // Show Mute LED
+ false, // Show Record LED
+ true, // Small
+ sliderOrientation, // Orientation
+ this, // parent
+ this, // View widget
+ md->name().latin1()
+ );
+ mdw->setBackgroundOrigin(AncestorOrigin);
+
+ static_cast<MDWSlider*>(mdw)->setValueStyle(MixDeviceWidget::NNONE);
+ static_cast<MDWSlider*>(mdw)->setIcons(shouldShowIcons( size()) ); // !!! This should use the panel size
+ _layoutMDW->add(mdw);
+ return mdw;
+}
+
+void ViewApplet::constructionFinished() {
+ _layoutMDW->activate();
+
+ KMixToolBox::setIcons ( _mdws, shouldShowIcons( size()) ); // !!! This should use the panel size
+ KMixToolBox::setValueStyle( _mdws, MixDeviceWidget::NNONE);
+}
+
+
+QSize ViewApplet::sizeHint() const {
+ // Basically out main layout knows very good what the sizes should be
+ QSize qsz = _layoutMDW->sizeHint();
+ //kdDebug(67100) << "ViewApplet::sizeHint(): NewSize is " << qsz << "\n";
+ return qsz;
+}
+
+QSizePolicy ViewApplet::sizePolicy() const {
+ if ( _viewOrientation == Qt::Horizontal ) {
+ //kdDebug(67100) << "ViewApplet::sizePolicy=(Fixed,Expanding)\n";
+ return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ }
+ else {
+ //kdDebug(67100) << "ViewApplet::sizePolicy=(Expanding,Fixed)\n";
+ return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ }
+}
+
+bool ViewApplet::shouldShowIcons(QSize qsz) {
+ bool showIcons = false;
+ if ( _viewOrientation == Qt::Horizontal ) {
+ if ( qsz.height() >= 32 ) {
+ //kdDebug(67100) << "ViewApplet::resizeEvent() hor >=32" << qre->size() << "\n";
+ showIcons = true;
+ }
+ }
+ else {
+ if ( qsz.width() >= 32 ) {
+ //kdDebug(67100) << "ViewApplet::resizeEvent() vert >=32" << qre->size() << "\n";
+ showIcons = true;
+ }
+ }
+ return showIcons;
+}
+
+void ViewApplet::resizeEvent(QResizeEvent *qre)
+{
+ //kdDebug(67100) << "ViewApplet::resizeEvent() size=" << qre->size() << "\n";
+ // decide whether we have to show or hide all icons
+ bool showIcons = shouldShowIcons(qre->size());
+
+ for ( QWidget *mdw = _mdws.first(); mdw != 0; mdw = _mdws.next() ) {
+ if ( mdw == 0 ) {
+ kdError(67100) << "ViewApplet::resizeEvent(): mdw == 0\n";
+ break; // sanity check (normally the lists are set up correctly)
+ }
+ else {
+ if ( mdw->inherits("MDWSlider")) {
+ static_cast<MDWSlider*>(mdw)->setIcons(showIcons);
+ static_cast<MDWSlider*>(mdw)->setValueStyle(MixDeviceWidget::NNONE);
+ //static_cast<MDWSlider*>(mdw)->resize(qre->size());
+ }
+ }
+ }
+ // kdDebug(67100) << "ViewApplet::resizeEvent(). SHOULD resize _layoutMDW to " << qre->size() << endl;
+ //QWidget::resizeEvent(qre);
+
+ // resizing changes our own sizeHint(), because we must take the new PanelSize in account.
+ // So updateGeometry() is amust for us.
+ updateGeometry();
+}
+
+
+void ViewApplet::refreshVolumeLevels() {
+ //kdDebug(67100) << "ViewApplet::refreshVolumeLevels()\n";
+
+ QWidget *mdw = _mdws.first();
+ MixDevice* md;
+ for ( md = _mixSet->first(); md != 0; md = _mixSet->next() ) {
+ if ( mdw == 0 ) {
+ kdError(67100) << "ViewApplet::refreshVolumeLevels(): mdw == 0\n";
+ break; // sanity check (normally the lists are set up correctly)
+ }
+ else {
+ if ( mdw->inherits("MDWSlider")) {
+ //kdDebug(67100) << "ViewApplet::refreshVolumeLevels(): updating\n";
+ // a slider, fine. Lets update its value
+ static_cast<MDWSlider*>(mdw)->update();
+ }
+ else {
+ kdError(67100) << "ViewApplet::refreshVolumeLevels(): mdw is not slider\n";
+ // no slider. Cannot happen in theory => skip it
+ }
+ }
+ mdw = _mdws.next();
+ }
+}
+
+void ViewApplet::configurationUpdate() {
+ updateGeometry();
+ //_layoutMDW->activate();
+ constructionFinished(); // contains "_layoutMDW->activate();"
+ emit appletContentChanged();
+ kdDebug(67100) << "ViewApplet::configurationUpdate()" << endl;
+ // the following "emit" is only here to be picked up by KMixApplet, because it has to
+ // - make sure the panel is informed about the size change
+ // - save the new configuration
+ //emit configurationUpdated();
+}
+
+#include "viewapplet.moc"
diff --git a/kmix/viewapplet.h b/kmix/viewapplet.h
new file mode 100644
index 00000000..a03d90e2
--- /dev/null
+++ b/kmix/viewapplet.h
@@ -0,0 +1,47 @@
+#ifndef ViewApplet_h
+#define ViewApplet_h
+
+#include "viewbase.h"
+#include <kpanelapplet.h>
+
+class QBoxLayout;
+class QHBox;
+class QSize;
+
+class Mixer;
+
+class ViewApplet : public ViewBase
+{
+ Q_OBJECT
+public:
+ ViewApplet(QWidget* parent, const char* name, Mixer* mixer, ViewBase::ViewFlags vflags, KPanelApplet::Position pos);
+ ~ViewApplet();
+
+ virtual int count();
+ virtual int advice();
+ virtual void setMixSet(MixSet *mixset);
+ virtual QWidget* add(MixDevice *mdw);
+ virtual void constructionFinished();
+ virtual void configurationUpdate();
+
+ QSize sizeHint() const;
+ QSizePolicy sizePolicy() const;
+ virtual void resizeEvent(QResizeEvent*);
+
+signals:
+ void appletContentChanged();
+
+public slots:
+ virtual void refreshVolumeLevels();
+
+private:
+ bool shouldShowIcons(QSize);
+ QBoxLayout* _layoutMDW;
+ // Position of the applet (pLeft, pRight, pTop, pBottom)
+ //KPanelApplet::Position _KMIXposition;
+ // Orientation of the applet (horizontal or vertical)
+ Qt::Orientation _viewOrientation;
+};
+
+#endif
+
diff --git a/kmix/viewbase.cpp b/kmix/viewbase.cpp
new file mode 100644
index 00000000..af4a9aa5
--- /dev/null
+++ b/kmix/viewbase.cpp
@@ -0,0 +1,187 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewbase.h"
+
+// QT
+#include <qlabel.h>
+#include <qcursor.h>
+
+// KDE
+#include <kaction.h>
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kiconloader.h>
+
+// KMix
+#include "dialogviewconfiguration.h"
+#include "mixdevicewidget.h"
+#include "mixer.h"
+
+
+ViewBase::ViewBase(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, WFlags f, ViewBase::ViewFlags vflags)
+ : QWidget(parent, name, f), _vflags(vflags), _caption(caption)
+{
+ _mixer = mixer;
+ _mixSet = new MixSet();
+
+ /* Can't use the following construct:
+ setMixSet( & mixer->getMixSet());
+ C++ does not use overloaded methods like getMixSet() as long as the constructor has not completed :-(((
+ */
+ _actions = new KActionCollection( this );
+
+ // Plug in the "showMenubar" action, if the caller wants it. Typically this is only neccesary for views in the KMix main window.
+ if ( vflags & ViewBase::HasMenuBar ) {
+ KToggleAction *m = static_cast<KToggleAction*>(KStdAction::showMenubar( this, SLOT(toggleMenuBarSlot()), _actions ));
+ if ( vflags & ViewBase::MenuBarVisible ) {
+ m->setChecked(true);
+ }
+ else {
+ m->setChecked(false);
+ }
+ }
+ new KAction(i18n("&Channels"), 0, this, SLOT(configureView()), _actions, "toggle_channels");
+ connect ( _mixer, SIGNAL(newVolumeLevels()), this, SLOT(refreshVolumeLevels()) );
+}
+
+ViewBase::~ViewBase() {
+ delete _mixSet;
+}
+
+void ViewBase::init() {
+ const MixSet& mixset = _mixer->getMixSet();
+ setMixSet( const_cast<MixSet*>(&mixset)); // const_cast<>
+}
+
+void ViewBase::setMixSet(MixSet *)
+{
+ // do nothing. Subclasses can do something if they feel like it
+}
+
+/**
+ * Dummy implementation for add().
+ */
+QWidget* ViewBase::add(MixDevice* mdw) {
+ QWidget* label = new QLabel( mdw->name(), this, mdw->name().latin1());
+ label->move(0, mdw->num()*12);
+ return label;
+}
+
+void ViewBase::configurationUpdate() {
+}
+
+/**
+ * Create all widgets.
+ * This is a loop over all supported devices of the corresponding view.
+ * On each device add() is called - the derived class must implement add() for creating and placing
+ * the real MixDeviceWidget.
+ * The added MixDeviceWidget is appended to the _mdws list.
+ */
+void ViewBase::createDeviceWidgets()
+{
+ // create devices
+ MixDevice *mixDevice;
+ for ( mixDevice = _mixSet->first(); mixDevice != 0; mixDevice = _mixSet->next())
+ {
+ QWidget* mdw = add(mixDevice);
+ _mdws.append(mdw);
+ }
+ // allow view to "polish" itself
+ constructionFinished();
+}
+
+// ---------- Popup stuff START ---------------------
+void ViewBase::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button()==RightButton )
+ showContextMenu();
+}
+
+/**
+ * Return a popup menu. This contains basic entries.
+ * More can be added by the caller.
+ */
+KPopupMenu* ViewBase::getPopup()
+{
+ popupReset();
+ return _popMenu;
+}
+
+void ViewBase::popupReset()
+{
+ KAction *a;
+
+ _popMenu = new KPopupMenu( this );
+ _popMenu->insertTitle( SmallIcon( "kmix" ), i18n("Device Settings") );
+
+ a = _actions->action( "toggle_channels" );
+ if ( a ) a->plug( _popMenu );
+
+ a = _actions->action( "options_show_menubar" );
+ if ( a ) a->plug( _popMenu );
+}
+
+
+/**
+ This will only get executed, when the user has removed all items from the view.
+ Don't remove this method, because then the user cannot get a menu for getting his
+ channels back
+*/
+void ViewBase::showContextMenu()
+{
+ //kdDebug(67100) << "ViewBase::showContextMenu()" << endl;
+ popupReset();
+
+ QPoint pos = QCursor::pos();
+ _popMenu->popup( pos );
+}
+
+
+void ViewBase::refreshVolumeLevels()
+{
+ // is virtual
+}
+
+Mixer* ViewBase::getMixer() {
+ return _mixer;
+}
+
+/**
+ * Open the View configuration dialog. The user can select which channels he wants
+ * to see and which not.
+ */
+void ViewBase::configureView() {
+
+ DialogViewConfiguration* dvc = new DialogViewConfiguration(0, *this);
+ dvc->show();
+ // !! The dialog is modal. Does it delete itself?
+}
+
+void ViewBase::toggleMenuBarSlot() {
+ //kdDebug(67100) << "ViewBase::toggleMenuBarSlot() start\n";
+ emit toggleMenuBar();
+ //kdDebug(67100) << "ViewBase::toggleMenuBarSlot() done\n";
+}
+
+// ---------- Popup stuff END ---------------------
+
+#include "viewbase.moc"
diff --git a/kmix/viewbase.h b/kmix/viewbase.h
new file mode 100644
index 00000000..50d92b10
--- /dev/null
+++ b/kmix/viewbase.h
@@ -0,0 +1,121 @@
+#ifndef ViewBase_h
+#define ViewBase_h
+
+// QT
+#include "qwidget.h"
+
+// KDE
+class KActionCollection;
+class KPopupMenu;
+class MixSet;
+class Mixer;
+class MixDevice;
+
+/**
+ * The ViewBase is a virtual base class, to be used for subclassing the real Mixer Views.
+ */
+class ViewBase : public QWidget
+{
+ Q_OBJECT
+public:
+
+ typedef uint ViewFlags;
+ enum ViewFlagsEnum {
+ // Regular flags
+ HasMenuBar = 0x0001,
+ MenuBarVisible = 0x0002,
+ Horizontal = 0x0004,
+ Vertical = 0x0008,
+ // Experimental flags
+ Experimental_SurroundView = 0x1000,
+ Experimental_GridView = 0x2000
+ };
+
+ ViewBase(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, WFlags=0, ViewFlags vflags=0);
+ virtual ~ViewBase();
+
+ // Subclasses must define this method. It is called by the ViewBase() constuctor.
+ // The view class must initialize here the _mixSet. This will normally be a subset
+ // of the passed mixset.
+ // After that the subclass must be prepared for
+ // being fed MixDevice's via the add() method.
+ virtual void setMixSet(MixSet *mixset);
+
+ // Returns the number of accepted MixDevice's from setMixerSet(). This is
+ // normally smaller that mixset->count(), except when the class creates virtual
+ // devices
+ virtual int count() = 0;
+ // returns an advice about whether this view should be used at all. The returned
+ // value is a percentage (0-100). A view without accepted devices would return 0,
+ // a "3D sound View" would return 75, if all vital but some optional devices are
+ // not available.
+ virtual int advice() = 0;
+
+ // This method is called by ViewBase at the end of createDeviceWidgets(). The default
+ // implementation does nothing. Subclasses can override this method for doing final
+ // touches. This is very much like polish(), but called at an exactly well-known time.
+ // Also I do not want Views to interfere with polish()
+ virtual void constructionFinished() = 0;
+
+ // This method is called after a configuration update (in other words: after the user
+ // has clicked "OK" on the "show/hide" configuration dialog. The default implementation
+ // does nothing.
+ virtual void configurationUpdate();
+
+ /**
+ * Creates the widgets for all supported devices. The default implementation loops
+ * over the supported MixDevice's and calls add() for each of it.
+ */
+ virtual void createDeviceWidgets();
+
+ /**
+ * Creates a suitable representation for the given MixDevice.
+ * The default implementation creates a label
+ */
+ virtual QWidget* add(MixDevice *);
+
+ /**
+ * Popup stuff
+ */
+ virtual KPopupMenu* getPopup();
+ virtual void popupReset();
+ virtual void showContextMenu();
+
+ Mixer* getMixer();
+
+ /**
+ * Contains the widgets for the _mixSet. There is a 1:1 relationship, which means:
+ * _mdws[i] is the Widget for the MixDevice _mixSet[i].
+ * Hint: The new ViewSurround class shows that a 1:1 relationship does not work in a general scenario.
+ * I actually DID expect this. The solution is unclear yet, probably there will be a virtual mapper method.
+ */
+ QPtrList<QWidget> _mdws; // this obsoletes the former Channel class
+
+ QString caption() const { return _caption; }
+
+protected:
+ void init();
+
+ Mixer *_mixer;
+ MixSet *_mixSet;
+ KPopupMenu *_popMenu;
+ KActionCollection* _actions;
+ ViewFlags _vflags;
+
+public slots:
+ virtual void refreshVolumeLevels();
+ virtual void configureView();
+ void toggleMenuBarSlot();
+
+protected slots:
+ void mousePressEvent( QMouseEvent *e );
+
+signals:
+ void toggleMenuBar();
+
+private:
+ QString _caption;
+};
+
+#endif
+
diff --git a/kmix/viewdockareapopup.cpp b/kmix/viewdockareapopup.cpp
new file mode 100644
index 00000000..b08138f7
--- /dev/null
+++ b/kmix/viewdockareapopup.cpp
@@ -0,0 +1,206 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewdockareapopup.h"
+
+// Qt
+#include <qwidget.h>
+#include <qevent.h>
+#include <qlayout.h>
+#include <qframe.h>
+#include <qpushbutton.h>
+#include <qdatetime.h>
+
+// KDE
+#include <kdebug.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <klocale.h>
+
+// KMix
+#include "mdwslider.h"
+#include "mixer.h"
+#include "kmixdockwidget.h"
+
+// !! Do NOT remove or mask out "WType_Popup"
+// Users will not be able to close the Popup without opening the KMix main window then.
+// See Bug #93443, #96332 and #96404 for further details. -- esken
+ViewDockAreaPopup::ViewDockAreaPopup(QWidget* parent, const char* name, Mixer* mixer, ViewBase::ViewFlags vflags, KMixDockWidget *dockW )
+ : ViewBase(parent, name, QString::null, mixer, WStyle_Customize | WType_Popup | Qt::WStyle_DialogBorder, vflags), _mdw(0), _dock(dockW)
+{
+ QBoxLayout *layout = new QHBoxLayout( this );
+ _frame = new QFrame( this );
+ layout->addWidget( _frame );
+
+ _frame->setFrameStyle( QFrame::PopupPanel | QFrame::Raised );
+ _frame->setLineWidth( 1 );
+
+ _layoutMDW = new QGridLayout( _frame, 1, 1, 2, 1, "KmixPopupLayout" );
+ _hideTimer = new QTime();
+ init();
+}
+
+ViewDockAreaPopup::~ViewDockAreaPopup() {
+}
+
+
+
+void ViewDockAreaPopup::mousePressEvent(QMouseEvent *)
+{
+// kdDebug() << "Teste pres mouse" << endl;
+ /**
+ Hide the popup:
+ This should work automatically, when the user clicks outside the bounds of this popup:
+ Alas - it does not work.
+ Why it does not work, I do not know: this->isPopup() returns "true", so Qt should
+ properly take care of it in QWidget.
+ */
+ if ( ! this->hasMouse() ) {
+ _hideTimer->start();
+ hide(); // needed!
+ }
+ return;
+}
+
+bool ViewDockAreaPopup::justHidden()
+{
+ return _hideTimer->elapsed() < 300;
+}
+
+void ViewDockAreaPopup::wheelEvent ( QWheelEvent * e ) {
+ // Pass wheel event from "border widget" to child
+ if ( _mdw != 0 ) {
+ QApplication::sendEvent( _mdw, e);
+ }
+}
+
+MixDevice* ViewDockAreaPopup::dockDevice()
+{
+ return _dockDevice;
+}
+
+
+void ViewDockAreaPopup::showContextMenu()
+{
+ // no right-button-menu on "dock area popup"
+ return;
+}
+
+
+void ViewDockAreaPopup::setMixSet(MixSet *)
+{
+ // kdDebug(67100) << "ViewDockAreaPopup::setMixSet()\n";
+ // This implementation of setMixSet() is a bit "exotic". But I will leave it like this, until I implement
+ // a configuration option for "what device to show on the dock area"
+ _dockDevice = _mixer->masterDevice();
+ if ( _dockDevice == 0 ) {
+ // If we have no mixer device, we will take the first available mixer device
+ _dockDevice = (*_mixer)[0];
+ }
+ _mixSet->append(_dockDevice);
+}
+
+QWidget* ViewDockAreaPopup::add(MixDevice *md)
+{
+ _mdw =
+ new MDWSlider(
+ _mixer, // the mixer for this device
+ md, // only 1 device. This is actually _dockDevice
+ true, // Show Mute LED
+ false, // Show Record LED
+ false, // Small
+ Qt::Vertical, // Direction: only 1 device, so doesn't matter
+ _frame, // parent
+ 0, // Is "NULL", so that there is no RMB-popup
+ _dockDevice->name().latin1() );
+ _layoutMDW->addItem( new QSpacerItem( 5, 20 ), 0, 2 );
+ _layoutMDW->addItem( new QSpacerItem( 5, 20 ), 0, 0 );
+ _layoutMDW->addWidget( _mdw, 0, 1 );
+
+ // Add button to show main panel
+ _showPanelBox = new QPushButton( i18n("Mixer"), _frame, "MixerPanel" );
+ connect ( _showPanelBox, SIGNAL( clicked() ), SLOT( showPanelSlot() ) );
+ _layoutMDW->addMultiCellWidget( _showPanelBox, 1, 1, 0, 2 );
+
+ return _mdw;
+}
+
+int ViewDockAreaPopup::count()
+{
+ return ( _mixSet->count() );
+}
+
+int ViewDockAreaPopup::advice() {
+ if ( _dockDevice != 0 ) {
+ // I could also evaluate whether we have a "sensible" device available.
+ // For example
+ // 100 : "master volume"
+ // 100 : "PCM"
+ // 50 : "CD"
+ // 0 : all other devices
+ return 100;
+ }
+ else {
+ return 0;
+ }
+}
+
+QSize ViewDockAreaPopup::sizeHint() const {
+ // kdDebug(67100) << "ViewDockAreaPopup::sizeHint(): NewSize is " << _mdw->sizeHint() << "\n";
+ return( _mdw->sizeHint() );
+}
+
+void ViewDockAreaPopup::constructionFinished() {
+ // kdDebug(67100) << "ViewDockAreaPopup::constructionFinished()\n";
+
+ _mdw->move(0,0);
+ _mdw->show();
+ _mdw->resize(_mdw->sizeHint() );
+ resize(sizeHint());
+
+}
+
+
+void ViewDockAreaPopup::refreshVolumeLevels() {
+ // kdDebug(67100) << "ViewDockAreaPopup::refreshVolumeLevels()\n";
+ QWidget* mdw = _mdws.first();
+ if ( mdw == 0 ) {
+ kdError(67100) << "ViewDockAreaPopup::refreshVolumeLevels(): mdw == 0\n";
+ // sanity check (normally the lists are set up correctly)
+ }
+ else {
+ if ( mdw->inherits("MDWSlider")) {
+ static_cast<MDWSlider*>(mdw)->update();
+ }
+ else {
+ kdError(67100) << "ViewDockAreaPopup::refreshVolumeLevels(): mdw is not slider\n";
+ // no slider. Cannot happen in theory => skip it
+ }
+ }
+}
+
+void ViewDockAreaPopup::showPanelSlot() {
+ _dock->toggleActive();
+ _dock->_dockAreaPopup->hide();
+}
+
+#include "viewdockareapopup.moc"
+
diff --git a/kmix/viewdockareapopup.h b/kmix/viewdockareapopup.h
new file mode 100644
index 00000000..4205e831
--- /dev/null
+++ b/kmix/viewdockareapopup.h
@@ -0,0 +1,57 @@
+#ifndef ViewDockAreaPopup_h
+#define ViewDockAreaPopup_h
+
+#include "viewbase.h"
+
+class QMouseEvent;
+class QGridLayout;
+class QWidget;
+class QPushButton;
+
+class Mixer;
+class KMixDockWidget;
+class MixDeviceWidget;
+class MixDevice;
+class QFrame;
+class QTime;
+
+class ViewDockAreaPopup : public ViewBase
+{
+ Q_OBJECT
+public:
+ ViewDockAreaPopup(QWidget* parent, const char* name, Mixer* mixer, ViewBase::ViewFlags vflags, KMixDockWidget *dockW);
+ ~ViewDockAreaPopup();
+ MixDevice* dockDevice();
+
+ virtual int count();
+ virtual int advice();
+ virtual void setMixSet(MixSet *mixset);
+ virtual QWidget* add(MixDevice *mdw);
+ virtual void constructionFinished();
+ virtual void refreshVolumeLevels();
+ virtual void showContextMenu();
+
+ QSize sizeHint() const;
+ bool justHidden();
+
+protected:
+ MixDeviceWidget *_mdw;
+ KMixDockWidget *_dock;
+ MixDevice *_dockDevice;
+ QPushButton *_showPanelBox;
+
+ void mousePressEvent(QMouseEvent *e);
+ void wheelEvent ( QWheelEvent * e );
+
+private:
+ QGridLayout* _layoutMDW;
+ QFrame *_frame;
+ QTime *_hideTimer;
+
+private slots:
+ void showPanelSlot();
+
+};
+
+#endif
+
diff --git a/kmix/viewgrid.cpp b/kmix/viewgrid.cpp
new file mode 100644
index 00000000..0a995ac8
--- /dev/null
+++ b/kmix/viewgrid.cpp
@@ -0,0 +1,212 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewgrid.h"
+
+// Qt
+#include <qwidget.h>
+
+// KDE
+#include <kdebug.h>
+
+// KMix
+#include "mdwenum.h"
+#include "mdwslider.h"
+#include "mdwswitch.h"
+#include "mixer.h"
+
+/**
+ */
+ViewGrid::ViewGrid(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags)
+ : ViewBase(parent, name, caption, mixer, WStyle_Customize|WStyle_NoBorder, vflags)
+{
+ m_spacingHorizontal = 5;
+ m_spacingVertical = 5;
+
+ if ( _vflags & ViewBase::Vertical ) {
+ //_layoutMDW = new QVBoxLayout(this);
+ }
+ else {
+ //_layoutMDW = new QHBoxLayout(this);
+ }
+ init();
+}
+
+ViewGrid::~ViewGrid() {
+}
+
+void ViewGrid::setMixSet(MixSet *mixset)
+{
+ MixDevice* md;
+ int testCounter = 0;
+ for ( md = mixset->first(); md != 0; md = mixset->next() ) {
+ if (testCounter<8) {
+ _mixSet->append(md);
+ }
+ testCounter++;
+ }
+}
+
+int ViewGrid::count()
+{
+ return ( _mixSet->count() );
+}
+
+int ViewGrid::advice() {
+ if ( _mixSet->count() > 0 ) {
+ // The standard input and output views are always advised, if there are devices in it
+ return 100;
+ }
+ else {
+ return 0;
+ }
+}
+
+QWidget* ViewGrid::add(MixDevice *md)
+{
+ MixDeviceWidget *mdw = 0;
+ if ( md->isEnum() ) {
+ Qt::Orientation orientation = (_vflags & ViewBase::Vertical) ? Qt::Horizontal : Qt::Vertical;
+ mdw = new MDWEnum(
+ _mixer, // the mixer for this device
+ md, // MixDevice (parameter)
+ orientation, // Orientation
+ this, // parent
+ this, // View widget
+ md->name().latin1()
+ );
+ } // an enum
+ else if (md->isSwitch()) {
+ Qt::Orientation orientation = (_vflags & ViewBase::Vertical) ? Qt::Horizontal : Qt::Vertical;
+ mdw =
+ new MDWSwitch(
+ _mixer, // the mixer for this device
+ md, // MixDevice (parameter)
+ false, // Small
+ orientation, // Orientation
+ this, // parent
+ this, // View widget
+ md->name().latin1()
+ );
+ } // a switch
+
+ else { // must be a slider
+ Qt::Orientation orientation = (_vflags & ViewBase::Vertical) ? Qt::Horizontal : Qt::Vertical;
+ mdw =
+ new MDWSlider(
+ _mixer, // the mixer for this device
+ md, // MixDevice (parameter)
+ true, // Show Mute LED
+ true, // Show Record LED
+ false, // Small
+ orientation, // Orientation
+ this, // parent
+ this, // View widget
+ md->name().latin1()
+ );
+ }
+ return mdw;
+}
+
+QSize ViewGrid::sizeHint() const {
+ // kdDebug(67100) << "ViewGrid::sizeHint(): NewSize is " << _layoutMDW->sizeHint() << "\n";
+ return( m_sizeHint);
+}
+
+void ViewGrid::constructionFinished() {
+ //_layoutMDW->activate();
+
+ // do a manual layout
+ configurationUpdate();
+}
+
+void ViewGrid::refreshVolumeLevels() {
+ // kdDebug(67100) << "ViewGrid::refreshVolumeLevels()\n";
+
+ m_sizeHint.setWidth (0);
+ m_sizeHint.setHeight(0);
+
+ m_testingX = 0;
+ m_testingY = 0;
+
+ QWidget *mdw = _mdws.first();
+ MixDevice* md;
+ for ( md = _mixSet->first(); md != 0; md = _mixSet->next() ) {
+ if ( mdw == 0 ) {
+ kdError(67100) << "ViewGrid::refreshVolumeLevels(): mdw == 0\n";
+ break; // sanity check (normally the lists are set up correctly)
+ }
+ else {
+ if ( mdw->inherits("MDWSlider")) {
+ //kdDebug(67100) << "ViewGrid::refreshVolumeLevels(): updating\n";
+ // a slider, fine. Lets update its value
+ static_cast<MDWSlider*>(mdw)->update();
+ }
+ else if ( mdw->inherits("MDWSwitch")) {
+ //kdDebug(67100) << "ViewGrid::refreshVolumeLevels(): updating\n";
+ // a slider, fine. Lets update its value
+ static_cast<MDWSwitch*>(mdw)->update();
+ }
+ else if ( mdw->inherits("MDWEnum")) {
+ static_cast<MDWEnum*>(mdw)->update();
+ }
+ else {
+ kdError(67100) << "ViewGrid::refreshVolumeLevels(): mdw is unknown/unsupported type\n";
+ // no slider. Cannot happen in theory => skip it
+ }
+ }
+ mdw = _mdws.next();
+ }
+}
+
+/**
+ This implementation makes sure the Grid's geometry is updated
+ after hiding/showing channels.
+*/
+void ViewGrid::configurationUpdate() {
+ m_sizeHint.setWidth (0);
+ m_sizeHint.setHeight(0);
+
+ m_testingX = 0;
+ m_testingY = 0;
+
+ for (QWidget *qw = _mdws.first(); qw !=0; qw = _mdws.next() ) {
+
+ if ( qw->inherits("MixDeviceWidget")) {
+ MixDeviceWidget* mdw = static_cast<MixDeviceWidget*>(qw);
+ int xPos = m_testingX * m_spacingHorizontal;
+ int yPos = m_testingY * m_spacingVertical ;
+ mdw->move( xPos, yPos );
+ mdw->resize( mdw->sizeHint() );
+ int xMax = xPos + mdw->width() ; if ( xMax > m_sizeHint.width() ) m_sizeHint.setWidth(xMax);
+ int yMax = yPos + mdw->height(); if ( yMax > m_sizeHint.height() ) m_sizeHint.setHeight(yMax);
+
+ m_testingX += 5;
+ if ( m_testingX > 50 ) {
+ m_testingY += 10;
+ m_testingX = 0;
+ }
+ } // inherits MixDeviceWidget
+ } // for all MDW's
+}
+
+
+#include "viewgrid.moc"
diff --git a/kmix/viewgrid.h b/kmix/viewgrid.h
new file mode 100644
index 00000000..f57cdc59
--- /dev/null
+++ b/kmix/viewgrid.h
@@ -0,0 +1,42 @@
+#ifndef ViewGrid_h
+#define ViewGrid_h
+
+class QBoxLayout;
+#include "qsize.h"
+class QWidget;
+
+class Mixer;
+#include "viewbase.h"
+
+class ViewGrid : public ViewBase
+{
+ Q_OBJECT
+public:
+ ViewGrid(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags);
+ ~ViewGrid();
+
+ virtual int count();
+ virtual int advice();
+ virtual void setMixSet(MixSet *mixset);
+ virtual QWidget* add(MixDevice *mdw);
+ virtual void configurationUpdate();
+ virtual void constructionFinished();
+
+ QSize sizeHint() const;
+
+public slots:
+ virtual void refreshVolumeLevels();
+
+private:
+ unsigned int m_spacingHorizontal;
+ unsigned int m_spacingVertical;
+
+ // m_maxX and m_maxY are the highest coordiantes encountered
+ QSize m_sizeHint;
+
+ unsigned int m_testingX;
+ unsigned int m_testingY;
+};
+
+#endif
+
diff --git a/kmix/viewinput.cpp b/kmix/viewinput.cpp
new file mode 100644
index 00000000..646e94d6
--- /dev/null
+++ b/kmix/viewinput.cpp
@@ -0,0 +1,50 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewinput.h"
+#include <qwidget.h>
+
+#include "mixer.h"
+#include "mixdevicewidget.h"
+
+ViewInput::ViewInput(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags)
+ : ViewSliders(parent, name, caption, mixer, vflags)
+{
+ init();
+ connect ( _mixer, SIGNAL(newRecsrc()) , this, SLOT(refreshVolumeLevels()) ); // only the input widget has record sources
+}
+
+ViewInput::~ViewInput() {
+}
+
+void ViewInput::setMixSet(MixSet *mixset)
+{
+ MixDevice* md;
+ for ( md = mixset->first(); md != 0; md = mixset->next() ) {
+ if ( md->isRecordable() && ! md->isSwitch() && ! md->isEnum() ) {
+ _mixSet->append(md);
+ }
+ else {
+ }
+ }
+}
+
+#include "viewinput.moc"
diff --git a/kmix/viewinput.h b/kmix/viewinput.h
new file mode 100644
index 00000000..1b5d5be8
--- /dev/null
+++ b/kmix/viewinput.h
@@ -0,0 +1,19 @@
+#ifndef ViewInput_h
+#define ViewInput_h
+
+#include "viewsliders.h"
+class QWidget;
+class Mixer;
+
+class ViewInput : public ViewSliders
+{
+ Q_OBJECT
+public:
+ ViewInput(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags);
+ ~ViewInput();
+
+ virtual void setMixSet(MixSet *mixset);
+};
+
+#endif
+
diff --git a/kmix/viewoutput.cpp b/kmix/viewoutput.cpp
new file mode 100644
index 00000000..81c850b1
--- /dev/null
+++ b/kmix/viewoutput.cpp
@@ -0,0 +1,50 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewoutput.h"
+#include <qwidget.h>
+
+#include "mixer.h"
+#include "mixdevicewidget.h"
+
+ViewOutput::ViewOutput(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags)
+ : ViewSliders(parent, name, caption, mixer, vflags)
+{
+ init();
+}
+
+ViewOutput::~ViewOutput() {
+}
+
+void ViewOutput::setMixSet(MixSet *mixset)
+{
+ MixDevice* md;
+ for ( md = mixset->first(); md != 0; md = mixset->next() ) {
+ if ( ! md->isRecordable() && ! md->isSwitch() && ! md->isEnum()) {
+ _mixSet->append(md);
+ }
+ else {
+ }
+ }
+}
+
+
+#include "viewoutput.moc"
diff --git a/kmix/viewoutput.h b/kmix/viewoutput.h
new file mode 100644
index 00000000..439aa7d8
--- /dev/null
+++ b/kmix/viewoutput.h
@@ -0,0 +1,19 @@
+#ifndef ViewOutput_h
+#define ViewOutput_h
+
+#include "viewsliders.h"
+class QWidget;
+class Mixer;
+
+class ViewOutput : public ViewSliders
+{
+ Q_OBJECT
+public:
+ ViewOutput(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags);
+ ~ViewOutput();
+
+ virtual void setMixSet(MixSet *mixset);
+};
+
+#endif
+
diff --git a/kmix/viewsliders.cpp b/kmix/viewsliders.cpp
new file mode 100644
index 00000000..cb9b441e
--- /dev/null
+++ b/kmix/viewsliders.cpp
@@ -0,0 +1,140 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewsliders.h"
+
+// Qt
+#include <qlayout.h>
+#include <qwidget.h>
+
+// KDE
+#include <kdebug.h>
+
+// KMix
+#include "mdwslider.h"
+#include "mixer.h"
+
+/**
+ * Don't instanciate objects of this class directly. It won't work
+ * correctly because init() does not get called.
+ * See ViewInput and ViewOutput for "real" implementations.
+ */
+ViewSliders::ViewSliders(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags)
+ : ViewBase(parent, name, caption, mixer, WStyle_Customize|WStyle_NoBorder, vflags)
+{
+ if ( _vflags & ViewBase::Vertical ) {
+ _layoutMDW = new QVBoxLayout(this);
+ }
+ else {
+ _layoutMDW = new QHBoxLayout(this);
+ }
+ /*
+ * Do not call init(). Call init() only for "end usage" classes.
+ * Otherwise setMixSet() will be called multiple times.
+ * Yes, this is rotten ... I will think of something smart later !!
+ * Perhaps I can have a boolean "init-has-run" instance variable.
+ */
+ //init();
+}
+
+ViewSliders::~ViewSliders() {
+}
+
+void ViewSliders::setMixSet(MixSet *mixset)
+{
+ MixDevice* md;
+ for ( md = mixset->first(); md != 0; md = mixset->next() ) {
+ if ( (! md->isSwitch()) && ( ! md->isEnum() ) ) {
+ _mixSet->append(md);
+ }
+ }
+}
+
+int ViewSliders::count()
+{
+ return ( _mixSet->count() );
+}
+
+int ViewSliders::advice() {
+ if ( _mixSet->count() > 0 ) {
+ // The standard input and output views are always advised, if there are devices in it
+ return 100;
+ }
+ else {
+ return 0;
+ }
+}
+
+QWidget* ViewSliders::add(MixDevice *md)
+{
+ Qt::Orientation orientation = (_vflags & ViewBase::Vertical) ? Qt::Horizontal : Qt::Vertical;
+ MixDeviceWidget *mdw =
+ new MDWSlider(
+ _mixer, // the mixer for this device
+ md, // MixDevice (parameter)
+ true, // Show Mute LED
+ true, // Show Record LED
+ false, // Small
+ orientation, // Orientation
+ this, // parent
+ this, // View widget
+ md->name().latin1()
+ );
+ _layoutMDW->add(mdw);
+ return mdw;
+}
+
+QSize ViewSliders::sizeHint() const {
+ // kdDebug(67100) << "ViewSliders::sizeHint(): NewSize is " << _layoutMDW->sizeHint() << "\n";
+ return( _layoutMDW->sizeHint() );
+}
+
+void ViewSliders::constructionFinished() {
+ _layoutMDW->activate();
+}
+
+void ViewSliders::refreshVolumeLevels() {
+ // kdDebug(67100) << "ViewSliders::refreshVolumeLevels()\n";
+
+ QWidget *mdw = _mdws.first();
+ MixDevice* md;
+ for ( md = _mixSet->first(); md != 0; md = _mixSet->next() ) {
+ if ( mdw == 0 ) {
+ kdError(67100) << "ViewSliders::refreshVolumeLevels(): mdw == 0\n";
+ break; // sanity check (normally the lists are set up correctly)
+ }
+ else {
+ if ( mdw->inherits("MDWSlider")) {
+ //kdDebug(67100) << "ViewSliders::refreshVolumeLevels(): updating\n";
+ // a slider, fine. Lets update its value
+ static_cast<MDWSlider*>(mdw)->update();
+ }
+ else {
+ kdError(67100) << "ViewSliders::refreshVolumeLevels(): mdw is not slider\n";
+ // no slider. Cannot happen in theory => skip it
+ }
+ }
+ mdw = _mdws.next();
+ }
+}
+
+
+#include "viewsliders.moc"
diff --git a/kmix/viewsliders.h b/kmix/viewsliders.h
new file mode 100644
index 00000000..ea108ee3
--- /dev/null
+++ b/kmix/viewsliders.h
@@ -0,0 +1,33 @@
+#ifndef ViewSliders_h
+#define ViewSliders_h
+
+class QBoxLayout;
+class QWidget;
+
+class Mixer;
+#include "viewbase.h"
+
+class ViewSliders : public ViewBase
+{
+ Q_OBJECT
+public:
+ ViewSliders(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags);
+ ~ViewSliders();
+
+ virtual int count();
+ virtual int advice();
+ virtual void setMixSet(MixSet *mixset);
+ virtual QWidget* add(MixDevice *mdw);
+ virtual void constructionFinished();
+
+ QSize sizeHint() const;
+
+public slots:
+ virtual void refreshVolumeLevels();
+
+private:
+ QBoxLayout* _layoutMDW;
+};
+
+#endif
+
diff --git a/kmix/viewsurround.cpp b/kmix/viewsurround.cpp
new file mode 100644
index 00000000..a5eb7068
--- /dev/null
+++ b/kmix/viewsurround.cpp
@@ -0,0 +1,270 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewsurround.h"
+
+// Qt
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qwidget.h>
+
+// KDE
+#include <kdebug.h>
+#include <kiconloader.h>
+
+// KMix
+#include "kmixtoolbox.h"
+#include "mdwslider.h"
+#include "mixer.h"
+
+/**
+ * Demonstration verion of a "surround view"
+ * Not really usable right now.
+ */
+ViewSurround::ViewSurround(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags)
+ : ViewBase(parent, name, caption, mixer, WStyle_Customize|WStyle_NoBorder, vflags)
+{
+ _mdSurroundFront = 0;
+ _mdSurroundBack = 0;
+ _layoutMDW = new QHBoxLayout(this);
+ _layoutMDW->setMargin(8);
+ // Create switch buttonGroup
+ if ( _vflags & ViewBase::Vertical ) {
+ _layoutSliders = new QVBoxLayout(_layoutMDW);
+ }
+ else {
+ _layoutSliders = new QHBoxLayout(_layoutMDW);
+ }
+ _layoutSurround = new QGridLayout(_layoutMDW,3,5);
+ // _layoutMDW->setMargin(8);
+ init();
+}
+
+ViewSurround::~ViewSurround() {
+}
+
+void ViewSurround::setMixSet(MixSet *mixset)
+{
+ MixDevice* md;
+ for ( md = mixset->first(); md != 0; md = mixset->next() ) {
+ if ( ! md->isSwitch() ) {
+ switch ( md->type() ) {
+ case MixDevice::VOLUME:
+ case MixDevice::SURROUND:
+ case MixDevice::SURROUND_BACK:
+ case MixDevice::SURROUND_LFE:
+ case MixDevice::SURROUND_CENTERFRONT:
+ case MixDevice::SURROUND_CENTERBACK:
+ case MixDevice::AC97:
+ _mixSet->append(md);
+ break;
+ default:
+ // we are not interested in other channels
+ break;
+ } // switch(type)
+ } // !is_switch()
+ } // for
+}
+
+int ViewSurround::count()
+{
+ return ( _mixSet->count() );
+}
+
+int ViewSurround::advice() {
+ if ( _mixSet->count() > 0 ) {
+ // The standard input and output views are always advised, if there are devices in it
+ return 100;
+ }
+ else {
+ return 0;
+ }
+}
+
+QWidget* ViewSurround::add(MixDevice *md)
+{
+ bool small = false;
+ Qt::Orientation orientation = Qt::Vertical;
+ switch ( md->type() ) {
+ case MixDevice::VOLUME:
+ _mdSurroundFront = md;
+ small = true;
+ break;
+ case MixDevice::SURROUND_BACK:
+ _mdSurroundBack = md;
+ small = true;
+ break;
+ case MixDevice::SURROUND_LFE:
+ orientation = Qt::Horizontal;
+ small = true;
+ break;
+ case MixDevice::SURROUND_CENTERFRONT:
+ orientation = Qt::Horizontal;
+ small = true;
+ break;
+ case MixDevice::SURROUND_CENTERBACK:
+ orientation = Qt::Horizontal;
+ small = true;
+ break;
+
+ default:
+ small = false;
+ // these are the sliders on the left side of the surround View
+ orientation = (_vflags & ViewBase::Vertical) ? Qt::Horizontal : Qt::Vertical;
+ } // switch(type)
+
+ MixDeviceWidget *mdw = createMDW(md, small, orientation);
+
+ switch ( md->type() ) {
+ case MixDevice::VOLUME:
+ _layoutSurround->addWidget(mdw ,0,0, Qt::AlignBottom | Qt::AlignLeft);
+ break;
+
+ case MixDevice::SURROUND_BACK:
+ _layoutSurround->addWidget(mdw ,2,0, Qt::AlignTop | Qt::AlignLeft);
+ break;
+ case MixDevice::SURROUND_LFE:
+ _layoutSurround->addWidget(mdw,1,3, Qt::AlignVCenter | Qt::AlignRight ); break;
+ break;
+ case MixDevice::SURROUND_CENTERFRONT:
+ _layoutSurround->addWidget(mdw,0,2, Qt::AlignTop | Qt::AlignHCenter); break;
+ break;
+ case MixDevice::SURROUND_CENTERBACK:
+ _layoutSurround->addWidget(mdw,2,2, Qt::AlignBottom | Qt::AlignHCenter); break;
+ break;
+
+ case MixDevice::SURROUND:
+ case MixDevice::AC97:
+ default:
+ // Add as slider to the layout on the left side
+ _layoutSliders->add(mdw);
+ break;
+ } // switch(type)
+
+ return mdw;
+}
+
+QSize ViewSurround::sizeHint() const {
+ // kdDebug(67100) << "ViewSurround::sizeHint(): NewSize is " << _layoutMDW->sizeHint() << "\n";
+ return( _layoutMDW->sizeHint() );
+}
+
+void ViewSurround::constructionFinished() {
+ QLabel* personLabel = new QLabel("Listener", this);
+ QPixmap icon = UserIcon( "Listener" );
+ if ( ! icon.isNull()) personLabel->setPixmap(icon);
+ personLabel->setLineWidth( 4 );
+ personLabel->setMidLineWidth( 3 );
+ personLabel->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ int rowOfSpeaker = 0;
+ if ( _mdSurroundBack != 0 ) {
+ // let the speaker "sit" in the rear of the room, if there is
+ // rear speaker support in this sound card
+ rowOfSpeaker = 1;
+ }
+ _layoutSurround->addWidget(personLabel ,rowOfSpeaker, 2, Qt::AlignHCenter | Qt::AlignVCenter);
+
+ if ( _mdSurroundFront != 0 ) {
+ MixDeviceWidget *mdw = createMDW(_mdSurroundFront, true, Qt::Vertical);
+ _layoutSurround->addWidget(mdw,0,4, Qt::AlignBottom | Qt::AlignRight);
+ _mdws.append(mdw);
+
+ QLabel* speakerIcon = new QLabel("Speaker", this);
+ icon = UserIcon( "SpeakerFrontLeft" );
+ if ( ! icon.isNull()) speakerIcon->setPixmap(icon);
+ _layoutSurround->addWidget(speakerIcon,0,1, Qt::AlignTop | Qt::AlignLeft);
+
+ speakerIcon = new QLabel("Speaker", this);
+ icon = UserIcon( "SpeakerFrontRight" );
+ if ( ! icon.isNull()) speakerIcon->setPixmap(icon);
+ _layoutSurround->addWidget(speakerIcon,0,3, Qt::AlignTop | Qt::AlignRight);
+
+ }
+
+ if ( _mdSurroundBack != 0 ) {
+ MixDeviceWidget *mdw = createMDW(_mdSurroundBack, true, Qt::Vertical);
+ _layoutSurround->addWidget(mdw,2,4, Qt::AlignTop | Qt::AlignRight);
+ _mdws.append(mdw);
+
+ QLabel* speakerIcon = new QLabel("Speaker", this);
+ icon = UserIcon( "SpeakerRearLeft" );
+ if ( ! icon.isNull()) speakerIcon->setPixmap(icon);
+ _layoutSurround->addWidget(speakerIcon,2,1, Qt::AlignBottom | Qt::AlignLeft);
+
+ speakerIcon = new QLabel("Speaker", this);
+ icon = UserIcon( "SpeakerRearRight" );
+ if ( ! icon.isNull()) speakerIcon->setPixmap(icon);
+ _layoutSurround->addWidget(speakerIcon,2,3, Qt::AlignBottom | Qt::AlignRight);
+
+
+ }
+
+ // !! just for the demo version
+ KMixToolBox::setIcons (_mdws, true);
+ KMixToolBox::setLabels(_mdws, true);
+ KMixToolBox::setTicks (_mdws, true);
+
+ _layoutMDW->activate();
+}
+
+void ViewSurround::refreshVolumeLevels() {
+ // kdDebug(67100) << "ViewSurround::refreshVolumeLevels()\n";
+
+ QWidget *mdw = _mdws.first();
+ MixDevice* md;
+ for ( md = _mixSet->first(); md != 0; md = _mixSet->next() ) {
+ if ( mdw == 0 ) {
+ kdError(67100) << "ViewSurround::refreshVolumeLevels(): mdw == 0\n";
+ break; // sanity check (normally the lists are set up correctly)
+ }
+ else {
+ if ( mdw->inherits("MDWSlider")) {
+ //kdDebug(67100) << "ViewSurround::refreshVolumeLevels(): updating\n";
+ // a slider, fine. Lets update its value
+ static_cast<MDWSlider*>(mdw)->update();
+ }
+ else {
+ kdError(67100) << "ViewSurround::refreshVolumeLevels(): mdw is not slider\n";
+ // no slider. Cannot happen in theory => skip it
+ }
+ }
+ mdw = _mdws.next();
+ }
+}
+
+
+MixDeviceWidget* ViewSurround::createMDW(MixDevice *md, bool small, Qt::Orientation orientation)
+{
+ MixDeviceWidget* mdw = new MDWSlider(
+ _mixer, // the mixer for this device
+ md, // MixDevice (parameter)
+ false, // Show Mute LED
+ false, // Show Record LED
+ small, // Small
+ orientation, // Orientation
+ this, // parent
+ this, // View widget
+ md->name().latin1()
+ );
+ return mdw;
+}
+
+#include "viewsurround.moc"
diff --git a/kmix/viewsurround.h b/kmix/viewsurround.h
new file mode 100644
index 00000000..1427f41d
--- /dev/null
+++ b/kmix/viewsurround.h
@@ -0,0 +1,42 @@
+#ifndef ViewSurround_h
+#define ViewSurround_h
+
+class QBoxLayout;
+class QGridLayout;
+class QWidget;
+
+class MixDevice;
+class MixDeviceWidget;
+class Mixer;
+#include "viewbase.h"
+
+class ViewSurround : public ViewBase
+{
+ Q_OBJECT
+public:
+ ViewSurround(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags);
+ ~ViewSurround();
+
+ virtual int count();
+ virtual int advice();
+ virtual void setMixSet(MixSet *mixset);
+ virtual QWidget* add(MixDevice *mdw);
+ virtual void constructionFinished();
+
+ QSize sizeHint() const;
+
+public slots:
+ virtual void refreshVolumeLevels();
+
+private:
+ MixDeviceWidget* createMDW(MixDevice *md, bool small, Qt::Orientation orientation);
+ MixDevice *_mdSurroundFront;
+ MixDevice *_mdSurroundBack;
+
+ QBoxLayout* _layoutMDW;
+ QBoxLayout* _layoutSliders;
+ QGridLayout* _layoutSurround;
+};
+
+#endif
+
diff --git a/kmix/viewswitches.cpp b/kmix/viewswitches.cpp
new file mode 100644
index 00000000..d5a9b60c
--- /dev/null
+++ b/kmix/viewswitches.cpp
@@ -0,0 +1,189 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "viewswitches.h"
+
+#include <qlayout.h>
+#include <qwidget.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "mdwswitch.h"
+#include "mdwenum.h"
+#include "mixer.h"
+
+ViewSwitches::ViewSwitches(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags)
+ : ViewBase(parent, name, caption, mixer, 0, vflags)
+{
+ // Create switch buttonGroup
+ if ( _vflags & ViewBase::Vertical ) {
+ _layoutMDW = new QVBoxLayout(this);
+ _layoutSwitch = new QVBoxLayout(_layoutMDW);
+ _layoutEnum = new QVBoxLayout(_layoutMDW); // always vertical!
+ }
+ else {
+ _layoutMDW = new QHBoxLayout(this);
+ _layoutSwitch = new QHBoxLayout(_layoutMDW);
+ // Place enums right from the switches: This is done, so that there will be no
+ // ugly space on the left side, when no Switch is shown.
+ // Actually it is not really clear yet, why there is empty space at all: There are 0 items in
+ // the _layoutEnum, so it might be a sizeHint() or some other subtle layout issue.
+ _layoutEnum = new QVBoxLayout(_layoutMDW);
+ }
+ init();
+}
+
+ViewSwitches::~ViewSwitches() {
+}
+
+void ViewSwitches::setMixSet(MixSet *mixset)
+{
+ MixDevice* md;
+ for ( md = mixset->first(); md != 0; md = mixset->next() ) {
+ if ( md->isSwitch() || md->isEnum() ) {
+ _mixSet->append(md);
+ }
+ else {
+ }
+ }
+}
+
+
+int ViewSwitches::count()
+{
+ return ( _mixSet->count() );
+}
+
+int ViewSwitches::advice() {
+ if ( _mixSet->count() > 0 ) {
+ // The Switch Views is always advised, if there are devices in it
+ return 100;
+ }
+ else {
+ return 0;
+ }
+}
+
+QWidget* ViewSwitches::add(MixDevice *md)
+{
+ MixDeviceWidget *mdw;
+
+ if ( md->isEnum() ) {
+ Qt::Orientation orientation = (_vflags & ViewBase::Vertical) ? Qt::Horizontal : Qt::Vertical;
+ mdw = new MDWEnum(
+ _mixer, // the mixer for this device
+ md, // MixDevice (parameter)
+ orientation, // Orientation
+ this, // parent
+ this, // View widget
+ md->name().latin1()
+ );
+ _layoutEnum->add(mdw);
+ } // an enum
+ else {
+ // must be a switch
+ Qt::Orientation orientation = (_vflags & ViewBase::Vertical) ? Qt::Horizontal : Qt::Vertical;
+ mdw =
+ new MDWSwitch(
+ _mixer, // the mixer for this device
+ md, // MixDevice (parameter)
+ false, // Small
+ orientation, // Orientation
+ this, // parent
+ this, // View widget
+ md->name().latin1()
+ );
+ _layoutSwitch->add(mdw);
+ } // a switch
+
+ return mdw;
+}
+
+QSize ViewSwitches::sizeHint() const {
+ //kdDebug(67100) << "ViewSwitches::sizeHint(): NewSize is " << _layoutMDW->sizeHint() << "\n";
+ return( _layoutMDW->sizeHint() );
+}
+
+void ViewSwitches::constructionFinished() {
+ configurationUpdate(); // also does _layoutMDW->activate();
+}
+
+void ViewSwitches::refreshVolumeLevels() {
+ //kdDebug(67100) << "ViewSwitches::refreshVolumeLevels()\n";
+ QWidget *mdw = _mdws.first();
+ MixDevice* md;
+ for ( md = _mixSet->first(); md != 0; md = _mixSet->next() ) {
+ if ( mdw == 0 ) {
+ kdError(67100) << "ViewSwitches::refreshVolumeLevels(): mdw == 0\n";
+ break; // sanity check (normally the lists are set up correctly)
+ }
+ else {
+ if ( mdw->inherits("MDWSwitch")) {
+ //kdDebug(67100) << "ViewSwitches::refreshVolumeLevels(): updating\n";
+ // a slider, fine. Lets update its value
+ static_cast<MDWSwitch*>(mdw)->update();
+ }
+ else if ( mdw->inherits("MDWEnum")) {
+ static_cast<MDWEnum*>(mdw)->update();
+ }
+ else {
+ kdError(67100) << "ViewSwitches::refreshVolumeLevels(): mdw is not slider\n";
+ // no switch. Cannot happen in theory => skip it
+ // If I start putting other stuff in the switch tab, I will get a nice warning.
+ }
+ }
+ mdw = _mdws.next();
+ }
+}
+
+
+/**
+ This implementation makes sure the BackgroundMode's are properly updated
+ with their alternating colors after hiding/showing channels.
+*/
+void ViewSwitches::configurationUpdate() {
+ bool backGoundModeToggler = true;
+ for (QWidget *qw = _mdws.first(); qw !=0; qw = _mdws.next() ) {
+ if ( qw->inherits("MDWSwitch")) {
+ MixDeviceWidget* mdw = static_cast<MDWSwitch*>(qw);
+ if ( ! mdw->isDisabled() ) {
+ if ( backGoundModeToggler ) {
+ mdw->setBackgroundMode(PaletteBackground);
+ }
+ else {
+ // !! Should use KGlobalSettings::alternateBackgroundColor()
+ // or KGlobalSettings::calculateAlternateBackgroundColor() instead.
+ mdw->setBackgroundMode( PaletteBase );
+ }
+ backGoundModeToggler = !backGoundModeToggler;
+ } // ! isDisabled()
+ else {
+ //kdDebug(67100) << "ViewSwitches::configurationUpdate() ignoring diabled switch\n";
+ }
+ } // inherits("MDWSwitch")
+ }
+ _layoutMDW->activate();
+}
+
+
+#include "viewswitches.moc"
+
diff --git a/kmix/viewswitches.h b/kmix/viewswitches.h
new file mode 100644
index 00000000..043fce07
--- /dev/null
+++ b/kmix/viewswitches.h
@@ -0,0 +1,36 @@
+#ifndef ViewSwitches_h
+#define ViewSwitches_h
+
+class QLayout;
+class QWidget;
+
+class Mixer;
+#include "viewbase.h"
+
+class ViewSwitches : public ViewBase
+{
+ Q_OBJECT
+public:
+ ViewSwitches(QWidget* parent, const char* name, const QString & caption, Mixer* mixer, ViewBase::ViewFlags vflags);
+ ~ViewSwitches();
+
+ virtual int count();
+ virtual int advice();
+ virtual void setMixSet(MixSet *mixset);
+ virtual QWidget* add(MixDevice *mdw);
+ virtual void constructionFinished();
+ virtual void configurationUpdate();
+
+ QSize sizeHint() const;
+
+public slots:
+ virtual void refreshVolumeLevels();
+
+private:
+ QLayout* _layoutMDW;
+ QLayout* _layoutEnum;
+ QLayout* _layoutSwitch;
+};
+
+#endif
+
diff --git a/kmix/volume.cpp b/kmix/volume.cpp
new file mode 100644
index 00000000..20d056a4
--- /dev/null
+++ b/kmix/volume.cpp
@@ -0,0 +1,266 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ *
+ * Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+// for operator<<()
+#include <iostream>
+
+#include <kdebug.h>
+
+#include "volume.h"
+
+
+int Volume::_channelMaskEnum[10] =
+ { MLEFT, MRIGHT, MCENTER,
+ MREARLEFT, MREARRIGHT, MWOOFER,
+ MLEFTREC , MRIGHTREC ,
+ MCUSTOM1, MCUSTOM2
+ };
+
+Volume::Volume( ChannelMask chmask, long maxVolume, long minVolume, bool isCapture )
+{
+ init(chmask, maxVolume, minVolume, isCapture);
+}
+
+
+// @ compatiblity constructor
+Volume::Volume( int channels, long maxVolume ) {
+ if (channels == 1 ) {
+ init(Volume::MLEFT, maxVolume, 0, false);
+ }
+ else if (channels == 2) {
+ init(ChannelMask(Volume::MLEFT|Volume::MRIGHT), maxVolume, 0, false );
+ }
+ else {
+ init(ChannelMask(Volume::MLEFT|Volume::MRIGHT), maxVolume, 0, false );
+ kdError(67100) << "Warning: Multi-channel Volume object created with old constructor - this will not work fully\n";
+ }
+}
+
+Volume::Volume( const Volume &v )
+{
+ _chmask = v._chmask;
+ _maxVolume = v._maxVolume;
+ _minVolume = v._minVolume;
+ _muted = v._muted;
+ _isCapture = v._isCapture;
+ setVolume(v, (ChannelMask)v._chmask);
+
+ // kdDebug(67100) << "Volume::copy-constructor initialized " << v << "\n";
+}
+
+void Volume::init( ChannelMask chmask, long maxVolume, long minVolume, bool isCapture )
+{
+ for ( int i=0; i<= Volume::CHIDMAX; i++ ) {
+ _volumes[i] = 0;
+ }
+ _chmask = chmask;
+ _maxVolume = maxVolume;
+ _minVolume = minVolume;
+ _isCapture = isCapture;
+ _muted = false;
+}
+
+// @ compatibility
+void Volume::setAllVolumes(long vol)
+{
+ for ( int i=0; i<= Volume::CHIDMAX; i++ ) {
+ if ( (_channelMaskEnum[i]) & _chmask ) {
+ // we are supposed to set it
+ _volumes[i] = volrange(vol);
+ }
+ }
+}
+
+// @ compatibility
+void Volume::setVolume( ChannelID chid, long vol)
+{
+ if ( chid>=0 && chid<=Volume::CHIDMAX ) {
+ // accepted. we don't care if we support the channel,
+ // because there is NO good action we could take.
+ // Anyway: getVolume() on an unsupported channel will return 0 all the time
+ _volumes[chid] = volrange(vol);
+ }
+}
+
+/**
+ * Copy the volume elements contained in v to this Volume object.
+ * Only those elments are copied, that are supported in BOTH Volume objects.
+ */
+void Volume::setVolume(const Volume &v)
+{
+ setVolume(v, (ChannelMask)(v._chmask&_chmask) );
+}
+
+/**
+ * Copy the volume elements contained in v to this Volume object.
+ * Only those elments are copied, that are supported in BOTH Volume objects
+ * and match the ChannelMask given by chmask.
+ */
+void Volume::setVolume(const Volume &v, ChannelMask chmask) {
+ for ( int i=0; i<= Volume::CHIDMAX; i++ ) {
+ if ( _channelMaskEnum[i] & _chmask & (int)chmask ) {
+ // we are supposed to copy it
+ _volumes[i] = volrange(v._volumes[i]);
+ }
+ else {
+ // Safety first! Lets play safe here and put sane values in
+ _volumes[i] = 0;
+ }
+ }
+
+}
+
+long Volume::maxVolume() {
+ return _maxVolume;
+}
+
+long Volume::minVolume() {
+ return _minVolume;
+}
+
+// @ compatibility
+long Volume::operator[](int id) {
+ return getVolume( (Volume::ChannelID) id );
+}
+
+long Volume::getVolume(ChannelID chid) {
+ long vol = 0;
+
+ if ( chid < 0 || chid > (Volume::CHIDMAX) ) {
+ // should throw exception here. I will return 0 instead
+ }
+ else {
+ // check if channel is supported
+ int chmask = _channelMaskEnum[chid];
+ if ( (chmask & _chmask) != 0 ) {
+ // channel is supported
+ vol = _volumes[chid];
+ }
+ else {
+ // should throw exception here. I will return 0 instead
+ }
+ }
+
+ return vol;
+}
+
+long Volume::getAvgVolume(ChannelMask chmask) {
+ int avgVolumeCounter = 0;
+ long long sumOfActiveVolumes = 0;
+ for ( int i=0; i<= Volume::CHIDMAX; i++ ) {
+ if ( (_channelMaskEnum[i] & _chmask) & (int)chmask ) {
+ avgVolumeCounter++;
+ sumOfActiveVolumes += _volumes[i];
+ }
+ }
+ if (avgVolumeCounter != 0) {
+ sumOfActiveVolumes /= avgVolumeCounter;
+ }
+ else {
+ // just return 0;
+ }
+ return (long)sumOfActiveVolumes;
+}
+
+long Volume::getTopStereoVolume(ChannelMask chmask) {
+ long long topVolumeCount = 0;
+ for ( int i=0; i<= Volume::CHIDMAX; i++ ) {
+ if ( (_channelMaskEnum[i] & _chmask) & (int)chmask ) {
+ if ( topVolumeCount < _volumes[i] )
+ topVolumeCount = _volumes[i];
+ }
+ }
+ return (long)topVolumeCount;
+}
+
+int Volume::count() {
+ int counter = 0;
+ for ( int i=0; i<= Volume::CHIDMAX; i++ ) {
+ if ( _channelMaskEnum[i] & _chmask ) {
+ counter++;
+ }
+ }
+ return counter;
+}
+
+/**
+ * returns a "sane" volume level. This means, it is a volume level inside the
+ * valid bounds
+ */
+long Volume::volrange( int vol )
+{
+ if ( vol < _minVolume ) {
+ return _minVolume;
+ }
+ else if ( vol < _maxVolume ) {
+ return vol;
+ }
+ else {
+ return _maxVolume;
+ }
+}
+
+
+std::ostream& operator<<(std::ostream& os, const Volume& vol) {
+ os << "(";
+ for ( int i=0; i<= Volume::CHIDMAX; i++ ) {
+ if ( i != 0 ) {
+ os << ",";
+ }
+ if ( Volume::_channelMaskEnum[i] & vol._chmask ) {
+ // supported channel: Print Volume
+ os << vol._volumes[i];
+ }
+ else {
+ // unsupported channel: Print "x"
+ os << "x";
+ }
+ } // all channels
+ os << ")";
+
+ os << " [" << vol._minVolume << "-" << vol._maxVolume;
+ if ( vol._muted ) { os << " : muted ]"; } else { os << " : playing ]"; }
+
+ return os;
+}
+
+kdbgstream& operator<<(kdbgstream &os, const Volume& vol) {
+ os << "(";
+ for ( int i=0; i<= Volume::CHIDMAX; i++ ) {
+ if ( i != 0 ) {
+ os << ",";
+ }
+ if ( Volume::_channelMaskEnum[i] & vol._chmask ) {
+ // supported channel: Print Volume
+ os << vol._volumes[i];
+ }
+ else {
+ // unsupported channel: Print "x"
+ os << "x";
+ }
+ } // all channels
+ os << ")";
+
+ os << " [" << vol._minVolume << "-" << vol._maxVolume;
+ if ( vol._muted ) { os << " : muted ]"; } else { os << " : playing ]"; }
+
+ return os;
+}
diff --git a/kmix/volume.h b/kmix/volume.h
new file mode 100644
index 00000000..9051ed0c
--- /dev/null
+++ b/kmix/volume.h
@@ -0,0 +1,80 @@
+// -*-C++-*-
+#ifndef VOLUME_H
+#define VOLUME_H
+
+#include <fstream>
+
+#include <kdebug.h>
+
+class Volume
+{
+ public:
+ enum ChannelMask { MNONE = 0,
+ MLEFT = 1, MRIGHT = 2, MCENTER = 4,
+ MMAIN = 3, MFRONT = 7,
+ MREARLEFT = 8, MREARRIGHT = 16, MWOOFER = 32,
+ MREAR = 56,
+ MLEFTREC = 64, MRIGHTREC = 128,
+ MREC =192,
+ MCUSTOM1 =256, MCUSTOM2 = 512,
+ MALL=65535 };
+
+
+ enum ChannelID { CHIDMIN = 0,
+ LEFT = 0, RIGHT = 1, CENTER = 2,
+ REARLEFT = 3, REARRIGHT = 4, WOOFER = 5,
+ LEFTREC = 6, RIGHTREC = 7,
+ CUSTOM1 = 8, CUSTOM2 = 9, CHIDMAX = 9 };
+
+
+ Volume( ChannelMask chmask = MALL, long maxVolume = 100, long minVolume=0, bool isCapture=false );
+ Volume( const Volume &v );
+ Volume( int channels, long maxVolume );
+
+
+
+ // Set all volumes as given by vol
+ void setAllVolumes(long vol);
+ // Set all volumes to the ones given in vol
+ void setVolume(const Volume &vol );
+ // Set volumes as specified by the channel mask
+ void setVolume( const Volume &vol, ChannelMask chmask);
+ void setVolume( ChannelID chid, long volume);
+
+ long getVolume(ChannelID chid);
+ long getAvgVolume(ChannelMask chmask);
+ long getTopStereoVolume(ChannelMask chmask);
+ long operator[](int);
+ long maxVolume();
+ long minVolume();
+ int count();
+
+ void setMuted( bool val ) { _muted = val; };
+ bool isMuted() { return _muted; };
+ bool isCapture() { return _isCapture; };
+
+ friend std::ostream& operator<<(std::ostream& os, const Volume& vol);
+ friend kdbgstream& operator<<(kdbgstream& os, const Volume& vol);
+
+ // _channelMaskEnum[] and the following elements moved to public seection. operator<<() could not
+ // access it, when private. Strange, as operator<<() is declared friend.
+ static int _channelMaskEnum[10];
+ bool _muted;
+ bool _isCapture; // true, when the Volume represents capture/record levels
+ long _chmask;
+ long _volumes[CHIDMAX+1];
+ long _maxVolume;
+ long _minVolume;
+
+private:
+ void init( ChannelMask chmask, long, long, bool );
+
+ long volrange( int vol );
+ long volrangeRec( int vol );
+};
+
+std::ostream& operator<<(std::ostream& os, const Volume& vol);
+kdbgstream& operator<<(kdbgstream &os, const Volume& vol);
+
+#endif // VOLUME
+