1 /***************************************************************************
2 * Copyright (C) 2005-2010 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This contains code from KStatusNotifierItem, part of the KDE libs *
6 * Copyright (C) 2009 Marco Martin <notmart@gmail.com> *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) version 3. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
24 #include "graphicalui.h"
26 #include "actioncollection.h"
27 #include "contextmenuactionprovider.h"
28 #include "toolbaractionprovider.h"
34 # include <KWindowInfo>
35 # include <KWindowSystem>
38 GraphicalUi *GraphicalUi::_instance = 0;
39 QWidget *GraphicalUi::_mainWidget = 0;
40 QHash<QString, ActionCollection *> GraphicalUi::_actionCollections;
41 ContextMenuActionProvider *GraphicalUi::_contextMenuActionProvider = 0;
42 ToolBarActionProvider *GraphicalUi::_toolBarActionProvider = 0;
43 UiStyle *GraphicalUi::_uiStyle = 0;
44 bool GraphicalUi::_onAllDesktops = false;
46 GraphicalUi::GraphicalUi(QObject *parent) : AbstractUi(parent) {
55 void GraphicalUi::init() {
57 mainWidget()->installEventFilter(this);
61 ActionCollection *GraphicalUi::actionCollection(const QString &category) {
62 if(_actionCollections.contains(category))
63 return _actionCollections.value(category);
64 ActionCollection *coll = new ActionCollection(_mainWidget);
66 coll->addAssociatedWidget(_mainWidget);
67 _actionCollections.insert(category, coll);
71 void GraphicalUi::setMainWidget(QWidget *widget) {
75 void GraphicalUi::setContextMenuActionProvider(ContextMenuActionProvider *provider) {
76 _contextMenuActionProvider = provider;
79 void GraphicalUi::setToolBarActionProvider(ToolBarActionProvider *provider) {
80 _toolBarActionProvider = provider;
83 void GraphicalUi::setUiStyle(UiStyle *style) {
87 void GraphicalUi::disconnectedFromCore() {
88 _contextMenuActionProvider->disconnectedFromCore();
89 _toolBarActionProvider->disconnectedFromCore();
90 AbstractUi::disconnectedFromCore();
93 bool GraphicalUi::eventFilter(QObject *obj, QEvent *event) {
95 if(obj == mainWidget() && event->type() == QEvent::ActivationChange) {
96 _dwTickCount = GetTickCount();
99 return AbstractUi::eventFilter(obj, event);
102 // Code taken from KStatusNotifierItem for handling minimize/restore
104 bool GraphicalUi::checkMainWidgetVisibility(bool perform) {
106 // the problem is that we lose focus when the systray icon is activated
107 // and we don't know the former active window
108 // therefore we watch for activation event and use our stopwatch :)
109 if(GetTickCount() - _dwTickCount < 300) {
110 // we were active in the last 300ms -> hide it
112 minimizeRestore(false);
116 minimizeRestore(true);
120 #elif defined(HAVE_KDE) && defined(Q_WS_X11)
121 KWindowInfo info1 = KWindowSystem::windowInfo(mainWidget()->winId(), NET::XAWMState | NET::WMState | NET::WMDesktop);
122 // mapped = visible (but possibly obscured)
123 bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized();
125 // - not mapped -> show, raise, focus
127 // - obscured -> raise, focus
128 // - not obscured -> hide
129 //info1.mappingState() != NET::Visible -> window on another desktop?
132 minimizeRestore(true);
136 QListIterator< WId > it (KWindowSystem::stackingOrder());
138 while(it.hasPrevious()) {
139 WId id = it.previous();
140 if(id == mainWidget()->winId())
143 KWindowInfo info2 = KWindowSystem::windowInfo(id, NET::WMDesktop | NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType);
145 if(info2.mappingState() != NET::Visible)
146 continue; // not visible on current desktop -> ignore
148 if(!info2.geometry().intersects(mainWidget()->geometry()))
149 continue; // not obscuring the window -> ignore
151 if(!info1.hasState(NET::KeepAbove) && info2.hasState(NET::KeepAbove))
152 continue; // obscured by window kept above -> ignore
154 NET::WindowType type = info2.windowType(NET::NormalMask | NET::DesktopMask
155 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
156 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask);
158 if(type == NET::Dock || type == NET::TopMenu)
159 continue; // obscured by dock or topmenu -> ignore
162 KWindowSystem::raiseWindow(mainWidget()->winId());
163 KWindowSystem::activateWindow(mainWidget()->winId());
168 //not on current desktop?
169 if(!info1.isOnCurrentDesktop()) {
171 KWindowSystem::activateWindow(mainWidget()->winId());
176 minimizeRestore(false); // hide
181 if(!mainWidget()->isVisible() || mainWidget()->isMinimized()) {
183 minimizeRestore(true);
187 minimizeRestore(false);
196 bool GraphicalUi::isMainWidgetVisible() {
197 return !instance()->checkMainWidgetVisibility(false);
200 void GraphicalUi::minimizeRestore(bool show) {
202 activateMainWidget();
207 void GraphicalUi::activateMainWidget() {
210 KWindowInfo info = KWindowSystem::windowInfo(mainWidget()->winId(), NET::WMDesktop | NET::WMFrameExtents);
212 KWindowSystem::setOnAllDesktops(mainWidget()->winId(), true);
214 KWindowSystem::setCurrentDesktop(info.desktop());
217 mainWidget()->move(info.frameGeometry().topLeft()); // avoid placement policies
218 mainWidget()->show();
219 mainWidget()->raise();
220 KWindowSystem::raiseWindow(mainWidget()->winId());
221 KWindowSystem::activateWindow(mainWidget()->winId());
223 mainWidget()->show();
224 KWindowSystem::raiseWindow(mainWidget()->winId());
225 KWindowSystem::forceActiveWindow(mainWidget()->winId());
231 // Bypass focus stealing prevention
232 QX11Info::setAppUserTime(QX11Info::appTime());
235 if(mainWidget()->windowState() & Qt::WindowMinimized) {
237 mainWidget()->setWindowState((mainWidget()->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
240 // this does not actually work on all platforms... and causes more evil than good
241 // mainWidget()->move(mainWidget()->frameGeometry().topLeft()); // avoid placement policies
242 mainWidget()->show();
243 mainWidget()->raise();
244 mainWidget()->activateWindow();
246 #endif /* HAVE_KDE */
249 void GraphicalUi::hideMainWidget() {
251 #if defined(HAVE_KDE) && defined(Q_WS_X11)
252 KWindowInfo info = KWindowSystem::windowInfo(mainWidget()->winId(), NET::WMDesktop | NET::WMFrameExtents);
253 _onAllDesktops = info.onAllDesktops();
256 if(instance()->isHidingMainWidgetAllowed())
257 mainWidget()->hide();
260 void GraphicalUi::toggleMainWidget() {
261 instance()->checkMainWidgetVisibility(true);