~ubuntu-branches/ubuntu/natty/kdemultimedia/natty-proposed

« back to all changes in this revision

Viewing changes to kmix/kmixdockwidget.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Debian Qt/KDE Maintainers
  • Date: 2011-05-26 02:41:36 UTC
  • mfrom: (0.2.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 108.
  • Revision ID: james.westby@ubuntu.com-20110526024136-jjwsigfy402jhupm
Tags: upstream-4.6.3
ImportĀ upstreamĀ versionĀ 4.6.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * KMix -- KDE's full featured mini mixer
3
 
 *
4
 
 *
5
 
 * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
6
 
 * Copyright (C) 2001 Preston Brown <pbrown@kde.org>
7
 
 * Copyright (C) 2004 Christian Esken <esken@kde.org>
8
 
 *
9
 
 * This program is free software; you can redistribute it and/or
10
 
 * modify it under the terms of the GNU Library General Public
11
 
 * License as published by the Free Software Foundation; either
12
 
 * version 2 of the License, or (at your option) any later version.
13
 
 *
14
 
 * This program is distributed in the hope that it will be useful,
15
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 
 * Library General Public License for more details.
18
 
 *
19
 
 * You should have received a copy of the GNU Library General Public
20
 
 * License along with this program; if not, write to the Free
21
 
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22
 
 */
23
 
 
24
 
#include <kaction.h>
25
 
#include <klocale.h>
26
 
#include <kapplication.h>
27
 
#include <kmenu.h>
28
 
#include <kurl.h>
29
 
#include <kglobalsettings.h>
30
 
#include <kdialog.h>
31
 
#include <kiconloader.h>
32
 
#include <kdebug.h>
33
 
#include <kwindowsystem.h>
34
 
#include <kactioncollection.h>
35
 
#include <ktoggleaction.h>
36
 
#include <qapplication.h>
37
 
#include <qcursor.h>
38
 
#include <QDesktopWidget>
39
 
#include <QMouseEvent>
40
 
 
41
 
#ifdef Q_WS_X11
42
 
#include <fixx11h.h>
43
 
#endif
44
 
 
45
 
#include <Phonon/MediaObject>
46
 
 
47
 
#include "dialogselectmaster.h"
48
 
#include "kmix.h"
49
 
#include "kmixdockwidget.h"
50
 
#include "mixer.h"
51
 
#include "mixdevicewidget.h"
52
 
#include "mixertoolbox.h"
53
 
#include "viewdockareapopup.h"
54
 
 
55
 
KMixDockWidget::KMixDockWidget(KMixWindow* parent, QWidget *referenceWidget, bool volumePopup)
56
 
    : KStatusNotifierItem(parent)
57
 
    , _referenceWidget(referenceWidget)
58
 
    , _audioPlayer(0L)
59
 
    , _playBeepOnVolumeChange(false) // disabled due to triggering a "Bug"
60
 
    , _oldToolTipValue(-1)
61
 
    , _oldPixmapType('-')
62
 
    , _volumePopup(volumePopup)
63
 
    , _kmixMainWindow(parent)
64
 
{
65
 
   setToolTipIconByName("kmix");
66
 
   setCategory(Hardware);
67
 
   setStatus(Active);
68
 
   m_mixer = Mixer::getGlobalMasterMixer();  // ugly, but we'll live with that for now
69
 
   createMasterVolWidget();
70
 
   createActions();
71
 
   connect(this, SIGNAL(scrollRequested(int,Qt::Orientation)), this, SLOT(trayWheelEvent(int)));
72
 
   connect(this, SIGNAL(secondaryActivateRequested(QPoint)), this, SLOT(dockMute()));
73
 
   connect(contextMenu(), SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow()));
74
 
 
75
 
// TODO remove this, as in a KMenu it does not need window tricks
76
 
//    ViewDockAreaPopup* dockAreaPopup = qobject_cast<ViewDockAreaPopup*>(referenceWidget);
77
 
//    if ( dockAreaPopup ) {
78
 
//        KWindowSystem::setState( dockAreaPopup->winId(), NET::StaysOnTop | NET::SkipTaskbar | NET::SkipPager );
79
 
//    }
80
 
}
81
 
 
82
 
KMixDockWidget::~KMixDockWidget()
83
 
{
84
 
    delete _audioPlayer;
85
 
}
86
 
 
87
 
void KMixDockWidget::createActions()
88
 
{
89
 
   QMenu *menu = contextMenu();
90
 
 
91
 
   MixDevice* md = Mixer::getGlobalMasterMD();
92
 
  if ( md != 0 && md->playbackVolume().hasSwitch() ) {
93
 
    // Put "Mute" selector in context menu
94
 
    KToggleAction *action = actionCollection()->add<KToggleAction>( "dock_mute" );
95
 
    action->setText( i18n( "M&ute" ) );
96
 
    connect(action, SIGNAL(triggered(bool) ), SLOT( dockMute() ));
97
 
    menu->addAction( action );
98
 
}
99
 
 
100
 
  // Put "Select Master Channel" dialog in context menu
101
 
  if ( m_mixer != 0 ) {
102
 
  QAction *action = actionCollection()->addAction( "select_master" );
103
 
  action->setText( i18n("Select Master Channel...") );
104
 
  connect(action, SIGNAL(triggered(bool) ), SLOT(selectMaster()));
105
 
  menu->addAction( action );
106
 
  }
107
 
 
108
 
   // Setup volume preview
109
 
  if ( _playBeepOnVolumeChange ) {
110
 
    _audioPlayer = Phonon::createPlayer(Phonon::MusicCategory);
111
 
    _audioPlayer->setParent(this);
112
 
  }
113
 
}
114
 
 
115
 
 
116
 
void
117
 
KMixDockWidget::createMasterVolWidget()
118
 
{
119
 
     // Reset flags, so that the dock icon will be reconstructed
120
 
     _oldToolTipValue = -1;
121
 
     _oldPixmapType   = '-';
122
 
 
123
 
    if (Mixer::getGlobalMasterMD() == 0) {
124
 
        // In case that there is no mixer installed, there will be no controlChanged() signal's
125
 
        // Thus we prepare the dock areas manually
126
 
        setVolumeTip();
127
 
        updatePixmap();
128
 
        return;
129
 
    }
130
 
    // create devices
131
 
 
132
 
    m_mixer->readSetFromHWforceUpdate();  // after changing the master device, make sure to re-read (otherwise no "changed()" signals might get sent by the Mixer
133
 
    /* With the recently introduced QSocketNotifier stuff, we can't rely on regular timer updates
134
 
       any longer. Also the readSetFromHWforceUpdate() won't be enough. As a workaround, we trigger
135
 
       all "repaints" manually here.
136
 
       The call to m_mixer->readSetFromHWforceUpdate() is most likely superfluous, even if we don't use QSocketNotifier (e.g. in backends OSS, Solaris, ...)
137
 
     */
138
 
    setVolumeTip();
139
 
    updatePixmap();
140
 
    /* We are setting up 3 connections:
141
 
     * Refreshig the _dockAreaPopup (not anymore necessary, because ViewBase already does it)
142
 
     * Refreshing the Tooltip
143
 
     * Refreshing the Icon
144
 
     */
145
 
    //    connect( m_mixer, SIGNAL(controlChanged()), _dockAreaPopup, SLOT(refreshVolumeLevels()) );
146
 
    connect( m_mixer, SIGNAL(controlChanged()), this, SLOT(setVolumeTip() ) );
147
 
    connect( m_mixer, SIGNAL(controlChanged()), this, SLOT(updatePixmap() ) );
148
 
}
149
 
 
150
 
void KMixDockWidget::selectMaster()
151
 
{
152
 
   DialogSelectMaster* dsm = new DialogSelectMaster(m_mixer);
153
 
   connect ( dsm, SIGNAL(newMasterSelected(QString&, QString&)), SLOT( handleNewMaster(QString&, QString&)) );
154
 
   connect ( dsm, SIGNAL(newMasterSelected(QString&, QString&)), SIGNAL( newMasterSelected()) );
155
 
   dsm->show();
156
 
    // !! The dialog is modal. Does it delete itself?
157
 
}
158
 
 
159
 
 
160
 
void KMixDockWidget::handleNewMaster(QString& /*mixerID*/, QString& /*control_id*/)
161
 
{
162
 
   /* When a new master is selected, we will need to destroy *this instance of KMixDockWidget.
163
 
      Reason: This widget is a KSystemTrayIcon, and needs an associated QWidget. This is in
164
 
      our case the ViewDockAreaPopup instance. As that is recreated, we need to recrate ourself as well.
165
 
      The only chance to do so is outside, in fact it is done by KMixWindow::updateDocking(). This needs to
166
 
      use deleteLater(), as we are executing in a SLOT currently.
167
 
    */
168
 
   _kmixMainWindow->updateDocking();
169
 
/*
170
 
    Mixer *mixer = MixerToolBox::instance()->find(mixerID);
171
 
    if ( mixer == 0 ) {
172
 
        kError(67100) << "KMixDockWidget::createPage(): Invalid Mixer (mixerID=" << mixerID << ")" << endl;
173
 
        return; // can not happen
174
 
   }
175
 
   m_mixer = mixer;
176
 
   //Mixer::setGlobalMaster(mixer->id(), control_id); // We must save this information "somewhere".
177
 
   createMasterVolWidget();
178
 
*/
179
 
}
180
 
 
181
 
 
182
 
void
183
 
KMixDockWidget::setVolumeTip()
184
 
{
185
 
    MixDevice *md = Mixer::getGlobalMasterMD();
186
 
    QString tip = "";
187
 
    int newToolTipValue = 0;
188
 
 
189
 
    if ( md == 0 )
190
 
    {
191
 
        tip = i18n("Mixer cannot be found"); // !! text could be reworked
192
 
        newToolTipValue = -2;
193
 
    }
194
 
    else
195
 
    {
196
 
        // Playback volume will be used for the DockIcon if available.
197
 
        // This heuristic is "good enough" for the DockIcon for now.
198
 
        long val = 0;
199
 
        Volume& vol       = md->playbackVolume();
200
 
        if (! vol.hasVolume() ) {
201
 
           vol = md->captureVolume();
202
 
        }
203
 
        if ( vol.hasVolume() && vol.maxVolume() != 0 ) {
204
 
            val = (vol.getAvgVolume(Volume::MMAIN)*100 )/( vol.maxVolume() );
205
 
        }
206
 
 
207
 
        // create a new "virtual" value. With that we see "volume changes" as well as "muted changes"
208
 
        newToolTipValue = val;
209
 
        if ( md->isMuted() ) newToolTipValue += 10000;
210
 
        if ( _oldToolTipValue != newToolTipValue ) {
211
 
            tip = i18n( "Volume at %1%", val );
212
 
            if ( md->playbackVolume().hasSwitch() && md->isMuted() ) {
213
 
                tip += i18n( " (Muted)" );
214
 
            }
215
 
        }
216
 
    }
217
 
 
218
 
    // The actual updating is only done when the "toolTipValue" was changed
219
 
    if ( newToolTipValue != _oldToolTipValue ) {
220
 
        // changed (or completely new tooltip)
221
 
        setToolTipTitle(tip);
222
 
    }
223
 
    _oldToolTipValue = newToolTipValue;
224
 
}
225
 
 
226
 
void
227
 
KMixDockWidget::updatePixmap()
228
 
{
229
 
    MixDevice *md = Mixer::getGlobalMasterMD();
230
 
 
231
 
    char newPixmapType;
232
 
    if ( md == 0 )
233
 
    {
234
 
        newPixmapType = 'e';
235
 
    }
236
 
    else if ( md->playbackVolume().hasSwitch() && md->isMuted() )
237
 
    {
238
 
        newPixmapType = 'm';
239
 
    }
240
 
    else
241
 
    {
242
 
        Volume& vol = md->playbackVolume();
243
 
        if (! vol.hasVolume() ) {
244
 
            vol = md->captureVolume();
245
 
        }
246
 
        long absoluteVolume    = vol.getAvgVolume(Volume::MALL);
247
 
        int percentage         = vol.percentage(absoluteVolume);
248
 
        if      ( percentage < 25 ) newPixmapType = '1';  // Hint: also negative-values
249
 
        else if ( percentage < 75 ) newPixmapType = '2';
250
 
        else                        newPixmapType = '3';
251
 
   }
252
 
 
253
 
 
254
 
   if ( newPixmapType != _oldPixmapType ) {
255
 
      // Pixmap must be changed => do so
256
 
      switch ( newPixmapType ) {
257
 
         case 'e': setIconByName( "kmixdocked_error" ); break;
258
 
         case 'm': setIconByName( "audio-volume-muted"  ); break;
259
 
         case '1': setIconByName( "audio-volume-low"  ); break;
260
 
         case '2': setIconByName( "audio-volume-medium" ); break;
261
 
         case '3': setIconByName( "audio-volume-high" ); break;
262
 
      }
263
 
   }
264
 
 
265
 
   _oldPixmapType = newPixmapType;
266
 
}
267
 
 
268
 
 
269
 
 
270
 
void KMixDockWidget::activate(const QPoint &pos)
271
 
{
272
 
   KMenu* dockAreaPopup = qobject_cast<KMenu*>(_referenceWidget);
273
 
   if ( !dockAreaPopup ) {
274
 
      // Use default KStatusNotifierItem behavior if we are not using the
275
 
      // dockAreaPopup
276
 
      KStatusNotifierItem::activate(pos);
277
 
      return;
278
 
   }
279
 
   if ( dockAreaPopup->isVisible() ) {
280
 
      dockAreaPopup->hide();
281
 
      return;
282
 
   }
283
 
 
284
 
   if (contextMenu()->isVisible()) {
285
 
        contextMenu()->hide();
286
 
    }
287
 
 
288
 
   dockAreaPopup->adjustSize();
289
 
   int h = dockAreaPopup->height();
290
 
   int x = pos.x() - dockAreaPopup->width()/2;
291
 
   int y = pos.y() - h;
292
 
 
293
 
  // kDebug() << "h="<<h<< " x="<<x << " y="<<y<< "gx="<< geometry().x() << "gy="<< geometry().y();
294
 
 
295
 
   if ( y < 0 ) {
296
 
       y = pos.y();
297
 
   }
298
 
 
299
 
   dockAreaPopup->move(x, y);  // so that the mouse is outside of the widget
300
 
   kDebug() << "moving to" << dockAreaPopup->size() << x << y;
301
 
 
302
 
   dockAreaPopup->show();
303
 
 
304
 
   // Now handle Multihead displays. And also make sure that the dialog is not
305
 
   // moved out-of-the screen on the right (see Bug 101742).
306
 
   const QDesktopWidget* vdesktop = QApplication::desktop();
307
 
   const QRect& vScreenSize = vdesktop->screenGeometry(dockAreaPopup);
308
 
   //const QRect screenGeometry(const QWidget *widget) const
309
 
   if ( (x+dockAreaPopup->width()) > (vScreenSize.width() + vScreenSize.x()) ) {
310
 
       // move horizontally, so that it is completely visible
311
 
       dockAreaPopup->move(vScreenSize.width() + vScreenSize.x() - dockAreaPopup->width() -1 , y);
312
 
   }
313
 
   else if ( x < vScreenSize.x() ) {
314
 
       // horizontally out-of bound
315
 
       dockAreaPopup->move(vScreenSize.x(), y);
316
 
   }
317
 
   // the above stuff could also be implemented vertically
318
 
 
319
 
   KWindowSystem::setState( dockAreaPopup->winId(), NET::StaysOnTop | NET::SkipTaskbar | NET::SkipPager );
320
 
}
321
 
 
322
 
// void
323
 
// KMixDockWidget::trayToolTipEvent(QHelpEvent *e ) {
324
 
//    kDebug(67100) << "trayToolTipEvent" ;
325
 
//    setVolumeTip();
326
 
// }
327
 
 
328
 
void
329
 
KMixDockWidget::trayWheelEvent(int delta)
330
 
{
331
 
  MixDevice *md = Mixer::getGlobalMasterMD();
332
 
  if ( md != 0 )
333
 
  {
334
 
      Volume vol = md->playbackVolume();
335
 
      if ( md->playbackVolume().hasVolume() )
336
 
         vol = md->playbackVolume();
337
 
      else
338
 
         vol = md->captureVolume();
339
 
 
340
 
      int inc = vol.maxVolume() / 20;
341
 
 
342
 
    if ( inc < 1 ) inc = 1;
343
 
 
344
 
    for ( int i = 0; i < vol.count(); i++ ) {
345
 
        int newVal = vol[i] + (inc * (delta / 120));
346
 
        if( newVal < 0 ) newVal = 0;
347
 
        vol.setVolume( (Volume::ChannelID)i, newVal < vol.maxVolume() ? newVal : vol.maxVolume() );
348
 
    }
349
 
 
350
 
    if ( _playBeepOnVolumeChange ) {
351
 
        QString fileName("KDE_Beep_Digital_1.ogg");
352
 
        _audioPlayer->setCurrentSource(fileName);
353
 
        _audioPlayer->play();
354
 
    }
355
 
      if ( md->playbackVolume().hasVolume() )
356
 
         md->playbackVolume().setVolume(vol);
357
 
      else
358
 
         md->captureVolume().setVolume(vol);
359
 
      m_mixer->commitVolumeChange(md);
360
 
    setVolumeTip();
361
 
  }
362
 
}
363
 
 
364
 
void
365
 
KMixDockWidget::dockMute()
366
 
{
367
 
   MixDevice *md = Mixer::getGlobalMasterMD();
368
 
   if ( md != 0 ) {
369
 
      md->setMuted( !md->isMuted() );
370
 
      md->mixer()->commitVolumeChange( md );
371
 
   }
372
 
}
373
 
 
374
 
void
375
 
KMixDockWidget::contextMenuAboutToShow()
376
 
{
377
 
    QAction* showAction = actionCollection()->action("minimizeRestore");
378
 
    if ( associatedWidget() && showAction )
379
 
    {
380
 
        if ( associatedWidget()->isVisible() )
381
 
        {
382
 
            showAction->setText( i18n("Hide Mixer Window") );
383
 
        }
384
 
        else
385
 
        {
386
 
            showAction->setText( i18n("Show Mixer Window") );
387
 
        }
388
 
    }
389
 
 
390
 
    // Enable/Disable "Muted" menu item
391
 
    MixDevice* md = Mixer::getGlobalMasterMD();
392
 
    KToggleAction *dockMuteAction = static_cast<KToggleAction*>(actionCollection()->action("dock_mute"));
393
 
    //kDebug(67100) << "---> md=" << md << "dockMuteAction=" << dockMuteAction << "isMuted=" << md->isMuted();
394
 
    if ( md != 0 && dockMuteAction != 0 ) {
395
 
        bool hasSwitch = md->playbackVolume().hasSwitch();
396
 
        dockMuteAction->setEnabled( hasSwitch );
397
 
        dockMuteAction->setChecked( hasSwitch && md->isMuted() );
398
 
    }
399
 
}
400
 
 
401
 
#include "kmixdockwidget.moc"