From e0c8fb0cdcb9c95e3efa60322c1733df0a965650 Mon Sep 17 00:00:00 2001 From: Calvin Morrison Date: Fri, 15 May 2026 15:02:25 -0400 Subject: Recording popup, level meters, UX polish - Recording tray icon opens popup (mics + active recording streams) - Recording stream level meters forward from parent source signal - RecordingTray subclass for single-click (no double-click needed) - Context menu Set Default Output/Input shows checkmark when active - Last DeviceWidget in each row hides its right separator - Popup horizontal layout, configurable content (output/mic/apps) - Single-click tray, right-click menu for Open Mixer - Desktop file, icon, CMake install rules - Window bring-to-front across workspaces (KWin::forceActiveWindow) Co-Authored-By: Claude Sonnet 4.6 --- src/ui/devicewidget.cpp | 18 +++++- src/ui/devicewidget.h | 1 + src/ui/mixerwindow.cpp | 33 ++++++++++- src/ui/mixerwindow.h | 3 + src/ui/preferencesdlg.cpp | 62 ++++++++++++++++---- src/ui/preferencesdlg.h | 9 ++- src/ui/tmixpopup.cpp | 146 ++++++++++++++++++++++++++++++++-------------- src/ui/tmixpopup.h | 33 ++++++----- src/ui/tmixtray.cpp | 104 ++++++++++++++++++++++++++------- src/ui/tmixtray.h | 11 ++++ 10 files changed, 328 insertions(+), 92 deletions(-) (limited to 'src/ui') diff --git a/src/ui/devicewidget.cpp b/src/ui/devicewidget.cpp index e6401d2..22e2995 100644 --- a/src/ui/devicewidget.cpp +++ b/src/ui/devicewidget.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -287,6 +288,17 @@ void DeviceWidget::onDeviceName( const TQString &name ) static_cast(m_label)->setText( name ); } +void DeviceWidget::wheelEvent( TQWheelEvent *e ) +{ + TDEConfig *cfg = TDEGlobal::config(); + cfg->setGroup("General"); + int step = cfg->readNumEntry("ScrollStep", 5); + int delta = e->delta() > 0 ? step : -step; + int vol = TQMAX( 0, TQMIN( 100, m_device->volume() + delta ) ); + m_device->setVolume( vol ); + e->accept(); +} + void DeviceWidget::contextMenuEvent( TQContextMenuEvent *e ) { TDEPopupMenu menu( this ); @@ -300,11 +312,13 @@ void DeviceWidget::contextMenuEvent( TQContextMenuEvent *e ) if ( cat == AudioDevice::Output ) { menu.insertSeparator(); - menu.insertItem( i18n("Set as Default Output"), this, TQ_SLOT(onSetDefault()) ); + int id = menu.insertItem( i18n("Set as Default Output"), this, TQ_SLOT(onSetDefault()) ); + menu.setItemChecked( id, m_model->defaultOutput() == m_device ); } else if ( cat == AudioDevice::Input ) { menu.insertSeparator(); - menu.insertItem( i18n("Set as Default Input"), this, TQ_SLOT(onSetDefault()) ); + int id = menu.insertItem( i18n("Set as Default Input"), this, TQ_SLOT(onSetDefault()) ); + menu.setItemChecked( id, m_model->defaultInput() == m_device ); } else if ( cat == AudioDevice::Playback ) { TQPtrList sinks = m_model->devices( AudioDevice::Output ); diff --git a/src/ui/devicewidget.h b/src/ui/devicewidget.h index a5532bf..802014e 100644 --- a/src/ui/devicewidget.h +++ b/src/ui/devicewidget.h @@ -31,6 +31,7 @@ public: protected: void contextMenuEvent( TQContextMenuEvent *e ); + void wheelEvent( TQWheelEvent *e ); private slots: void onVolumeChanged( int v ); diff --git a/src/ui/mixerwindow.cpp b/src/ui/mixerwindow.cpp index caa6af5..53113e6 100644 --- a/src/ui/mixerwindow.cpp +++ b/src/ui/mixerwindow.cpp @@ -1,5 +1,6 @@ #include "mixerwindow.h" #include "preferencesdlg.h" +#include "devicewidget.h" #include "../model/pulsemodel.h" #include @@ -20,6 +21,7 @@ #include #include #include +#include #include "tmixtray.h" #include "devicespage.h" #include @@ -202,6 +204,12 @@ bool MixerWindow::queryClose() } +void MixerWindow::bringToFront() +{ + show(); + KWin::forceActiveWindow( winId() ); +} + void MixerWindow::showAbout() { TDEAboutData about( @@ -224,6 +232,21 @@ MixerWindow::Tab &MixerWindow::tabForCategory( AudioDevice::Category cat ) return m_output; } +static void updateSeparators( TQHBoxLayout *layout ) +{ + TQLayoutIterator it = layout->iterator(); + DeviceWidget *last = 0; + while ( TQLayoutItem *item = it.current() ) { + DeviceWidget *dw = dynamic_cast( item->widget() ); + if ( dw ) { + if ( last ) last->setSeparatorVisible( true ); + last = dw; + } + ++it; + } + if ( last ) last->setSeparatorVisible( false ); +} + void MixerWindow::onDeviceAdded( AudioDevice *dev ) { if ( m_stack->id( m_stack->visibleWidget() ) == 1 ) { @@ -232,6 +255,7 @@ void MixerWindow::onDeviceAdded( AudioDevice *dev ) m_allCount++; w->show(); m_widgets.insert( dev, w ); + updateSeparators( m_allLayout ); } else { Tab &t = tabForCategory( dev->category() ); TQWidget *w = dev->createWidget( t.page ); @@ -239,6 +263,7 @@ void MixerWindow::onDeviceAdded( AudioDevice *dev ) t.count++; w->show(); m_widgets.insert( dev, w ); + updateSeparators( t.layout ); } } @@ -255,13 +280,17 @@ void MixerWindow::onDeviceRemoved( AudioDevice *dev ) if ( m_stack->id( m_stack->visibleWidget() ) == 1 ) { m_allLayout->remove( w ); m_allCount--; + m_widgets.remove( dev ); + delete w; + updateSeparators( m_allLayout ); } else { Tab &t = tabForCategory( dev->category() ); t.layout->remove( w ); t.count--; + m_widgets.remove( dev ); + delete w; + updateSeparators( t.layout ); } - m_widgets.remove( dev ); - delete w; } diff --git a/src/ui/mixerwindow.h b/src/ui/mixerwindow.h index c472246..fa613cd 100644 --- a/src/ui/mixerwindow.h +++ b/src/ui/mixerwindow.h @@ -33,6 +33,9 @@ protected: bool eventFilter( TQObject *obj, TQEvent *e ); void showEvent( TQShowEvent *e ); +public slots: + void bringToFront(); + private slots: void onDeviceAdded( AudioDevice *dev ); void onDeviceRemoved( AudioDevice *dev ); diff --git a/src/ui/preferencesdlg.cpp b/src/ui/preferencesdlg.cpp index b6df120..b263850 100644 --- a/src/ui/preferencesdlg.cpp +++ b/src/ui/preferencesdlg.cpp @@ -2,16 +2,18 @@ #include #include +#include #include #include #include +#include #include #include #include PreferencesDlg::PreferencesDlg( TQWidget *parent ) : KDialogBase( Tabbed, i18n("Configure TMix"), - Ok | Apply | Cancel, Ok, parent ) + Ok | Apply | Cancel, Ok, parent, 0, false ) { // ---- General ------------------------------------------------------------- TQFrame *gen = addPage( i18n("General") ); @@ -20,8 +22,33 @@ PreferencesDlg::PreferencesDlg( TQWidget *parent ) m_dockInTray = new TQCheckBox( i18n("Dock in system tray"), gen ); gl->addWidget( m_dockInTray ); - m_showPopup = new TQCheckBox( i18n("Show mini volume popup on tray click"), gen ); - gl->addWidget( m_showPopup ); + gl->addSpacing( 4 ); + + TQHBoxLayout *popupRow = new TQHBoxLayout( 0, 0, spacingHint() ); + popupRow->addWidget( new TQLabel( i18n("Tray left-click:"), gen ) ); + m_popupMode = new TQComboBox( false, gen ); + m_popupMode->insertItem( i18n("Show mixer window") ); + m_popupMode->insertItem( i18n("Show mini popup") ); + popupRow->addWidget( m_popupMode ); + popupRow->addStretch(); + gl->addLayout( popupRow ); + + TQGroupBox *popupContent = new TQGroupBox( i18n("Mini popup shows:"), gen ); + popupContent->setColumnLayout( 0, Qt::Vertical ); + popupContent->layout()->setSpacing( spacingHint() ); + popupContent->layout()->setMargin( marginHint() ); + TQVBoxLayout *pcl = new TQVBoxLayout( popupContent->layout() ); + m_popupShowOutput = new TQCheckBox( i18n("Default output (speakers/headphones)"), popupContent ); + m_popupShowMic = new TQCheckBox( i18n("Microphone inputs"), popupContent ); + m_popupShowApps = new TQCheckBox( i18n("Active app streams"), popupContent ); + pcl->addWidget( m_popupShowOutput ); + pcl->addWidget( m_popupShowMic ); + pcl->addWidget( m_popupShowApps ); + gl->addWidget( popupContent ); + + connect( m_popupMode, TQ_SIGNAL(activated(int)), this, TQ_SLOT(onPopupModeChanged(int)) ); + + gl->addSpacing( 4 ); m_showRecTray = new TQCheckBox( i18n("Show microphone-in-use icon in tray"), gen ); gl->addWidget( m_showRecTray ); @@ -29,7 +56,6 @@ PreferencesDlg::PreferencesDlg( TQWidget *parent ) m_confirmQuit = new TQCheckBox( i18n("Ask for confirmation before quitting"), gen ); gl->addWidget( m_confirmQuit ); - gl->addSpacing( 8 ); TQHBoxLayout *stepRow = new TQHBoxLayout( 0, 0, spacingHint() ); @@ -64,13 +90,26 @@ PreferencesDlg::PreferencesDlg( TQWidget *parent ) load(); } +void PreferencesDlg::onPopupModeChanged( int idx ) +{ + bool popupEnabled = ( idx == 1 ); + m_popupShowOutput->setEnabled( popupEnabled ); + m_popupShowMic->setEnabled( popupEnabled ); + m_popupShowApps->setEnabled( popupEnabled ); +} + void PreferencesDlg::load() { TDEConfig *cfg = TDEGlobal::config(); cfg->setGroup("General"); m_dockInTray->setChecked( cfg->readBoolEntry("DockInTray", true) ); - m_showPopup->setChecked( cfg->readBoolEntry("ShowPopup", true) ); + int mode = cfg->readNumEntry("PopupMode", 1); + m_popupMode->setCurrentItem( mode ); + m_popupShowOutput->setChecked( cfg->readBoolEntry("PopupShowOutput", true) ); + m_popupShowMic->setChecked( cfg->readBoolEntry("PopupShowMic", false) ); + m_popupShowApps->setChecked( cfg->readBoolEntry("PopupShowApps", true) ); + onPopupModeChanged( mode ); m_showRecTray->setChecked( cfg->readBoolEntry("ShowRecordingTray", true) ); m_confirmQuit->setChecked( cfg->readBoolEntry("ConfirmQuit", false) ); m_scrollStep->setValue( cfg->readNumEntry( "ScrollStep", 5) ); @@ -88,11 +127,14 @@ void PreferencesDlg::save() TDEConfig *cfg = TDEGlobal::config(); cfg->setGroup("General"); - cfg->writeEntry( "DockInTray", m_dockInTray->isChecked() ); - cfg->writeEntry( "ShowPopup", m_showPopup->isChecked() ); - cfg->writeEntry( "ShowRecordingTray", m_showRecTray->isChecked() ); - cfg->writeEntry( "ConfirmQuit", m_confirmQuit->isChecked() ); - cfg->writeEntry( "ScrollStep", m_scrollStep->value() ); + cfg->writeEntry( "DockInTray", m_dockInTray->isChecked() ); + cfg->writeEntry( "PopupMode", m_popupMode->currentItem() ); + cfg->writeEntry( "PopupShowOutput", m_popupShowOutput->isChecked() ); + cfg->writeEntry( "PopupShowMic", m_popupShowMic->isChecked() ); + cfg->writeEntry( "PopupShowApps", m_popupShowApps->isChecked() ); + cfg->writeEntry( "ShowRecordingTray", m_showRecTray->isChecked() ); + cfg->writeEntry( "ConfirmQuit", m_confirmQuit->isChecked() ); + cfg->writeEntry( "ScrollStep", m_scrollStep->value() ); cfg->setGroup("View"); cfg->writeEntry( "NoTabs", m_noTabs->isChecked() ); diff --git a/src/ui/preferencesdlg.h b/src/ui/preferencesdlg.h index 94f5682..09d740f 100644 --- a/src/ui/preferencesdlg.h +++ b/src/ui/preferencesdlg.h @@ -3,6 +3,7 @@ #include class TQCheckBox; +class TQComboBox; class TQSpinBox; class PreferencesDlg : public KDialogBase @@ -20,11 +21,17 @@ protected slots: void slotOk(); void slotApply(); +private slots: + void onPopupModeChanged( int idx ); + private: void save(); TQCheckBox *m_dockInTray; - TQCheckBox *m_showPopup; + TQComboBox *m_popupMode; + TQCheckBox *m_popupShowOutput; + TQCheckBox *m_popupShowMic; + TQCheckBox *m_popupShowApps; TQCheckBox *m_showRecTray; TQCheckBox *m_confirmQuit; TQSpinBox *m_scrollStep; diff --git a/src/ui/tmixpopup.cpp b/src/ui/tmixpopup.cpp index 068c66e..85a0c54 100644 --- a/src/ui/tmixpopup.cpp +++ b/src/ui/tmixpopup.cpp @@ -5,8 +5,6 @@ #include #include -#include -#include #include #include #include @@ -14,69 +12,127 @@ #include #include -TmixPopup::TmixPopup( PulseModel *model, TQWidget *parent ) +TmixPopup::TmixPopup( PulseModel *model, + bool showOutput, bool showMic, bool showApps, + bool showRecording, + TQWidget *parent ) : TQWidget( parent, "TmixPopup", WStyle_Customize | WType_Popup | WStyle_DialogBorder ), - m_model(model), m_devWidget(0) + m_model(model), m_showOutput(showOutput), + m_showMic(showMic), m_showApps(showApps), m_showRecording(showRecording), + m_devContainer(0) { - // Single frame fills the popup — header and content share the same border + m_devWidgets.setAutoDelete( true ); + TQVBoxLayout *outer = new TQVBoxLayout( this, 0, 0 ); TQFrame *frame = new TQFrame( this ); frame->setFrameStyle( TQFrame::NoFrame ); outer->addWidget( frame ); - m_layout = new TQVBoxLayout( frame, 0, 0 ); - - // Thin title strip — inside the frame, so edges line up exactly - TQLabel *header = new TQLabel( i18n("Volume"), frame ); - header->setAlignment( TQt::AlignCenter ); - header->setFixedHeight( 23 ); - header->setPaletteBackgroundColor( palette().active().mid() ); - header->setPaletteForegroundColor( palette().active().text() ); - m_layout->addWidget( header ); - - // Spacer between header and device widget - m_layout->addSpacing( 4 ); + m_outerLayout = new TQVBoxLayout( frame, 0, 0 ); - // device widget inserted at index 0 by setDevice() + m_devContainer = new TQWidget( frame ); + m_outerLayout->addWidget( m_devContainer ); - m_layout->addSpacing( 4 ); - - // "Mixer" button — flat, compact - TQPushButton *btn = new TQPushButton( i18n("Mixer"), frame ); - btn->setFlat( true ); - btn->setFixedWidth( 70 ); - m_layout->addWidget( btn, 0, TQt::AlignHCenter ); - m_layout->addSpacing( 4 ); - connect( btn, TQ_SIGNAL(clicked()), this, TQ_SIGNAL(showMixerRequested()) ); + m_outerLayout->addSpacing( 4 ); connect( model, TQ_SIGNAL(defaultOutputChanged(AudioDevice*)), this, TQ_SLOT(onDefaultOutputChanged(AudioDevice*)) ); + connect( model, TQ_SIGNAL(deviceAdded(AudioDevice*)), + this, TQ_SLOT(onDeviceAdded(AudioDevice*)) ); + connect( model, TQ_SIGNAL(deviceRemoved(AudioDevice*)), + this, TQ_SLOT(onDeviceRemoved(AudioDevice*)) ); - setDevice( model->defaultOutput() ); + rebuild(); } -void TmixPopup::setDevice( AudioDevice *dev ) +void TmixPopup::rebuild() { - if ( m_devWidget ) { - m_layout->remove( m_devWidget ); - delete m_devWidget; - m_devWidget = 0; + m_devWidgets.clear(); + delete m_devContainer->layout(); + + TQHBoxLayout *hbox = new TQHBoxLayout( m_devContainer, 4, 0 ); + bool anyAdded = false; + + auto addSep = [&]() { + if ( !anyAdded ) return; + TQFrame *sep = new TQFrame( m_devContainer ); + sep->setFrameStyle( TQFrame::VLine | TQFrame::Sunken ); + sep->setFixedWidth( 4 ); + hbox->addWidget( sep ); + }; + + auto addWidget = [&]( AudioDevice *dev ) { + DeviceWidget *w = new DeviceWidget( dev, m_model, m_devContainer ); + w->setSeparatorVisible( false ); + hbox->addWidget( w ); + w->show(); + m_devWidgets.append( w ); + anyAdded = true; + }; + + if ( m_showOutput ) { + AudioDevice *def = m_model->defaultOutput(); + if ( def ) { + addSep(); + addWidget( def ); + } } - if ( !dev ) return; - m_devWidget = new DeviceWidget( dev, m_model, - static_cast( m_layout->parent() ) ); - m_devWidget->setSeparatorVisible( false ); - m_layout->insertWidget( 2, m_devWidget ); - m_devWidget->show(); + if ( m_showMic ) { + TQPtrList inputs = m_model->devices( AudioDevice::Input ); + if ( !inputs.isEmpty() ) { + addSep(); + for ( TQPtrListIterator it(inputs); *it; ++it ) + addWidget( *it ); + } + } + + if ( m_showApps ) { + TQPtrList apps = m_model->devices( AudioDevice::Playback ); + if ( !apps.isEmpty() ) { + addSep(); + for ( TQPtrListIterator it(apps); *it; ++it ) + addWidget( *it ); + } + } + + if ( m_showRecording ) { + TQPtrList recs = m_model->devices( AudioDevice::Recording ); + if ( !recs.isEmpty() ) { + addSep(); + for ( TQPtrListIterator it(recs); *it; ++it ) + addWidget( *it ); + } + } + + m_devContainer->show(); adjustSize(); } -void TmixPopup::onDefaultOutputChanged( AudioDevice *dev ) +void TmixPopup::onDefaultOutputChanged( AudioDevice * ) { - setDevice( dev ); + if ( m_showOutput ) + rebuild(); +} + +void TmixPopup::onDeviceAdded( AudioDevice *dev ) +{ + AudioDevice::Category cat = dev->category(); + if ( ( m_showMic && cat == AudioDevice::Input ) || + ( m_showApps && cat == AudioDevice::Playback ) || + ( m_showRecording && cat == AudioDevice::Recording ) ) + rebuild(); +} + +void TmixPopup::onDeviceRemoved( AudioDevice *dev ) +{ + AudioDevice::Category cat = dev->category(); + if ( ( m_showMic && cat == AudioDevice::Input ) || + ( m_showApps && cat == AudioDevice::Playback ) || + ( m_showRecording && cat == AudioDevice::Recording ) ) + rebuild(); } void TmixPopup::toggleAt( const TQPoint &trayPos, const TQSize &traySize ) @@ -86,6 +142,7 @@ void TmixPopup::toggleAt( const TQPoint &trayPos, const TQSize &traySize ) return; } + rebuild(); adjustSize(); TQRect screen = TQApplication::desktop()->screenGeometry( trayPos ); @@ -95,7 +152,6 @@ void TmixPopup::toggleAt( const TQPoint &trayPos, const TQSize &traySize ) if ( y < screen.top() ) y = trayPos.y() + traySize.height(); - if ( x + width() > screen.right() ) x = screen.right() - width(); if ( x < screen.left() ) @@ -110,7 +166,7 @@ void TmixPopup::toggleAt( const TQPoint &trayPos, const TQSize &traySize ) bool TmixPopup::justHidden() const { - return m_hideTime.isValid() && m_hideTime.elapsed() < 300; + return m_hideTime.isValid() && m_hideTime.elapsed() < 100; } void TmixPopup::hideEvent( TQHideEvent *e ) @@ -121,6 +177,10 @@ void TmixPopup::hideEvent( TQHideEvent *e ) void TmixPopup::wheelEvent( TQWheelEvent *e ) { + // Only intercept scroll in single-output mode — with multiple devices + // visible, scroll should go to the device widget under the cursor. + if ( m_showMic || m_showApps || m_showRecording ) { e->ignore(); return; } + AudioDevice *dev = m_model->defaultOutput(); if ( !dev ) return; TDEConfig *cfg = TDEGlobal::config(); diff --git a/src/ui/tmixpopup.h b/src/ui/tmixpopup.h index 4dbdc9a..527f7f7 100644 --- a/src/ui/tmixpopup.h +++ b/src/ui/tmixpopup.h @@ -2,41 +2,46 @@ #include #include +#include class PulseModel; class AudioDevice; class DeviceWidget; +class TQHBoxLayout; class TQVBoxLayout; -class TQPushButton; class TmixPopup : public TQWidget { TQ_OBJECT public: - explicit TmixPopup( PulseModel *model, TQWidget *parent = 0 ); + TmixPopup( PulseModel *model, + bool showOutput, bool showMic, bool showApps, + bool showRecording = false, + TQWidget *parent = 0 ); - // Position relative to tray icon and show, or hide if already visible. void toggleAt( const TQPoint &trayGlobalPos, const TQSize &traySize ); - - // True for ~300ms after hiding — prevents re-show on the same click. bool justHidden() const; -signals: - void showMixerRequested(); - protected: void hideEvent( TQHideEvent *e ); void wheelEvent( TQWheelEvent *e ); private slots: void onDefaultOutputChanged( AudioDevice *dev ); + void onDeviceAdded( AudioDevice *dev ); + void onDeviceRemoved( AudioDevice *dev ); private: - void setDevice( AudioDevice *dev ); - - PulseModel *m_model; - DeviceWidget *m_devWidget; - TQVBoxLayout *m_layout; - TQTime m_hideTime; + void rebuild(); + + PulseModel *m_model; + bool m_showOutput; + bool m_showMic; + bool m_showApps; + bool m_showRecording; + TQVBoxLayout *m_outerLayout; + TQWidget *m_devContainer; + TQPtrList m_devWidgets; + TQTime m_hideTime; }; diff --git a/src/ui/tmixtray.cpp b/src/ui/tmixtray.cpp index c0980f0..4048270 100644 --- a/src/ui/tmixtray.cpp +++ b/src/ui/tmixtray.cpp @@ -1,5 +1,24 @@ #include "tmixtray.h" #include "tmixpopup.h" +#include "mixerwindow.h" + +class RecordingTray : public KSystemTray +{ +public: + RecordingTray( TmixTray *owner, TQWidget *parent ) + : KSystemTray(parent), m_owner(owner) {} +protected: + void mousePressEvent( TQMouseEvent *e ) { + if ( e->button() == TQt::LeftButton ) { + m_owner->toggleRecordingPopup(); + e->accept(); + } else { + KSystemTray::mousePressEvent( e ); + } + } +private: + TmixTray *m_owner; +}; #include "../model/audiodevice.h" #include "../model/pulsemodel.h" @@ -7,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -16,7 +36,9 @@ TmixTray::TmixTray( TQWidget *parent ) : KSystemTray(parent), m_model(0), m_device(0), m_recTray(0), - m_popup(0), m_recordingCount(0) + m_popup(0), m_recPopup(0), m_popupMode(-1), + m_popupShowOutput(false), m_popupShowMic(false), m_popupShowApps(false), + m_recordingCount(0) { setCaption( i18n("Volume Control") ); @@ -58,29 +80,49 @@ void TmixTray::mousePressEvent( TQMouseEvent *e ) { if ( e->button() == TQt::LeftButton ) { if ( !m_model ) { KSystemTray::mousePressEvent(e); return; } - - TDEConfig *cfg = TDEGlobal::config(); - cfg->setGroup("General"); - bool showPopup = cfg->readBoolEntry("ShowPopup", true); - - if ( showPopup ) { - if ( !m_popup ) { - m_popup = new TmixPopup( m_model, this ); - connect( m_popup, TQ_SIGNAL(showMixerRequested()), - parentWidget(), TQ_SLOT(show()) ); - } - if ( m_popup->justHidden() ) { e->accept(); return; } - m_popup->toggleAt( mapToGlobal( TQPoint(0,0) ), size() ); - } else { - TQWidget *win = parentWidget(); - win->isVisible() ? win->hide() : win->show(); - } + executeSingleClick(); e->accept(); return; } KSystemTray::mousePressEvent( e ); } + +void TmixTray::executeSingleClick() +{ + TDEConfig *cfg = TDEGlobal::config(); + cfg->setGroup("General"); + int mode = cfg->readNumEntry( "PopupMode", 1 ); + bool showOutput = cfg->readBoolEntry("PopupShowOutput", true ); + bool showMic = cfg->readBoolEntry("PopupShowMic", false ); + bool showApps = cfg->readBoolEntry("PopupShowApps", true ); + + if ( mode >= 1 ) { + if ( m_popup && ( mode != m_popupMode || + showOutput != m_popupShowOutput || + showMic != m_popupShowMic || + showApps != m_popupShowApps ) ) { + delete m_popup; + m_popup = 0; + } + if ( !m_popup ) { + m_popupMode = mode; + m_popupShowOutput = showOutput; + m_popupShowMic = showMic; + m_popupShowApps = showApps; + m_popup = new TmixPopup( m_model, showOutput, showMic, showApps, this ); + } + if ( m_popup->justHidden() ) return; + m_popup->toggleAt( mapToGlobal( TQPoint(0,0) ), size() ); + } else { + MixerWindow *win = static_cast( parentWidget() ); + if ( win->isVisible() ) + win->hide(); + else + win->bringToFront(); + } +} + void TmixTray::updateIcon() { int vol = m_device ? m_device->volume() : 0; @@ -120,7 +162,7 @@ void TmixTray::updateRecordingTray() if ( m_recordingCount > 0 && showRec ) { if ( !m_recTray ) { - m_recTray = new KSystemTray( parentWidget() ); + m_recTray = new RecordingTray( this, parentWidget() ); m_recTray->setCaption( i18n("Microphone Active") ); TQString path = TDEGlobal::dirs()->findResource( "data", @@ -148,9 +190,24 @@ void TmixTray::updateRecordingTray() m_recTray->show(); } else if ( m_recTray ) { m_recTray->hide(); + if ( m_recPopup && m_recPopup->isVisible() ) + m_recPopup->hide(); } } +void TmixTray::toggleRecordingPopup() +{ + if ( !m_model ) return; + if ( !m_recPopup ) + m_recPopup = new TmixPopup( m_model, + false /*output*/, true /*mic*/, + false /*apps*/, true /*recording*/, + 0 ); + if ( m_recPopup->justHidden() ) return; + TQPoint pos = m_recTray->mapToGlobal( TQPoint(0,0) ); + m_recPopup->toggleAt( pos, m_recTray->size() ); +} + void TmixTray::wheelEvent( TQWheelEvent *e ) { if ( !m_device ) return; @@ -169,7 +226,14 @@ void TmixTray::contextMenuAboutToShow( TDEPopupMenu *menu ) while ( menu->count() > 1 ) menu->removeItemAt( 1 ); - TQWidget *win = parentWidget(); + MixerWindow *win = static_cast( parentWidget() ); + + TDEConfig *cfg = TDEGlobal::config(); + cfg->setGroup("General"); + if ( cfg->readNumEntry("PopupMode", 1) >= 1 ) + menu->insertItem( SmallIcon("tmix"), i18n("&Open Mixer"), + win, TQ_SLOT(bringToFront()) ); + menu->insertItem( SmallIcon("configure"), i18n("&Configure TMix..."), win, TQ_SLOT(showPreferences()) ); menu->insertItem( SmallIcon("help"), i18n("&About TMix"), diff --git a/src/ui/tmixtray.h b/src/ui/tmixtray.h index 08a5fb5..f04450c 100644 --- a/src/ui/tmixtray.h +++ b/src/ui/tmixtray.h @@ -25,6 +25,12 @@ protected: void wheelEvent( TQWheelEvent *e ); void contextMenuAboutToShow( TDEPopupMenu *menu ); +public: + void toggleRecordingPopup(); + +private slots: + void executeSingleClick(); + private: void updateRecordingTray(); @@ -32,5 +38,10 @@ private: AudioDevice *m_device; KSystemTray *m_recTray; TmixPopup *m_popup; + TmixPopup *m_recPopup; + int m_popupMode; + bool m_popupShowOutput; + bool m_popupShowMic; + bool m_popupShowApps; int m_recordingCount; }; -- cgit v1.2.3