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