X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fuisupport%2Fgraphicalui.cpp;h=5d9a4198260954bedc4a03dbbc5e554e13a32879;hp=40921cff39b8f4df7cea1dfd7ef4cb07f22872e2;hb=2e9492d9ef198bde37da1f858602ab9624c0a12a;hpb=30063c5a63c6111787258b5c4ba8acdb03008667 diff --git a/src/uisupport/graphicalui.cpp b/src/uisupport/graphicalui.cpp index 40921cff..5d9a4198 100644 --- a/src/uisupport/graphicalui.cpp +++ b/src/uisupport/graphicalui.cpp @@ -1,7 +1,10 @@ /*************************************************************************** - * Copyright (C) 2005-09 by the Quassel Project * + * 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 * + * * * 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 * @@ -31,6 +34,7 @@ # include #endif +GraphicalUi *GraphicalUi::_instance = 0; QWidget *GraphicalUi::_mainWidget = 0; QHash GraphicalUi::_actionCollections; ContextMenuActionProvider *GraphicalUi::_contextMenuActionProvider = 0; @@ -38,11 +42,23 @@ ToolBarActionProvider *GraphicalUi::_toolBarActionProvider = 0; UiStyle *GraphicalUi::_uiStyle = 0; bool GraphicalUi::_onAllDesktops = false; -GraphicalUi::GraphicalUi(QObject *parent) : AbstractUi(parent) -{ +GraphicalUi::GraphicalUi(QObject *parent) : AbstractUi(parent) { + Q_ASSERT(!_instance); + _instance = this; + +#ifdef Q_WS_WIN + _dwTickCount = 0; + mainWidget()->installEventFilter(this); +#endif } +GraphicalUi::~GraphicalUi() { +#ifdef Q_WS_WIN + mainWidget()->removeEventFilter(this); +#endif +} + ActionCollection *GraphicalUi::actionCollection(const QString &category) { if(_actionCollections.contains(category)) return _actionCollections.value(category); @@ -69,6 +85,112 @@ void GraphicalUi::setUiStyle(UiStyle *style) { _uiStyle = style; } +bool GraphicalUi::eventFilter(QObject *obj, QEvent *event) { +#ifdef Q_WS_WIN + if(obj == mainWidget() && event->type() == QEvent::ActivationChange) { + _dwTickCount = GetTickCount(); + } +#endif + return AbstractUi::eventFilter(obj, event); +} + +// Code taken from KStatusNotifierItem for handling minimize/restore + +bool GraphicalUi::checkMainWidgetVisibility(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(mainWidget()->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 == mainWidget()->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(mainWidget()->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(mainWidget()->winId()); + KWindowSystem::activateWindow(mainWidget()->winId()); + } + return true; + } + + //not on current desktop? + if(!info1.isOnCurrentDesktop()) { + if(perform) + KWindowSystem::activateWindow(mainWidget()->winId()); + return true; + } + + if(perform) + minimizeRestore(false); // hide + return false; + } +#else + + if(!mainWidget()->isVisible() || mainWidget()->isMinimized()) { + if(perform) + minimizeRestore(true); + return true; + } else { + if(perform) + minimizeRestore(false); + return false; + } + +#endif + + return true; +} + +void GraphicalUi::minimizeRestore(bool show) { + if(show) + activateMainWidget(); + else + hideMainWidget(); +} + void GraphicalUi::activateMainWidget() { #ifdef HAVE_KDE # ifdef Q_WS_X11 @@ -118,5 +240,10 @@ void GraphicalUi::hideMainWidget() { _onAllDesktops = info.onAllDesktops(); #endif - mainWidget()->hide(); + if(instance()->isHidingMainWidgetAllowed()) + mainWidget()->hide(); +} + +void GraphicalUi::toggleMainWidget() { + instance()->checkMainWidgetVisibility(true); }