diff --git a/include/tomahawk/tomahawkapp.h b/include/tomahawk/tomahawkapp.h index b0a277462..e29e3484f 100644 --- a/include/tomahawk/tomahawkapp.h +++ b/include/tomahawk/tomahawkapp.h @@ -78,10 +78,10 @@ public: XMPPBot* xmppBot() { return m_xmppBot; } const QString& nodeID() const; - #ifndef TOMAHAWK_HEADLESS AudioControls* audioControls(); PlaylistManager* playlistManager(); + TomahawkWindow* mainWindow() const { return m_mainwindow; } #endif void registerIODeviceFactory( const QString &proto, boost::function(Tomahawk::result_ptr)> fac ); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18e5c2b46..7a44a4f7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -138,6 +138,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} infowidgets/sourceinfowidget.cpp tomahawkwindow.cpp + tomahawktrayicon.cpp audiocontrols.cpp settingsdialog.cpp ) @@ -264,6 +265,7 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui} infowidgets/sourceinfowidget.h tomahawkwindow.h + tomahawktrayicon.h audiocontrols.h settingsdialog.h ) diff --git a/src/audio/audioengine.h b/src/audio/audioengine.h index 0489d2b7b..608c98acf 100644 --- a/src/audio/audioengine.h +++ b/src/audio/audioengine.h @@ -26,7 +26,8 @@ public: explicit AudioEngine(); ~AudioEngine(); - unsigned int volume() { if ( m_audio ) return m_audio->volume() * 100.0; else return 0; }; // in percent + unsigned int volume() const { if ( m_audio ) return m_audio->volume() * 100.0; else return 0; }; // in percent + bool isPaused() const { return m_audio->isPaused(); } /* Returns the PlaylistInterface of the currently playing track. Note: This might be different to the current playlist! */ PlaylistInterface* currentPlaylist() const { return m_currentPlaylist; } diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index ae2d6fbc9..132245045 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -108,18 +108,18 @@ AudioControls::AudioControls( QWidget* parent ) m_prevAction = new QAction( this ); m_nextAction = new QAction( this ); - connect( m_playAction, SIGNAL( triggered() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( play() ) ); - connect( m_pauseAction, SIGNAL( triggered() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( pause() ) ); - connect( m_prevAction, SIGNAL( triggered() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( previous() ) ); - connect( m_nextAction, SIGNAL( triggered() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( next() ) ); */ + connect( m_playAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( play() ) ); + connect( m_pauseAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( pause() ) ); + connect( m_prevAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( previous() ) ); + connect( m_nextAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( next() ) ); */ - connect( ui->volumeSlider, SIGNAL( valueChanged( int ) ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( setVolume( int ) ) ); - connect( ui->prevButton, SIGNAL( clicked() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( previous() ) ); - connect( ui->playPauseButton, SIGNAL( clicked() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( play() ) ); - connect( ui->pauseButton, SIGNAL( clicked() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( pause() ) ); - connect( ui->nextButton, SIGNAL( clicked() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( next() ) ); - connect( ui->volumeLowButton, SIGNAL( clicked() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( lowerVolume() ) ); - connect( ui->volumeHighButton, SIGNAL( clicked() ), (QObject*)TomahawkApp::instance()->audioEngine(), SLOT( raiseVolume() ) ); + connect( ui->volumeSlider, SIGNAL( valueChanged( int ) ), (QObject*)APP->audioEngine(), SLOT( setVolume( int ) ) ); + connect( ui->prevButton, SIGNAL( clicked() ), (QObject*)APP->audioEngine(), SLOT( previous() ) ); + connect( ui->playPauseButton, SIGNAL( clicked() ), (QObject*)APP->audioEngine(), SLOT( play() ) ); + connect( ui->pauseButton, SIGNAL( clicked() ), (QObject*)APP->audioEngine(), SLOT( pause() ) ); + connect( ui->nextButton, SIGNAL( clicked() ), (QObject*)APP->audioEngine(), SLOT( next() ) ); + connect( ui->volumeLowButton, SIGNAL( clicked() ), (QObject*)APP->audioEngine(), SLOT( lowerVolume() ) ); + connect( ui->volumeHighButton, SIGNAL( clicked() ), (QObject*)APP->audioEngine(), SLOT( raiseVolume() ) ); connect( ui->repeatButton, SIGNAL( clicked() ), SLOT( onRepeatClicked() ) ); connect( ui->shuffleButton, SIGNAL( clicked() ), SLOT( onShuffleClicked() ) ); @@ -128,13 +128,13 @@ AudioControls::AudioControls( QWidget* parent ) connect( ui->albumLabel, SIGNAL( clicked() ), SLOT( onAlbumClicked() ) ); // - connect( (QObject*)TomahawkApp::instance()->audioEngine(), SIGNAL( loading( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackLoading( const Tomahawk::result_ptr& ) ) ); - connect( (QObject*)TomahawkApp::instance()->audioEngine(), SIGNAL( started( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackStarted( const Tomahawk::result_ptr& ) ) ); - connect( (QObject*)TomahawkApp::instance()->audioEngine(), SIGNAL( paused() ), SLOT( onPlaybackPaused() ) ); - connect( (QObject*)TomahawkApp::instance()->audioEngine(), SIGNAL( resumed() ), SLOT( onPlaybackResumed() ) ); - connect( (QObject*)TomahawkApp::instance()->audioEngine(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ) ); - connect( (QObject*)TomahawkApp::instance()->audioEngine(), SIGNAL( timerSeconds( unsigned int ) ), SLOT( onPlaybackTimer( unsigned int ) ) ); - connect( (QObject*)TomahawkApp::instance()->audioEngine(), SIGNAL( volumeChanged( int ) ), SLOT( onVolumeChanged( int ) ) ); + connect( (QObject*)APP->audioEngine(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( onPlaybackLoading( Tomahawk::result_ptr ) ) ); + connect( (QObject*)APP->audioEngine(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ) ); + connect( (QObject*)APP->audioEngine(), SIGNAL( paused() ), SLOT( onPlaybackPaused() ) ); + connect( (QObject*)APP->audioEngine(), SIGNAL( resumed() ), SLOT( onPlaybackResumed() ) ); + connect( (QObject*)APP->audioEngine(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ) ); + connect( (QObject*)APP->audioEngine(), SIGNAL( timerSeconds( unsigned int ) ), SLOT( onPlaybackTimer( unsigned int ) ) ); + connect( (QObject*)APP->audioEngine(), SIGNAL( volumeChanged( int ) ), SLOT( onVolumeChanged( int ) ) ); m_defaultCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" ) .scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); diff --git a/src/tomahawktrayicon.cpp b/src/tomahawktrayicon.cpp new file mode 100644 index 000000000..2698f4108 --- /dev/null +++ b/src/tomahawktrayicon.cpp @@ -0,0 +1,153 @@ +#include "tomahawktrayicon.h" + +#include + +#include "tomahawk/tomahawkapp.h" +#include "audio/audioengine.h" +#include "tomahawkwindow.h" + + +TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) + : QSystemTrayIcon( parent ) + , m_currentAnimationFrame( 0 ) +{ + QIcon icon( RESPATH "icons/tomahawk-icon-128x128.png" ); + setIcon( icon ); + + refreshToolTip(); + + m_contextMenu = new QMenu(); + setContextMenu( m_contextMenu ); + + m_playAction = m_contextMenu->addAction( tr( "Play" ) ); + m_pauseAction = m_contextMenu->addAction( tr( "Pause" ) ); + m_stopAction = m_contextMenu->addAction( tr( "Stop" ) ); + m_contextMenu->addSeparator(); + m_prevAction = m_contextMenu->addAction( tr( "Previous Track" ) ); + m_nextAction = m_contextMenu->addAction( tr( "Next Track" ) ); + m_contextMenu->addSeparator(); + m_quitAction = m_contextMenu->addAction( tr( "Quit" ) ); + + connect( (QObject*)APP->audioEngine(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( setResult( Tomahawk::result_ptr ) ) ); + + connect( m_playAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( play() ) ); + connect( m_pauseAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( pause() ) ); + connect( m_stopAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( stop() ) ); + connect( m_prevAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( previous() ) ); + connect( m_nextAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( next() ) ); + connect( m_quitAction, SIGNAL( triggered() ), (QObject*)APP, SLOT( quit() ) ); + + connect( &m_animationTimer, SIGNAL( timeout() ), SLOT( onAnimationTimer() ) ); + connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), SLOT( onActivated( QSystemTrayIcon::ActivationReason ) ) ); + + show(); +} + + +TomahawkTrayIcon::~TomahawkTrayIcon() +{ + delete m_contextMenu; +} + + +void +TomahawkTrayIcon::setResult( const Tomahawk::result_ptr& result ) +{ + m_currentTrack = result; + refreshToolTip(); +} + + +void +TomahawkTrayIcon::refreshToolTip() +{ + #ifdef Q_WS_MAC + // causes issues with OS X menubar, also none + // of the other OS X menubar icons have a tooltip + return; + #endif + + QString tip; + if ( !m_currentTrack.isNull() ) + { + tip = m_currentTrack->artist()->name() + " " + QChar( 8211 ) /*en dash*/ + " " + m_currentTrack->track(); + } + else + { + tip = tr( "Currently not playing." ); + } + + #ifdef WIN32 + // Good old crappy Win32 + tip.replace( "&", "&&&" ); + #endif + + setToolTip( tip ); +} + + +void +TomahawkTrayIcon::onAnimationTimer() +{ + /*if( m_animationPixmaps.isEmpty() ) + { + stopIpodScrobblingAnimation(); + Q_ASSERT( !"Animation should not be started without frames being loaded" ); + return; + } + + m_currentAnimationFrame++; + if( m_currentAnimationFrame >= m_animationPixmaps.count() ) + m_currentAnimationFrame = 0; + + setIcon( m_animationPixmaps.at( m_currentAnimationFrame ) );*/ +} + + +void +TomahawkTrayIcon::onActivated( QSystemTrayIcon::ActivationReason reason ) +{ + switch( reason ) + { + case QSystemTrayIcon::DoubleClick: + { + TomahawkWindow* mainwindow = APP->mainWindow(); + if ( mainwindow->isVisible() ) + { + mainwindow->hide(); + } + else + { + mainwindow->show(); + } + } + break; + + default: + break; + } +} + + +bool +TomahawkTrayIcon::event( QEvent* e ) +{ + // Beginning with Qt 4.3, QSystemTrayIcon supports wheel events, but only + // on X11. Let's make it adjust the volume. + if ( e->type() == QEvent::Wheel ) + { + if ( ((QWheelEvent*)e)->delta() > 0 ) + { + APP->audioEngine()->raiseVolume(); + } + else + { + APP->audioEngine()->lowerVolume(); + } + + return true; + } + + return QSystemTrayIcon::event( e ); +} + diff --git a/src/tomahawktrayicon.h b/src/tomahawktrayicon.h new file mode 100644 index 000000000..d975f93f2 --- /dev/null +++ b/src/tomahawktrayicon.h @@ -0,0 +1,45 @@ +#ifndef TOMAHAWK_TRAYICON_H +#define TOMAHAWK_TRAYICON_H + +#include +#include +#include + +#include "tomahawk/result.h" + +class TomahawkTrayIcon : public QSystemTrayIcon +{ + Q_OBJECT + +public: + TomahawkTrayIcon( QObject* parent ); + virtual bool event( QEvent* e ); + +public slots: + void setResult( const Tomahawk::result_ptr& result ); + +private slots: + void onAnimationTimer(); + void onActivated( QSystemTrayIcon::ActivationReason reason ); + +private: + void refreshToolTip(); + ~TomahawkTrayIcon(); + + QTimer m_animationTimer; + Tomahawk::result_ptr m_currentTrack; + + QList m_animationPixmaps; + int m_currentAnimationFrame; + + QMenu* m_contextMenu; + QAction* m_playAction; + QAction* m_pauseAction; + QAction* m_stopAction; + QAction* m_prevAction; + QAction* m_nextAction; + QAction* m_quitAction; +}; + +#endif // TOMAHAWK_TRAYICON_H + diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index e8d3729fc..dd064398b 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -29,6 +29,7 @@ #include "xspfloader.h" #include "proxystyle.h" #include "tomahawksettings.h" +#include "tomahawktrayicon.h" #include "widgetdragfilter.h" using namespace Tomahawk; @@ -40,6 +41,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) , m_topbar( new TopBar( this ) ) , m_audioControls( new AudioControls( this ) ) , m_playlistManager( new PlaylistManager( this ) ) + , m_trayIcon( new TomahawkTrayIcon( this ) ) { qApp->setStyle( new ProxyStyle() ); setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) ); diff --git a/src/tomahawkwindow.h b/src/tomahawkwindow.h index 02ed0b365..347fb7e6a 100644 --- a/src/tomahawkwindow.h +++ b/src/tomahawkwindow.h @@ -14,6 +14,7 @@ class QAction; class AudioControls; class PlaylistManager; class TopBar; +class TomahawkTrayIcon; namespace Ui { @@ -63,6 +64,7 @@ private: TopBar* m_topbar; AudioControls* m_audioControls; PlaylistManager* m_playlistManager; + TomahawkTrayIcon* m_trayIcon; QNetworkAccessManager m_nam; Tomahawk::result_ptr m_currentTrack;