diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8fd8b9afa..b7779d32b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -205,6 +205,7 @@ set(SOURCES ui/screensaver.cpp ui/settingsdialog.cpp ui/systemtrayicon.cpp + ui/windows7thumbbar.cpp widgets/autoexpandingtreeview.cpp widgets/busyindicator.cpp @@ -377,6 +378,7 @@ set(HEADERS ui/qtsystemtrayicon.h ui/settingsdialog.h ui/systemtrayicon.h + ui/windows7thumbbar.h widgets/autoexpandingtreeview.h widgets/busyindicator.h diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 598fa4eee..2604e0638 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -15,10 +15,6 @@ along with Clementine. If not, see . */ -#ifdef Q_OS_WIN32 -# define _WIN32_WINNT 0x0600 -#endif - #include "mainwindow.h" #include "ui_mainwindow.h" #include "core/backgroundstreams.h" @@ -81,6 +77,7 @@ #include "ui/qtsystemtrayicon.h" #include "ui/settingsdialog.h" #include "ui/systemtrayicon.h" +#include "ui/windows7thumbbar.h" #include "widgets/errordialog.h" #include "widgets/fileview.h" #include "widgets/multiloadingindicator.h" @@ -123,9 +120,6 @@ #ifdef Q_OS_WIN32 # include -# include -# include -# include #endif @@ -156,6 +150,7 @@ MainWindow::MainWindow( QWidget* parent) : QMainWindow(parent), ui_(new Ui_MainWindow), + thumbbar_(new Windows7ThumbBar(this)), tray_icon_(tray_icon), osd_(osd), task_manager_(task_manager), @@ -191,8 +186,7 @@ MainWindow::MainWindow( playlist_menu_(new QMenu(this)), library_sort_model_(new QSortFilterProxyModel(this)), track_position_timer_(new QTimer(this)), - was_maximized_(false), - taskbar_list_(NULL) + was_maximized_(false) { // Create some objects in the database thread playlist_backend_ = new PlaylistBackend; @@ -499,6 +493,16 @@ MainWindow::MainWindow( connect(tray_icon_, SIGNAL(ShowHide()), SLOT(ToggleShowHide())); connect(tray_icon_, SIGNAL(ChangeVolume(int)), SLOT(VolumeWheelEvent(int))); + // Windows 7 thumbbar buttons + thumbbar_->SetActions(QList() + << ui_->action_previous_track + << ui_->action_play_pause + << ui_->action_stop + << ui_->action_next_track + << NULL // spacer + << ui_->action_love + << ui_->action_ban); + #if (defined(Q_OS_DARWIN) && defined(HAVE_SPARKLE)) || defined(Q_OS_WIN32) // Add check for updates item to application menu. QAction* check_updates = ui_->menu_tools->addAction(tr("Check for updates...")); @@ -1651,51 +1655,8 @@ void MainWindow::ShowScriptDialog() { } #ifdef Q_OS_WIN32 -static const int kTaskbarIconSize = 16; - -static void SetButton(const QIcon& icon, const QString& tooltip, uint id, - THUMBBUTTON* button) { - button->dwMask = THUMBBUTTONMASK(THB_ICON | THB_TOOLTIP | THB_FLAGS); - button->iId = id; - button->dwFlags = THBF_ENABLED; - button->hIcon = icon.pixmap(kTaskbarIconSize).toWinHICON(); - tooltip.toWCharArray(button->szTip); -} - -bool MainWindow::winEvent(MSG* m, long* result) { - static UINT sTaskbarButtonCreated = WM_NULL; - - if (sTaskbarButtonCreated == WM_NULL) { - // Compute the value for the TaskbarButtonCreated message - sTaskbarButtonCreated = RegisterWindowMessage("TaskbarButtonCreated"); - } - - if (m->message == sTaskbarButtonCreated) { - if (!taskbar_list_) { - // Get the interface - if (CoCreateInstance(CLSID_ITaskbarList, NULL, CLSCTX_ALL, - IID_ITaskbarList3, (void**) &taskbar_list_)) { - qWarning() << "Error creating the ITaskbarList3 interface"; - return false; - } - - ITaskbarList3* taskbar_list = reinterpret_cast(taskbar_list_); - if (taskbar_list->HrInit()) { - taskbar_list->Release(); - taskbar_list_ = NULL; - return false; - } - - // Add the playback control buttons - THUMBBUTTON buttons[4] = {}; - SetButton(IconLoader::Load("media-skip-backward"), tr("Previous track"), 0, &buttons[0]); - SetButton(IconLoader::Load("media-playback-start"), tr("Pause"), 1, &buttons[1]); - SetButton(IconLoader::Load("media-playback-stop"), tr("Stop"), 2, &buttons[2]); - SetButton(IconLoader::Load("media-skip-forward"), tr("Next track"), 3, &buttons[3]); - - taskbar_list->ThumbBarAddButtons(winId(), 4, buttons); - } - } +bool MainWindow::winEvent(MSG* msg, long*) { + thumbbar_->HandleWinEvent(msg); return false; } #endif // Q_OS_WIN32 diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 9b9d1e2ed..4bbdb83ba 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -67,6 +67,7 @@ class TaskManager; class TranscodeDialog; class VisualisationContainer; class WiimotedevShortcuts; +class Windows7ThumbBar; class Ui_MainWindow; class QSortFilterProxyModel; @@ -216,6 +217,7 @@ class MainWindow : public QMainWindow, public PlatformInterface { private: Ui_MainWindow* ui_; + Windows7ThumbBar* thumbbar_; SystemTrayIcon* tray_icon_; OSD* osd_; @@ -284,9 +286,6 @@ class MainWindow : public QMainWindow, public PlatformInterface { bool autoclear_playlist_; BackgroundStreams* background_streams_; - - // Really an ITaskbarList3* but I don't want to have to include windows.h here - void* taskbar_list_; }; #endif // MAINWINDOW_H diff --git a/src/ui/windows7thumbbar.cpp b/src/ui/windows7thumbbar.cpp new file mode 100644 index 000000000..fd14e3ca9 --- /dev/null +++ b/src/ui/windows7thumbbar.cpp @@ -0,0 +1,140 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "windows7thumbbar.h" + +#include +#include + +#ifdef Q_OS_WIN32 +# define _WIN32_WINNT 0x0600 +# include +# include +# include +#endif // Q_OS_WIN32 + + +const int Windows7ThumbBar::kIconSize = 16; +const int Windows7ThumbBar::kMaxButtonCount = 7; + + +Windows7ThumbBar::Windows7ThumbBar(QWidget* widget) + : QObject(widget), + widget_(widget), + button_created_message_id_(0), + taskbar_list_(NULL) +{ +} + +void Windows7ThumbBar::SetActions(const QList& actions) { +#ifdef Q_OS_WIN32 + Q_ASSERT(actions.count() <= kMaxButtonCount); + + actions_ = actions; + foreach (QAction* action, actions) { + if (action) { + connect(action, SIGNAL(changed()), SLOT(ActionChanged())); + } + } + +#endif // Q_OS_WIN32 +} + +#ifdef Q_OS_WIN32 +static void SetupButton(const QAction* action, THUMBBUTTON* button) { + if (action) { + button->hIcon = action->icon().pixmap(Windows7ThumbBar::kIconSize).toWinHICON(); + button->dwFlags = action->isEnabled() ? THBF_ENABLED : THBF_DISABLED; + action->text().toWCharArray(button->szTip); + button->szTip[action->text().count()] = '\0'; + + if (!action->isVisible()) { + button->dwFlags = THUMBBUTTONFLAGS(button->dwFlags | THBF_HIDDEN); + } + } else { + button->hIcon = 0; + button->szTip[0] = '\0'; + button->dwFlags = THBF_NOBACKGROUND; + } +} +#endif // Q_OS_WIN32 + +void Windows7ThumbBar::HandleWinEvent(MSG* msg) { +#ifdef Q_OS_WIN32 + if (button_created_message_id_ == 0) { + // Compute the value for the TaskbarButtonCreated message + button_created_message_id_ = RegisterWindowMessage("TaskbarButtonCreated"); + } + + if (msg->message == button_created_message_id_) { + if (!taskbar_list_) { + // Create the taskbar list for the first time + if (CoCreateInstance(CLSID_ITaskbarList, NULL, CLSCTX_ALL, + IID_ITaskbarList3, (void**) &taskbar_list_)) { + qWarning() << "Error creating the ITaskbarList3 interface"; + return; + } + + ITaskbarList3* taskbar_list = reinterpret_cast(taskbar_list_); + if (taskbar_list->HrInit()) { + taskbar_list->Release(); + taskbar_list_ = NULL; + return; + } + + // Add the buttons + THUMBBUTTON buttons[kMaxButtonCount]; + for (int i=0 ; idwMask = THUMBBUTTONMASK(THB_ICON | THB_TOOLTIP | THB_FLAGS); + button->iId = i; + SetupButton(action, button); + } + + taskbar_list->ThumbBarAddButtons(widget_->winId(), actions_.count(), buttons); + } + } else if (msg->message == WM_COMMAND) { + const int button_id = LOWORD(msg->wParam); + + if (button_id >= 0 && button_id < actions_.count()) { + actions_[button_id]->activate(QAction::Trigger); + } + } +#endif // Q_OS_WIN32 +} + +void Windows7ThumbBar::ActionChanged() { +#ifdef Q_OS_WIN32 + if (!taskbar_list_) + return; + ITaskbarList3* taskbar_list = reinterpret_cast(taskbar_list_); + + THUMBBUTTON buttons[kMaxButtonCount]; + for (int i=0 ; idwMask = THUMBBUTTONMASK(THB_ICON | THB_TOOLTIP | THB_FLAGS); + button->iId = i; + SetupButton(action, button); + } + + taskbar_list->ThumbBarUpdateButtons(widget_->winId(), actions_.count(), buttons); +#endif // Q_OS_WIN32 +} diff --git a/src/ui/windows7thumbbar.h b/src/ui/windows7thumbbar.h new file mode 100644 index 000000000..70b7f03bc --- /dev/null +++ b/src/ui/windows7thumbbar.h @@ -0,0 +1,59 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#ifndef WINDOWS7THUMBBAR_H +#define WINDOWS7THUMBBAR_H + +#include +#include + +#ifndef Q_OS_WIN32 + typedef void MSG; +#endif // Q_OS_WIN32 + +class Windows7ThumbBar : public QObject { + Q_OBJECT + +public: + // Creates a list of buttons in the taskbar icon for this window. Does + // nothing and is safe to use on other operating systems too. + Windows7ThumbBar(QWidget* widget = 0); + + static const int kIconSize; + static const int kMaxButtonCount; + + // You must call this in the parent widget's constructor before returning + // to the event loop. If an action is NULL it becomes a spacer. + void SetActions(const QList& actions); + + // Call this from the parent's winEvent() function. + void HandleWinEvent(MSG* msg); + +private slots: + void ActionChanged(); + +private: + QWidget* widget_; + QList actions_; + + unsigned int button_created_message_id_; + + // Really an ITaskbarList3* but I don't want to have to include windows.h here + void* taskbar_list_; +}; + +#endif // WINDOWS7THUMBBAR_H