Quassel IRC  Pre-Release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
graphicalui.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2015 by the Quassel Project *
3  * devel@quassel-irc.org *
4  * *
5  * This contains code from KStatusNotifierItem, part of the KDE libs *
6  * Copyright (C) 2009 Marco Martin <notmart@gmail.com> *
7  * *
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. *
12  * *
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. *
17  * *
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  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22  ***************************************************************************/
23 
24 #include "graphicalui.h"
25 
26 #include "actioncollection.h"
27 #include "uisettings.h"
29 #include "toolbaractionprovider.h"
30 
31 #ifdef Q_WS_X11
32 # include <QX11Info>
33 #endif
34 #ifdef HAVE_KDE4
35 # include <KWindowInfo>
36 # include <KWindowSystem>
37 #endif
38 
40 QWidget *GraphicalUi::_mainWidget = 0;
41 QHash<QString, ActionCollection *> GraphicalUi::_actionCollections;
45 bool GraphicalUi::_onAllDesktops = false;
46 
47 GraphicalUi::GraphicalUi(QObject *parent) : AbstractUi(parent)
48 {
49  Q_ASSERT(!_instance);
50  _instance = this;
51 
52 #ifdef Q_OS_WIN
53  _dwTickCount = 0;
54 #endif
55 }
56 
57 
59 {
60 #ifdef Q_OS_WIN
61  mainWidget()->installEventFilter(this);
62 #endif
63 }
64 
65 
66 ActionCollection *GraphicalUi::actionCollection(const QString &category, const QString &translatedCategory)
67 {
68  if (_actionCollections.contains(category))
69  return _actionCollections.value(category);
71 
72  if (!translatedCategory.isEmpty())
73  coll->setProperty("Category", translatedCategory);
74  else
75  coll->setProperty("Category", category);
76 
77  if (_mainWidget)
79  _actionCollections.insert(category, coll);
80  return coll;
81 }
82 
83 
84 QHash<QString, ActionCollection *> GraphicalUi::actionCollections()
85 {
86  return _actionCollections;
87 }
88 
89 
91 {
92  foreach(ActionCollection *coll, actionCollections())
93  coll->readSettings();
94 }
95 
96 
98 {
100  s.clear();
101  foreach(ActionCollection *coll, actionCollections())
102  coll->writeSettings();
103 }
104 
105 
106 void GraphicalUi::setMainWidget(QWidget *widget)
107 {
108  _mainWidget = widget;
109 }
110 
111 
113 {
114  _contextMenuActionProvider = provider;
115 }
116 
117 
119 {
120  _toolBarActionProvider = provider;
121 }
122 
123 
125 {
126  _uiStyle = style;
127 }
128 
129 
131 {
135 }
136 
137 
138 bool GraphicalUi::eventFilter(QObject *obj, QEvent *event)
139 {
140 #ifdef Q_OS_WIN
141  if (obj == mainWidget() && event->type() == QEvent::ActivationChange) {
142  _dwTickCount = GetTickCount();
143  }
144 #endif
145  return AbstractUi::eventFilter(obj, event);
146 }
147 
148 
149 // NOTE: Window activation stuff seems to work just fine in Plasma 5 without requiring X11 hacks.
150 // TODO: Evaluate cleaning all this up once we can get rid of Qt4/KDE4
151 
152 // Code taken from KStatusNotifierItem for handling minimize/restore
153 
155 {
156 #ifdef Q_OS_WIN
157  // the problem is that we lose focus when the systray icon is activated
158  // and we don't know the former active window
159  // therefore we watch for activation event and use our stopwatch :)
160  if (GetTickCount() - _dwTickCount < 300) {
161  // we were active in the last 300ms -> hide it
162  if (perform)
163  minimizeRestore(false);
164  return false;
165  }
166  else {
167  if (perform)
168  minimizeRestore(true);
169  return true;
170  }
171 
172 #elif defined(HAVE_KDE4) && defined(Q_WS_X11)
173  KWindowInfo info1 = KWindowSystem::windowInfo(mainWidget()->winId(), NET::XAWMState | NET::WMState | NET::WMDesktop);
174  // mapped = visible (but possibly obscured)
175  bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized();
176 
177  // - not mapped -> show, raise, focus
178  // - mapped
179  // - obscured -> raise, focus
180  // - not obscured -> hide
181  //info1.mappingState() != NET::Visible -> window on another desktop?
182  if (!mapped) {
183  if (perform)
184  minimizeRestore(true);
185  return true;
186  }
187  else {
188  QListIterator<WId> it(KWindowSystem::stackingOrder());
189  it.toBack();
190  while (it.hasPrevious()) {
191  WId id = it.previous();
192  if (id == mainWidget()->winId())
193  break;
194 
195  KWindowInfo info2 = KWindowSystem::windowInfo(id, NET::WMDesktop | NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType);
196 
197  if (info2.mappingState() != NET::Visible)
198  continue; // not visible on current desktop -> ignore
199 
200  if (!info2.geometry().intersects(mainWidget()->geometry()))
201  continue; // not obscuring the window -> ignore
202 
203  if (!info1.hasState(NET::KeepAbove) && info2.hasState(NET::KeepAbove))
204  continue; // obscured by window kept above -> ignore
205 
206  NET::WindowType type = info2.windowType(NET::NormalMask | NET::DesktopMask
207  | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
208  | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask);
209 
210  if (type == NET::Dock || type == NET::TopMenu)
211  continue; // obscured by dock or topmenu -> ignore
212 
213  if (perform) {
214  KWindowSystem::raiseWindow(mainWidget()->winId());
215  KWindowSystem::activateWindow(mainWidget()->winId());
216  }
217  return true;
218  }
219 
220  //not on current desktop?
221  if (!info1.isOnCurrentDesktop()) {
222  if (perform)
223  KWindowSystem::activateWindow(mainWidget()->winId());
224  return true;
225  }
226 
227  if (perform)
228  minimizeRestore(false); // hide
229  return false;
230  }
231 #else
232 
233  if (!mainWidget()->isVisible() || mainWidget()->isMinimized() || !mainWidget()->isActiveWindow()) {
234  if (perform)
235  minimizeRestore(true);
236  return true;
237  }
238  else {
239  if (perform)
240  minimizeRestore(false);
241  return false;
242  }
243 
244 #endif
245 
246  return true;
247 }
248 
249 
251 {
252  return !instance()->checkMainWidgetVisibility(false);
253 }
254 
255 
257 {
258  if (show)
260  else
261  hideMainWidget();
262 }
263 
264 
266 {
267 #ifdef HAVE_KDE4
268 # ifdef Q_WS_X11
269  KWindowInfo info = KWindowSystem::windowInfo(mainWidget()->winId(), NET::WMDesktop | NET::WMFrameExtents);
270  if (_onAllDesktops) {
271  KWindowSystem::setOnAllDesktops(mainWidget()->winId(), true);
272  }
273  else {
274  KWindowSystem::setCurrentDesktop(info.desktop());
275  }
276 
277  mainWidget()->move(info.frameGeometry().topLeft()); // avoid placement policies
278  mainWidget()->show();
279  mainWidget()->raise();
280  KWindowSystem::raiseWindow(mainWidget()->winId());
281  KWindowSystem::activateWindow(mainWidget()->winId());
282 # else
283  mainWidget()->show();
284  KWindowSystem::raiseWindow(mainWidget()->winId());
285  KWindowSystem::forceActiveWindow(mainWidget()->winId());
286 # endif
287 
288 #else /* HAVE_KDE4 */
289 
290 #ifdef Q_WS_X11
291  // Bypass focus stealing prevention
292  QX11Info::setAppUserTime(QX11Info::appTime());
293 #endif
294 
295  if (mainWidget()->windowState() & Qt::WindowMinimized) {
296  // restore
297  mainWidget()->setWindowState((mainWidget()->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
298  }
299 
300  // this does not actually work on all platforms... and causes more evil than good
301  // mainWidget()->move(mainWidget()->frameGeometry().topLeft()); // avoid placement policies
302  mainWidget()->show();
303  mainWidget()->raise();
304  mainWidget()->activateWindow();
305 
306 #endif /* HAVE_KDE4 */
307 }
308 
309 
311 {
312 #if defined(HAVE_KDE4) && defined(Q_WS_X11)
313  KWindowInfo info = KWindowSystem::windowInfo(mainWidget()->winId(), NET::WMDesktop | NET::WMFrameExtents);
314  _onAllDesktops = info.onAllDesktops();
315 #endif
316 
318  mainWidget()->hide();
319 }
320 
321 
323 {
325 }