74ca0400b0e65fd60d0a5b15029e3eebf40b3817
[quassel.git] / src / uisupport / graphicalui.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 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"
28 #include "contextmenuactionprovider.h"
29 #include "toolbaractionprovider.h"
30
31 #ifdef Q_WS_X11
32 #  include <QX11Info>
33 #endif
34
35 QWidget *GraphicalUi::_mainWidget = nullptr;
36 QHash<QString, ActionCollection *> GraphicalUi::_actionCollections;
37 ContextMenuActionProvider *GraphicalUi::_contextMenuActionProvider = nullptr;
38 ToolBarActionProvider *GraphicalUi::_toolBarActionProvider = nullptr;
39 UiStyle *GraphicalUi::_uiStyle = nullptr;
40
41
42 GraphicalUi::GraphicalUi(QObject *parent) : AbstractUi(parent), Singleton<GraphicalUi>(this)
43 {
44     Q_INIT_RESOURCE(pics);
45     Q_INIT_RESOURCE(hicolor_icons);
46 #ifdef EMBED_DATA
47     Q_INIT_RESOURCE(icons);
48     Q_INIT_RESOURCE(iconthemes);
49 #endif
50
51 #ifdef Q_OS_WIN
52     _dwTickCount = 0;
53 #endif
54 #ifdef Q_OS_MAC
55     GetFrontProcess(&_procNum);
56 #endif
57 }
58
59
60 void GraphicalUi::init()
61 {
62 #ifdef Q_OS_WIN
63     mainWidget()->installEventFilter(this);
64 #endif
65 }
66
67
68 ActionCollection *GraphicalUi::actionCollection(const QString &category, const QString &translatedCategory)
69 {
70     if (_actionCollections.contains(category))
71         return _actionCollections.value(category);
72     ActionCollection *coll = new ActionCollection(_mainWidget);
73
74     if (!translatedCategory.isEmpty())
75         coll->setProperty("Category", translatedCategory);
76     else
77         coll->setProperty("Category", category);
78
79     if (_mainWidget)
80         coll->addAssociatedWidget(_mainWidget);
81     _actionCollections.insert(category, coll);
82     return coll;
83 }
84
85
86 QHash<QString, ActionCollection *> GraphicalUi::actionCollections()
87 {
88     return _actionCollections;
89 }
90
91
92 void GraphicalUi::loadShortcuts()
93 {
94     foreach(ActionCollection *coll, actionCollections())
95     coll->readSettings();
96 }
97
98
99 void GraphicalUi::saveShortcuts()
100 {
101     ShortcutSettings s;
102     s.clear();
103     foreach(ActionCollection *coll, actionCollections())
104     coll->writeSettings();
105 }
106
107
108 void GraphicalUi::setMainWidget(QWidget *widget)
109 {
110     _mainWidget = widget;
111 }
112
113
114 void GraphicalUi::setContextMenuActionProvider(ContextMenuActionProvider *provider)
115 {
116     _contextMenuActionProvider = provider;
117 }
118
119
120 void GraphicalUi::setToolBarActionProvider(ToolBarActionProvider *provider)
121 {
122     _toolBarActionProvider = provider;
123 }
124
125
126 void GraphicalUi::setUiStyle(UiStyle *style)
127 {
128     _uiStyle = style;
129 }
130
131
132 void GraphicalUi::disconnectedFromCore()
133 {
134     _contextMenuActionProvider->disconnectedFromCore();
135     _toolBarActionProvider->disconnectedFromCore();
136     AbstractUi::disconnectedFromCore();
137 }
138
139
140 bool GraphicalUi::eventFilter(QObject *obj, QEvent *event)
141 {
142 #ifdef Q_OS_WIN
143     if (obj == mainWidget() && event->type() == QEvent::ActivationChange) {
144         _dwTickCount = GetTickCount();
145     }
146 #endif
147     return AbstractUi::eventFilter(obj, event);
148 }
149
150
151 // NOTE: Window activation stuff seems to work just fine in Plasma 5 without requiring X11 hacks.
152 // TODO: Evaluate cleaning all this up once we can get rid of Qt4/KDE4
153
154 // Code taken from KStatusNotifierItem for handling minimize/restore
155
156 bool GraphicalUi::checkMainWidgetVisibility(bool perform)
157 {
158 #ifdef Q_OS_WIN
159     // the problem is that we lose focus when the systray icon is activated
160     // and we don't know the former active window
161     // therefore we watch for activation event and use our stopwatch :)
162     if (GetTickCount() - _dwTickCount < 300) {
163         // we were active in the last 300ms -> hide it
164         if (perform)
165             minimizeRestore(false);
166         return false;
167     }
168     else {
169         if (perform)
170             minimizeRestore(true);
171         return true;
172     }
173
174 #else
175
176     if (!mainWidget()->isVisible() || mainWidget()->isMinimized() || !mainWidget()->isActiveWindow()) {
177         if (perform)
178             minimizeRestore(true);
179         return true;
180     }
181     else {
182         if (perform)
183             minimizeRestore(false);
184         return false;
185     }
186
187 #endif
188
189     return true;
190 }
191
192
193 bool GraphicalUi::isMainWidgetVisible()
194 {
195     return !instance()->checkMainWidgetVisibility(false);
196 }
197
198
199 void GraphicalUi::minimizeRestore(bool show)
200 {
201     if (show)
202         activateMainWidget();
203     else
204         hideMainWidget();
205 }
206
207
208 void GraphicalUi::activateMainWidget()
209 {
210 #ifdef Q_WS_X11
211     // Bypass focus stealing prevention
212     QX11Info::setAppUserTime(QX11Info::appTime());
213 #endif
214
215     if (mainWidget()->windowState() & Qt::WindowMinimized) {
216         // restore
217         mainWidget()->setWindowState((mainWidget()->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
218     }
219
220     // this does not actually work on all platforms... and causes more evil than good
221     // mainWidget()->move(mainWidget()->frameGeometry().topLeft()); // avoid placement policies
222 #ifdef Q_OS_MAC
223     SetFrontProcess(&instance()->_procNum);
224 #else
225     mainWidget()->show();
226     mainWidget()->raise();
227     mainWidget()->activateWindow();
228 #endif
229 }
230
231
232 void GraphicalUi::hideMainWidget()
233 {
234     if (instance()->isHidingMainWidgetAllowed())
235 #ifdef Q_OS_MAC
236         ShowHideProcess(&instance()->_procNum, false);
237 #else
238         mainWidget()->hide();
239 #endif
240 }
241
242
243 void GraphicalUi::toggleMainWidget()
244 {
245     instance()->checkMainWidgetVisibility(true);
246 }