Improve systray activation behavior; more refactoring
authorManuel Nickschas <sputnick@quassel-irc.org>
Sun, 14 Feb 2010 19:10:07 +0000 (20:10 +0100)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sun, 14 Feb 2010 19:15:55 +0000 (20:15 +0100)
* Move the methods for forcing window activation into SystemTray
* Improve behavior on clicking the tray icon
* Improve notification activation in Qt-only Quassel

12 files changed:
src/qtui/indicatornotificationbackend.cpp
src/qtui/indicatornotificationbackend.h
src/qtui/legacysystemtray.cpp
src/qtui/legacysystemtray.h
src/qtui/mainwin.cpp
src/qtui/mainwin.h
src/qtui/qtui.cpp
src/qtui/systemtray.cpp
src/qtui/systemtray.h
src/qtui/systraynotificationbackend.cpp
src/uisupport/graphicalui.cpp
src/uisupport/graphicalui.h

index 41fce5c..df7b534 100644 (file)
@@ -51,7 +51,7 @@ IndicatorNotificationBackend::IndicatorNotificationBackend(QObject *parent)
     .arg(XSTR(XDG_APPS_INSTALL_DIR))
     .arg(QCoreApplication::applicationFilePath().section('/', -1));
   _server->setDesktopFile(desktopFile);
-  connect(_server, SIGNAL(serverDisplay()), QtUi::mainWindow(), SLOT(forceActivated()));
+  connect(_server, SIGNAL(serverDisplay()), SLOT(activateMainWidget()));
 
   if (_enabled) {
     _server->show();
@@ -62,6 +62,10 @@ IndicatorNotificationBackend::~IndicatorNotificationBackend() {
   qDeleteAll(_indicatorHash);
 }
 
+void IndicatorNotificationBackend::activateMainWidget() {
+  GraphicalUi::activateMainWidget();
+}
+
 void IndicatorNotificationBackend::notify(const Notification &notification) {
   if(!_enabled) {
     return;
index d187ff1..4ccbe44 100644 (file)
@@ -49,6 +49,7 @@ public:
   virtual SettingsPage *createConfigWidget() const;
 
 private slots:
+  void activateMainWidget();
   void enabledChanged(const QVariant &);
   void indicatorDisplayed(QIndicate::Indicator *);
 
index b57fd99..18bf02c 100644 (file)
 #include "legacysystemtray.h"
 #include "qtui.h"
 
-LegacySystemTray::LegacySystemTray(QObject *parent)
+LegacySystemTray::LegacySystemTray(QWidget *parent)
   : SystemTray(parent),
   _blinkState(false),
   _isVisible(true)
 {
 #ifndef HAVE_KDE
-  _trayIcon = new QSystemTrayIcon(QtUi::mainWindow());
+  _trayIcon = new QSystemTrayIcon(associatedWidget());
 #else
-  _trayIcon = new KSystemTrayIcon(QtUi::mainWindow());
+  _trayIcon = new KSystemTrayIcon(associatedWidget());
   // We don't want to trigger a minimize if a highlight is pending, so we brutally remove the internal connection for that
   disconnect(_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
                  _trayIcon, SLOT(activateOrHide(QSystemTrayIcon::ActivationReason)));
@@ -54,6 +54,8 @@ LegacySystemTray::LegacySystemTray(QObject *parent)
 void LegacySystemTray::init() {
   if(mode() == Invalid) // derived class hasn't set a mode itself
     setMode(Legacy);
+
+  SystemTray::init();
 }
 
 void LegacySystemTray::syncLegacyIcon() {
@@ -71,6 +73,13 @@ void LegacySystemTray::setVisible(bool visible) {
   }
 }
 
+bool LegacySystemTray::isVisible() const {
+  if(mode() == Legacy) {
+    return _trayIcon->isVisible();
+  }
+  return false;
+}
+
 void LegacySystemTray::setMode(Mode mode_) {
   SystemTray::setMode(mode_);
 
@@ -113,18 +122,7 @@ void LegacySystemTray::on_blinkTimeout() {
 }
 
 void LegacySystemTray::on_activated(QSystemTrayIcon::ActivationReason reason) {
-  emit activated((ActivationReason)reason);
-
-  if(reason == QSystemTrayIcon::Trigger && !isActivationInhibited()) {
-
-#  ifdef HAVE_KDE
-     // the slot is private, but meh, who cares :)
-     QMetaObject::invokeMethod(_trayIcon, "activateOrHide", Q_ARG(QSystemTrayIcon::ActivationReason, QSystemTrayIcon::Trigger));
-#  else
-     QtUi::mainWindow()->toggleMinimizedToTray();
-#  endif
-
-  }
+  activate((SystemTray::ActivationReason)reason);
 }
 
 void LegacySystemTray::showMessage(const QString &title, const QString &message, SystemTray::MessageIcon icon, int millisecondsTimeoutHint) {
index e84a917..47c5f11 100644 (file)
@@ -37,10 +37,11 @@ class LegacySystemTray : public SystemTray {
   Q_OBJECT
 
 public:
-  LegacySystemTray(QObject *parent = 0);
+  explicit LegacySystemTray(QWidget *parent);
   virtual ~LegacySystemTray() {}
   virtual void init();
 
+  virtual bool isVisible() const;
   virtual inline bool isSystemTrayAvailable() const;
   virtual Icon stateIcon() const; // overriden to care about blinkState
 
@@ -49,6 +50,8 @@ public slots:
   virtual void setVisible(bool visible = true);
   virtual void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int millisecondsTimeoutHint = 10000);
 
+protected slots:
+
 protected:
   virtual void setMode(Mode mode);
 
index d943bfa..3ea5d90 100644 (file)
@@ -135,10 +135,6 @@ MainWin::MainWin(QWidget *parent)
     _awayLog(0),
     _layoutLoaded(false)
 {
-#ifdef Q_WS_WIN
-  dwTickCount = 0;
-#endif
-
   QtUiSettings uiSettings;
   QString style = uiSettings.value("Style", QString()).toString();
   if(!style.isEmpty()) {
@@ -279,8 +275,8 @@ void MainWin::restoreStateFromSettings(UiSettings &s) {
   move(_normalPos);
 #endif
 
-  if(s.value("MainWinHidden").toBool())
-    hideToTray();
+  if(s.value("MainWinHidden").toBool() && systemTray()->isSystemTrayAvailable())
+    systemTray()->hideMainWidget();
   else if(s.value("MainWinMinimized").toBool())
     showMinimized();
   else if(maximized)
@@ -749,9 +745,7 @@ void MainWin::setConnectedState() {
 
   _coreConnectionStatusWidget->setVisible(!Client::internalCore());
   updateIcon();
-#ifndef QT_NO_SYSTEMTRAYICON
   systemTray()->setState(SystemTray::Active);
-#endif
 
   if(Client::networkIds().isEmpty()) {
     IrcConnectionWizard *wizard = new IrcConnectionWizard(this, Qt::Sheet);
@@ -1011,86 +1005,17 @@ void MainWin::resizeEvent(QResizeEvent *event) {
 }
 
 void MainWin::closeEvent(QCloseEvent *event) {
-#ifndef QT_NO_SYSTEMTRAYICON
   QtUiSettings s;
   QtUiApplication* app = qobject_cast<QtUiApplication*> qApp;
   Q_ASSERT(app);
-  if(!app->isAboutToQuit() && s.value("UseSystemTrayIcon").toBool() && s.value("MinimizeOnClose").toBool()) {
-    hideToTray();
+  if(!app->isAboutToQuit()
+    && s.value("UseSystemTrayIcon").toBool() && s.value("MinimizeOnClose").toBool() && systemTray()->isSystemTrayAvailable()) {
+    systemTray()->hideMainWidget();
     event->ignore();
   } else {
     event->accept();
     quit();
   }
-#else
-  event->accept();
-  quit();
-#endif
-}
-
-void MainWin::changeEvent(QEvent *event) {
-#ifdef Q_WS_WIN
-  if(event->type() == QEvent::ActivationChange)
-    dwTickCount = GetTickCount();  // needed for toggleMinimizedToTray()
-#endif
-
-  QMainWindow::changeEvent(event);
-}
-
-void MainWin::hideToTray() {
-  if(!systemTray()->isSystemTrayAvailable()) {
-    qWarning() << Q_FUNC_INFO << "was called with no SystemTray available!";
-    return;
-  }
-  hide();
-  systemTray()->setVisible();
-}
-
-void MainWin::toggleMinimizedToTray() {
-#ifdef Q_WS_WIN
-  // the problem is that we lose focus when the systray icon is activated
-  // and we don't know the former active window
-  // therefore we watch for activation event and use our stopwatch :)
-  // courtesy: KSystemTrayIcon
-  if(GetTickCount() - dwTickCount >= 300)
-    // we weren't active in the last 300ms -> activate
-    forceActivated();
-  else
-    hideToTray();
-
-#else
-
-  if(!isVisible() || isMinimized())
-    // restore
-    forceActivated();
-  else
-    hideToTray();
-
-#endif
-}
-
-void MainWin::forceActivated() {
-#ifdef HAVE_KDE
-  show();
-  KWindowSystem::forceActiveWindow(winId());
-#else
-
-#ifdef Q_WS_X11
-  // Bypass focus stealing prevention
-  QX11Info::setAppUserTime(QX11Info::appTime());
-#endif
-
-  if(windowState() & Qt::WindowMinimized) {
-    // restore
-    setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
-  }
-
-  // this does not actually work on all platforms... and causes more evil than good
-  // move(frameGeometry().topLeft()); // avoid placement policies
-  show();
-  raise();
-  activateWindow();
-#endif /* HAVE_KDE */
 }
 
 void MainWin::messagesInserted(const QModelIndex &parent, int start, int end) {
index 4929e5c..53548bf 100644 (file)
 #  include <QMainWindow>
 #endif
 
-#ifdef Q_WS_WIN
-#  include <windows.h>
-#endif
-
 #include "qtui.h"
 #include "titlesetter.h"
 #include "uisettings.h"
@@ -88,17 +84,12 @@ class MainWin
 
   public slots:
     void showStatusBarMessage(const QString &message);
-    void toggleMinimizedToTray();
-
-    //! Bring window to front and focus it
-    void forceActivated();
 
     //! Quit application
     void quit();
 
   protected:
     void closeEvent(QCloseEvent *event);
-    void changeEvent(QEvent *event);
     void moveEvent(QMoveEvent *event);
     void resizeEvent(QResizeEvent *event);
 
@@ -188,8 +179,6 @@ class MainWin
     void updateIcon();
     void enableMenus();
 
-    void hideToTray();
-
     QList<BufferViewDock *> _bufferViews;
     BufferWidget *_bufferWidget;
     NickListWidget *_nickListWidget;
@@ -208,10 +197,6 @@ class MainWin
     QSize _normalSize; //!< Size of the non-maximized window
     QPoint _normalPos; //!< Position of the non-maximized window
 
-#ifdef Q_WS_WIN
-    DWORD dwTickCount;
-#endif
-
     BufferHotListFilter *_bufferHotList;
 
     friend class QtUi;
index 5495758..30064d6 100644 (file)
@@ -167,5 +167,5 @@ void QtUi::notificationActivated(uint notificationId) {
   }
   closeNotification(notificationId);
 
-  mainWindow()->forceActivated();
+  activateMainWidget();
 }
index 9944823..27aeb08 100644 (file)
@@ -2,6 +2,9 @@
  *   Copyright (C) 2005-2010 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
+ *   This contains code from KStatusNotifierItem, part of the KDE libs     *
+ *   Copyright (C) 2009 Marco Martin <notmart@gmail.com>                   *
+ *                                                                         *
  *   This program 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 2 of the License, or     *
 #include "client.h"
 #include "iconloader.h"
 #include "qtui.h"
-#include "qtuisettings.h"
 
-SystemTray::SystemTray(QObject *parent)
+#ifdef HAVE_KDE
+#  include <KWindowInfo>
+#  include <KWindowSystem>
+#endif
+
+SystemTray::SystemTray(QWidget *parent)
 : QObject(parent),
   _mode(Invalid),
   _state(Passive),
@@ -35,15 +42,31 @@ SystemTray::SystemTray(QObject *parent)
   _passiveIcon(DesktopIcon("quassel_inactive")),
   _activeIcon(DesktopIcon("quassel")),
   _needsAttentionIcon(DesktopIcon("quassel_message")),
-  _trayMenu(0)
+  _trayMenu(0),
+  _associatedWidget(parent)
 {
+  Q_ASSERT(parent);
+
+#ifdef Q_WS_WIN
+  _dwTickCount = 0;
+  associatedWidget()->installEventFilter(this);
+#endif
+
   qApp->installEventFilter(this);
 }
 
 SystemTray::~SystemTray() {
+#ifdef Q_WS_WIN
+  associatedWidget()->removeEventFilter(this);
+#endif
+
   _trayMenu->deleteLater();
 }
 
+QWidget *SystemTray::associatedWidget() const {
+  return _associatedWidget;
+}
+
 void SystemTray::setTrayMenu(QMenu *menu) {
   if(menu)
     _trayMenu = menu;
@@ -59,7 +82,6 @@ void SystemTray::setTrayMenu(QMenu *menu) {
   _trayMenu->addSeparator();
   _trayMenu->addAction(coll->action("Quit"));
 #endif /* HAVE_KDE */
-
 }
 
 void SystemTray::setMode(Mode mode_) {
@@ -119,10 +141,133 @@ void SystemTray::showMessage(const QString &title, const QString &message, Messa
   Q_UNUSED(millisecondsTimeoutHint)
 }
 
+void SystemTray::activate(SystemTray::ActivationReason reason) {
+
+  emit activated(reason);
+
+  if(reason == Trigger && !isActivationInhibited()) {
+    toggleMainWidget();
+  }
+}
+
 bool SystemTray::eventFilter(QObject *obj, QEvent *event) {
-  Q_UNUSED(obj);
-  if(event->type() == QEvent::MouseButtonRelease) {
+  if(event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonRelease) {
     _inhibitActivation = false;
   }
-  return false;
+#ifdef Q_WS_WIN
+  if(obj == associatedWidget() && event->type() == QEvent::ActivationChange) {
+    _dwTickCount = GetTickCount();
+  }
+#endif
+  return QObject::eventFilter(obj, event);
+}
+
+// Code taken from KStatusNotifierItem for handling minimize/restore
+
+bool SystemTray::checkVisibility(bool perform) {
+#ifdef Q_WS_WIN
+  // the problem is that we lose focus when the systray icon is activated
+  // and we don't know the former active window
+  // therefore we watch for activation event and use our stopwatch :)
+  if(GetTickCount() - _dwTickCount < 300) {
+    // we were active in the last 300ms -> hide it
+    minimizeRestore(false);
+  } else {
+    minimizeRestore(true);
+  }
+
+#elif defined(HAVE_KDE) && defined(Q_WS_X11)
+  KWindowInfo info1 = KWindowSystem::windowInfo(associatedWidget()->winId(), NET::XAWMState | NET::WMState | NET::WMDesktop);
+  // mapped = visible (but possibly obscured)
+  bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized();
+
+  //    - not mapped -> show, raise, focus
+  //    - mapped
+  //        - obscured -> raise, focus
+  //        - not obscured -> hide
+  //info1.mappingState() != NET::Visible -> window on another desktop?
+  if(!mapped) {
+    if(perform)
+      minimizeRestore(true);
+    return true;
+
+  } else {
+    QListIterator< WId > it (KWindowSystem::stackingOrder());
+    it.toBack();
+    while(it.hasPrevious()) {
+      WId id = it.previous();
+      if(id == associatedWidget()->winId())
+        break;
+
+      KWindowInfo info2 = KWindowSystem::windowInfo(id, NET::WMDesktop | NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType);
+
+      if(info2.mappingState() != NET::Visible)
+        continue; // not visible on current desktop -> ignore
+
+      if(!info2.geometry().intersects(associatedWidget()->geometry()))
+        continue; // not obscuring the window -> ignore
+
+      if(!info1.hasState(NET::KeepAbove) && info2.hasState(NET::KeepAbove))
+        continue; // obscured by window kept above -> ignore
+
+      NET::WindowType type = info2.windowType(NET::NormalMask | NET::DesktopMask
+                                              | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
+                                              | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask);
+
+      if(type == NET::Dock || type == NET::TopMenu)
+        continue; // obscured by dock or topmenu -> ignore
+
+      if(perform) {
+        KWindowSystem::raiseWindow(associatedWidget()->winId());
+        KWindowSystem::activateWindow(associatedWidget()->winId());
+      }
+      return true;
+    }
+
+    //not on current desktop?
+    if(!info1.isOnCurrentDesktop()) {
+      if(perform)
+        KWindowSystem::activateWindow(associatedWidget()->winId());
+      return true;
+    }
+
+    if(perform)
+      minimizeRestore(false); // hide
+    return false;
+  }
+#else
+
+  if(!associatedWidget()->isVisible() || associatedWidget()->isMinimized()) {
+    if(perform)
+      minimizeRestore(true);
+    return true;
+  } else {
+    if(perform)
+      minimizeRestore(false);
+    return false;
+  }
+
+#endif
+
+  return true;
+}
+
+void SystemTray::minimizeRestore(bool show) {
+  if(show)
+    GraphicalUi::activateMainWidget();
+  else {
+    if(isSystemTrayAvailable()) {
+      if(!isVisible())
+        setVisible();
+      GraphicalUi::hideMainWidget();
+    }
+  }
+}
+
+void SystemTray::hideMainWidget() {
+  minimizeRestore(false);
+}
+
+void SystemTray::toggleMainWidget() {
+  checkVisibility(true);
 }
index b2b0afb..d610c48 100644 (file)
 
 #include "icon.h"
 
+#ifdef Q_WS_WIN
+#  include <windows.h>
+#endif
+
 class QMenu;
 
 class SystemTray : public QObject {
   Q_OBJECT
+  Q_ENUMS(State Mode MessageIcon ActivationReason)
 
 public:
   enum State {
@@ -58,7 +63,7 @@ public:
     MiddleClick
   };
 
-  SystemTray(QObject *parent = 0);
+  explicit SystemTray(QWidget *parent);
   virtual ~SystemTray();
   virtual void init() {}
 
@@ -68,13 +73,18 @@ public:
 
   void setAlert(bool alerted);
   inline void setInhibitActivation();
+  inline virtual bool isVisible() const { return false; }
   inline bool isActivationInhibited() const;
 
+  QWidget *associatedWidget() const;
+
 public slots:
   virtual void setState(State);
   virtual void setVisible(bool visible = true);
   virtual void setToolTip(const QString &title, const QString &subtitle);
   virtual void showMessage(const QString &title, const QString &message, MessageIcon icon = Information, int millisecondsTimeoutHint = 10000);
+  void toggleMainWidget();
+  void hideMainWidget();
 
 signals:
   void activated(SystemTray::ActivationReason);
@@ -82,6 +92,11 @@ signals:
   void toolTipChanged(const QString &title, const QString &subtitle);
   void messageClicked();
 
+protected slots:
+  virtual void activate(SystemTray::ActivationReason = Trigger);
+
+  void minimizeRestore(bool restore);
+
 protected:
   virtual void setMode(Mode mode);
   inline Mode mode() const;
@@ -98,6 +113,8 @@ protected:
 private slots:
 
 private:
+  bool checkVisibility(bool performToggle = true);
+
   Mode _mode;
   State _state;
 
@@ -107,6 +124,12 @@ private:
   Icon _passiveIcon, _activeIcon, _needsAttentionIcon;
 
   QMenu *_trayMenu;
+  QWidget *_associatedWidget;
+
+#ifdef Q_WS_WIN
+    DWORD _dwTickCount;
+#endif
+
 };
 
 // inlines
index 7a8f993..a451665 100644 (file)
@@ -40,9 +40,9 @@ SystrayNotificationBackend::SystrayNotificationBackend(QObject *parent)
   notificationSettings.notify("Systray/ShowBubble", this, SLOT(showBubbleChanged(const QVariant &)));
   notificationSettings.notify("Systray/Animate", this, SLOT(animateChanged(const QVariant &)));
 
-  connect(QtUi::mainWindow()->systemTray(), SIGNAL(messageClicked()), SLOT(notificationActivated()));
   connect(QtUi::mainWindow()->systemTray(), SIGNAL(activated(SystemTray::ActivationReason)),
                                             SLOT(notificationActivated(SystemTray::ActivationReason)));
+  connect(QtUi::mainWindow()->systemTray(), SIGNAL(messageClicked()), SLOT(notificationActivated()));
 }
 
 void SystrayNotificationBackend::notify(const Notification &notification) {
@@ -91,7 +91,7 @@ void SystrayNotificationBackend::closeBubble() {
 }
 
 void SystrayNotificationBackend::notificationActivated() {
-  if(QtUi::mainWindow()->systemTray()->isAlerted()) {
+  if(QtUi::mainWindow()->systemTray()->isAlerted() && !QtUi::mainWindow()->systemTray()->isActivationInhibited()) {
     QtUi::mainWindow()->systemTray()->setInhibitActivation();
     uint id = _notifications.count()? _notifications.last().notificationId : 0;
     emit activated(id);
index 53042b8..40921cf 100644 (file)
 #include "actioncollection.h"
 #include "contextmenuactionprovider.h"
 
+#ifdef Q_WS_X11
+#  include <QX11Info>
+#endif
+#ifdef HAVE_KDE
+#  include <KWindowInfo>
+#  include <KWindowSystem>
+#endif
+
 QWidget *GraphicalUi::_mainWidget = 0;
 QHash<QString, ActionCollection *> GraphicalUi::_actionCollections;
 ContextMenuActionProvider *GraphicalUi::_contextMenuActionProvider = 0;
 ToolBarActionProvider *GraphicalUi::_toolBarActionProvider = 0;
 UiStyle *GraphicalUi::_uiStyle = 0;
+bool GraphicalUi::_onAllDesktops = false;
 
 GraphicalUi::GraphicalUi(QObject *parent) : AbstractUi(parent)
 {
@@ -59,3 +68,55 @@ void GraphicalUi::setToolBarActionProvider(ToolBarActionProvider *provider) {
 void GraphicalUi::setUiStyle(UiStyle *style) {
   _uiStyle = style;
 }
+
+void GraphicalUi::activateMainWidget() {
+#ifdef HAVE_KDE
+#  ifdef Q_WS_X11
+    KWindowInfo info = KWindowSystem::windowInfo(mainWidget()->winId(), NET::WMDesktop | NET::WMFrameExtents);
+    if(_onAllDesktops) {
+      KWindowSystem::setOnAllDesktops(mainWidget()->winId(), true);
+    } else {
+      KWindowSystem::setCurrentDesktop(info.desktop());
+    }
+
+    mainWidget()->move(info.frameGeometry().topLeft()); // avoid placement policies
+    mainWidget()->show();
+    mainWidget()->raise();
+    KWindowSystem::raiseWindow(mainWidget()->winId());
+    KWindowSystem::activateWindow(mainWidget()->winId());
+#  else
+    mainWidget()->show();
+    KWindowSystem::raiseWindow(mainWidget()->winId());
+    KWindowSystem::forceActiveWindow(mainWidget()->winId());
+#  endif
+
+#else /* HAVE_KDE */
+
+#ifdef Q_WS_X11
+  // Bypass focus stealing prevention
+  QX11Info::setAppUserTime(QX11Info::appTime());
+#endif
+
+  if(mainWidget()->windowState() & Qt::WindowMinimized) {
+    // restore
+    mainWidget()->setWindowState((mainWidget()->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
+  }
+
+  // this does not actually work on all platforms... and causes more evil than good
+  // mainWidget()->move(mainWidget()->frameGeometry().topLeft()); // avoid placement policies
+  mainWidget()->show();
+  mainWidget()->raise();
+  mainWidget()->activateWindow();
+
+#endif /* HAVE_KDE */
+}
+
+void GraphicalUi::hideMainWidget() {
+
+#if defined(HAVE_KDE) && defined(Q_WS_X11)
+  KWindowInfo info = KWindowSystem::windowInfo(mainWidget()->winId(), NET::WMDesktop | NET::WMFrameExtents);
+  _onAllDesktops = info.onAllDesktops();
+#endif
+
+  mainWidget()->hide();
+}
index f1fef7b..9832d10 100644 (file)
@@ -45,6 +45,13 @@ public:
   inline static ContextMenuActionProvider *contextMenuActionProvider();
   inline static ToolBarActionProvider *toolBarActionProvider();
   inline static UiStyle *uiStyle();
+  inline static QWidget *mainWidget();
+
+  //! Force the main widget to the front and focus it (may not work in all window systems)
+  static void activateMainWidget();
+
+  //! Hide main widget (storing the current desktop if possible)
+  static void hideMainWidget();
 
 protected:
   //! This is the widget we associate global actions with, typically the main window
@@ -60,6 +67,7 @@ private:
   static ContextMenuActionProvider *_contextMenuActionProvider;
   static ToolBarActionProvider *_toolBarActionProvider;
   static UiStyle *_uiStyle;
+  static bool _onAllDesktops;
 };
 
 ContextMenuActionProvider *GraphicalUi::contextMenuActionProvider() {
@@ -74,4 +82,8 @@ UiStyle *GraphicalUi::uiStyle() {
   return _uiStyle;
 }
 
+QWidget *GraphicalUi::mainWidget() {
+  return _mainWidget;
+}
+
 #endif