1 |
From 4c070c5d3619416d5c7866ce29f546911ffe8faa Mon Sep 17 00:00:00 2001 |
2 |
From: Tasos Sahanidis <tasos@tasossah.com> |
3 |
Date: Wed, 5 Aug 2020 06:02:44 +0300 |
4 |
Subject: [PATCH] Replace AppIndicator with minimal KStatusNotifier |
5 |
|
6 |
--- |
7 |
(daviddavid) Rebase patch |
8 |
--- |
9 |
CMakeLists.txt | 2 +- |
10 |
cmake/modules/FindAppindicator.cmake | 69 -- |
11 |
src/gui/CMakeLists.txt | 51 +- |
12 |
src/gui/ckbsystemtrayicon.cpp | 59 +- |
13 |
src/gui/ckbsystemtrayicon.h | 40 +- |
14 |
src/gui/kstatusnotifier/COPYING.LIB | 510 +++++++++++ |
15 |
.../kstatusnotifier/kstatusnotifieritem.cpp | 829 ++++++++++++++++++ |
16 |
src/gui/kstatusnotifier/kstatusnotifieritem.h | 483 ++++++++++ |
17 |
.../kstatusnotifieritemdbus_p.cpp | 292 ++++++ |
18 |
.../kstatusnotifieritemdbus_p.h | 246 ++++++ |
19 |
.../kstatusnotifieritemprivate_p.h | 171 ++++ |
20 |
.../org.freedesktop.Notifications.xml | 37 + |
21 |
.../org.kde.StatusNotifierItem.xml | 96 ++ |
22 |
.../org.kde.StatusNotifierWatcher.xml | 42 + |
23 |
src/gui/mainwindow.cpp | 103 +-- |
24 |
src/gui/mainwindow.h | 25 +- |
25 |
16 files changed, 2838 insertions(+), 217 deletions(-) |
26 |
delete mode 100644 cmake/modules/FindAppindicator.cmake |
27 |
create mode 100644 src/gui/kstatusnotifier/COPYING.LIB |
28 |
create mode 100644 src/gui/kstatusnotifier/kstatusnotifieritem.cpp |
29 |
create mode 100644 src/gui/kstatusnotifier/kstatusnotifieritem.h |
30 |
create mode 100644 src/gui/kstatusnotifier/kstatusnotifieritemdbus_p.cpp |
31 |
create mode 100644 src/gui/kstatusnotifier/kstatusnotifieritemdbus_p.h |
32 |
create mode 100644 src/gui/kstatusnotifier/kstatusnotifieritemprivate_p.h |
33 |
create mode 100644 src/gui/kstatusnotifier/org.freedesktop.Notifications.xml |
34 |
create mode 100644 src/gui/kstatusnotifier/org.kde.StatusNotifierItem.xml |
35 |
create mode 100644 src/gui/kstatusnotifier/org.kde.StatusNotifierWatcher.xml |
36 |
|
37 |
diff --git a/CMakeLists.txt b/CMakeLists.txt |
38 |
index eb0c937d..107c87fb 100644 |
39 |
--- a/CMakeLists.txt |
40 |
+++ b/CMakeLists.txt |
41 |
@@ -103,6 +103,8 @@ cmake_dependent_option(WITH_PIPE "Bu |
42 |
|
43 |
if (LINUX) |
44 |
cmake_dependent_option(WITH_MVIZ "Build with music visualizer." ON "WITH_ANIMATIONS;WITH_GUI" OFF) |
45 |
+ cmake_dependent_option(USE_DBUS_MENU "Build with DBus support for the tray." ON |
46 |
+ "WITH_GUI" OFF) |
47 |
option(USE_PORTAUDIO "Use portaudio for music visualizer." OFF) |
48 |
else () |
49 |
cmake_dependent_option(WITH_MVIZ "Build with music visualizer." OFF "WITH_ANIMATIONS;WITH_GUI" OFF) |
50 |
@@ -136,7 +138,6 @@ option(SAFE_UNINSTALL "Execute pre-unins |
51 |
Intended to be used with direct removals without package manager." OFF) |
52 |
|
53 |
option(WITH_SHIPPED_QUAZIP "Use shipped QuaZip5 instead of system package" OFF) |
54 |
-option(USE_APPINDICATOR_OVERRIDE "Use gtk2 Appindicator for Qt > 5.7." OFF) |
55 |
|
56 |
if (NOT WITH_GUI) |
57 |
message(WARNING "Building without GUI. Proceed only if you know what you are doing.") |
58 |
diff --git a/cmake/modules/FindAppindicator.cmake b/cmake/modules/FindAppindicator.cmake |
59 |
deleted file mode 100644 |
60 |
index b5f541d1..00000000 |
61 |
--- a/cmake/modules/FindAppindicator.cmake |
62 |
+++ /dev/null |
63 |
@@ -1,69 +0,0 @@ |
64 |
-# Copyright 2017-2018 ckb-next Development Team <ckb-next@googlegroups.com> |
65 |
-# All rights reserved. |
66 |
-# |
67 |
-# Redistribution and use in source and binary forms, with or without |
68 |
-# modification, are permitted provided that the following conditions are met: |
69 |
-# |
70 |
-# 1. Redistributions of source code must retain the above copyright notice, |
71 |
-# this list of conditions and the following disclaimer. |
72 |
-# 2. Redistributions in binary form must reproduce the above copyright |
73 |
-# notice, this list of conditions and the following disclaimer in the |
74 |
-# documentation and/or other materials provided with the distribution. |
75 |
-# 3. Neither the name of the copyright holder nor the names of its |
76 |
-# contributors may be used to endorse or promote products derived from this |
77 |
-# software without specific prior written permission. |
78 |
-# |
79 |
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
80 |
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
81 |
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
82 |
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
83 |
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
84 |
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
85 |
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
86 |
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
87 |
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
88 |
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
89 |
-# POSSIBILITY OF SUCH DAMAGE. |
90 |
- |
91 |
-#.rst: |
92 |
-# FindAppindicator |
93 |
-# ----------- |
94 |
-# |
95 |
-# Find any available appindicator (gtk2, gtk3, sharp). |
96 |
-# |
97 |
-# Result variables |
98 |
-# ^^^^^^^^^^^^^^^^ |
99 |
-# |
100 |
-# This module will set the following variables in your project: |
101 |
-# |
102 |
-# ``Appindicator_FOUND`` |
103 |
-# true if appindicator headers and libraries were found |
104 |
-# ``Appindicator_INCLUDE_DIRS`` |
105 |
-# list of the include directories needed to use appindicator |
106 |
-# ``Appindicator_LIBRARIES`` |
107 |
-# appindicator libraries to be linked |
108 |
-# ``Appindicator_DEFINITIONS`` |
109 |
-# the compiler switches required for using appindicator |
110 |
-# ``Appindicator_VERSION`` |
111 |
-# the version of appindicator found |
112 |
- |
113 |
-find_package(PkgConfig REQUIRED) |
114 |
-pkg_search_module(Appindicator appindicator-0.1) |
115 |
-set(Appindicator_DEFINITIONS ${Appindicator_CFLAGS_OTHER}) |
116 |
- |
117 |
-include(FindPackageHandleStandardArgs) |
118 |
-find_package_handle_standard_args( |
119 |
- Appindicator |
120 |
- REQUIRED_VARS |
121 |
- Appindicator_LIBRARIES |
122 |
- Appindicator_INCLUDE_DIRS |
123 |
- Appindicator_DEFINITIONS |
124 |
- VERSION_VAR |
125 |
- Appindicator_VERSION) |
126 |
- |
127 |
-mark_as_advanced(Appindicator_LIBRARIES Appindicator_DEFINITIONS Appindicator_INCLUDE_DIRS Appindicator_VERSION) |
128 |
- |
129 |
-if(NOT Appindicator_FOUND) |
130 |
- message(WARNING "Appindicator was not found.\n" |
131 |
- "If you encounter issues with the tray icon, please install it.") |
132 |
-endif() |
133 |
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt |
134 |
index b1abd554..e39810a3 100644 |
135 |
--- a/src/gui/CMakeLists.txt |
136 |
+++ b/src/gui/CMakeLists.txt |
137 |
@@ -88,16 +88,8 @@ AudioToolbox: ${AUDIOTOOLBOX_LIBRARY}") |
138 |
endif () |
139 |
mark_as_advanced(FOUNDATION_LIBRARY COREAUDIO_LIBRARY AUDIOTOOLBOX_LIBRARY) |
140 |
elseif (LINUX) |
141 |
- if ((Qt5Core_VERSION VERSION_LESS 5.7.0) OR USE_APPINDICATOR_OVERRIDE OR "$ENV{QT_QPA_PLATFORMTHEME}" STREQUAL "gtk2" ) |
142 |
- find_package(Appindicator) |
143 |
- if (Appindicator_FOUND) |
144 |
- target_compile_definitions( |
145 |
- ckb-next |
146 |
- PRIVATE |
147 |
- USE_LIBAPPINDICATOR) |
148 |
- endif () |
149 |
- endif () |
150 |
find_package(X11 REQUIRED) |
151 |
+ find_package(Qt5 5.2.0 COMPONENTS DBus) |
152 |
endif () |
153 |
|
154 |
# Automatically handle MOC, UIC and RCC |
155 |
@@ -121,7 +113,6 @@ if (MACOS OR LINUX) |
156 |
autorun.cpp |
157 |
ckbsettings.cpp |
158 |
ckbsettingswriter.cpp |
159 |
- ckbsystemtrayicon.cpp |
160 |
ckbupdater.cpp |
161 |
ckbupdaterwidget.cpp |
162 |
colorbutton.cpp |
163 |
@@ -240,6 +231,40 @@ elseif (LINUX) |
164 |
ckb-next |
165 |
PRIVATE |
166 |
media_linux.cpp) |
167 |
+ |
168 |
+ if(USE_DBUS_MENU) |
169 |
+ find_package(dbusmenu-qt5 CONFIG) |
170 |
+ if(NOT dbusmenu-qt5_FOUND) |
171 |
+ message(FATAL_ERROR "dbusmenu-qt5 was not found. Either install it or pass -DUSE_DBUS_MENU=0 to fall back to the default Qt tray icon.") |
172 |
+ endif() |
173 |
+ target_link_libraries( |
174 |
+ ckb-next |
175 |
+ PRIVATE |
176 |
+ Qt5::DBus |
177 |
+ dbusmenu-qt5 |
178 |
+ ) |
179 |
+ target_compile_definitions( |
180 |
+ ckb-next |
181 |
+ PRIVATE |
182 |
+ USE_DBUS_MENU) |
183 |
+ |
184 |
+ include_directories(${dbusmenu-qt5_INCLUDE_DIRS}) |
185 |
+ qt5_add_dbus_adaptor(statusNotifierAutogen "kstatusnotifier/org.kde.StatusNotifierItem.xml" |
186 |
+ "kstatusnotifier/kstatusnotifieritemdbus_p.h" KStatusNotifierItemDBus) |
187 |
+ qt5_add_dbus_interface(statusNotifierAutogen "kstatusnotifier/org.freedesktop.Notifications.xml" notifications_interface) |
188 |
+ qt5_add_dbus_interface(statusNotifierAutogen "kstatusnotifier/org.kde.StatusNotifierWatcher.xml" statusnotifierwatcher_interface) |
189 |
+ set_property(SOURCE ${statusNotifierAutogen} PROPERTY SKIP_AUTOGEN ON) |
190 |
+ target_sources( |
191 |
+ ckb-next |
192 |
+ PRIVATE |
193 |
+ kstatusnotifier/kstatusnotifieritem.cpp |
194 |
+ kstatusnotifier/kstatusnotifieritemdbus_p.cpp |
195 |
+ kstatusnotifier/kstatusnotifieritemdbus_p.h |
196 |
+ kstatusnotifier/kstatusnotifieritem.h |
197 |
+ kstatusnotifier/kstatusnotifieritemprivate_p.h |
198 |
+ ckbsystemtrayicon.cpp |
199 |
+ ${statusNotifierAutogen}) |
200 |
+ endif() |
201 |
endif () |
202 |
|
203 |
if (MAC_LEGACY) |
204 |
@@ -375,8 +400,7 @@ elseif (LINUX) |
205 |
ckb-next |
206 |
SYSTEM |
207 |
PRIVATE |
208 |
- "${X11_INCLUDE_DIR}" |
209 |
- "${Appindicator_INCLUDE_DIRS}") |
210 |
+ "${X11_INCLUDE_DIR}") |
211 |
endif () |
212 |
|
213 |
if (NOT WITH_SHIPPED_QUAZIP) |
214 |
@@ -412,14 +436,12 @@ elseif (LINUX) |
215 |
ckb-next |
216 |
PRIVATE |
217 |
"${X11_LIBRARIES}" |
218 |
- "${Appindicator_LIBRARIES}" |
219 |
"${PULSEAUDIO_LIBRARIES}") |
220 |
else() |
221 |
target_link_libraries( |
222 |
ckb-next |
223 |
PRIVATE |
224 |
- "${X11_LIBRARIES}" |
225 |
- "${Appindicator_LIBRARIES}") |
226 |
+ "${X11_LIBRARIES}") |
227 |
endif() |
228 |
endif() |
229 |
|
230 |
@@ -444,7 +466,6 @@ set_target_properties( |
231 |
target_compile_options( |
232 |
ckb-next |
233 |
PRIVATE |
234 |
- "${Appindicator_DEFINITIONS}" |
235 |
"${CKB_NEXT_COMMON_COMPILE_FLAGS}") |
236 |
|
237 |
if (CMAKE_BUILD_TYPE STREQUAL "Debug") |
238 |
diff --git a/src/gui/ckbsystemtrayicon.cpp b/src/gui/ckbsystemtrayicon.cpp |
239 |
index 3e98f066..89eb6939 100644 |
240 |
--- a/src/gui/ckbsystemtrayicon.cpp |
241 |
+++ b/src/gui/ckbsystemtrayicon.cpp |
242 |
@@ -1,15 +1,50 @@ |
243 |
+// Cmake will not build this file if USE_DBUS_MENU is not set |
244 |
#include "ckbsystemtrayicon.h" |
245 |
-#include <QEvent> |
246 |
-#include <QWheelEvent> |
247 |
- |
248 |
-bool CkbSystemTrayIcon::event(QEvent* evt){ |
249 |
- if(evt->type() == QEvent::Wheel) { |
250 |
- QWheelEvent* wheelEvt = static_cast<QWheelEvent*>(evt); |
251 |
- if(wheelEvt->delta() > 0) |
252 |
- emit wheelScrolled(true); |
253 |
- else |
254 |
- emit wheelScrolled(false); |
255 |
- return true; |
256 |
+#include <QDir> |
257 |
+#include <QDebug> |
258 |
+CkbSystemTrayIcon::CkbSystemTrayIcon(const QIcon& icon, QObject*parent) : KStatusNotifierItem("ckb-next", parent), previousPath("") |
259 |
+{ |
260 |
+ setIcon(icon); |
261 |
+} |
262 |
+ |
263 |
+// Not all implementations support passing icons by pixmap |
264 |
+// Save the icon to /tmp/ and use that instead |
265 |
+void CkbSystemTrayIcon::setIcon(QIcon icon) |
266 |
+{ |
267 |
+ QList<QSize> availSizes = icon.availableSizes(); |
268 |
+ if(!availSizes.length()) |
269 |
+ return; |
270 |
+ |
271 |
+ QPixmap pm = icon.pixmap(availSizes.at(0)); |
272 |
+ QString path; |
273 |
+ // Keep trying until we find a path that doesn't conflict |
274 |
+ int i; |
275 |
+ for(i = 0; i < 5; i++) |
276 |
+ { |
277 |
+ path = QDir::tempPath() + QString("/ckb-next-tray-%1.png").arg(qrand()); |
278 |
+ if(!QFile::exists(path)) |
279 |
+ break; |
280 |
} |
281 |
- return QSystemTrayIcon::event(evt); |
282 |
+ |
283 |
+ if(i == 5) |
284 |
+ return; |
285 |
+ |
286 |
+ if(!pm.save(path)) |
287 |
+ return; |
288 |
+ |
289 |
+ setIconByName(path); |
290 |
+ |
291 |
+ // Delete the old file |
292 |
+ QFile f(previousPath); |
293 |
+ if(!previousPath.isEmpty() && f.exists()) |
294 |
+ f.remove(); |
295 |
+ |
296 |
+ previousPath = path; |
297 |
+} |
298 |
+ |
299 |
+CkbSystemTrayIcon::~CkbSystemTrayIcon() |
300 |
+{ |
301 |
+ QFile f(previousPath); |
302 |
+ if(f.exists()) |
303 |
+ f.remove(); |
304 |
} |
305 |
diff --git a/src/gui/ckbsystemtrayicon.h b/src/gui/ckbsystemtrayicon.h |
306 |
index c1c442bc..66980e13 100644 |
307 |
--- a/src/gui/ckbsystemtrayicon.h |
308 |
+++ b/src/gui/ckbsystemtrayicon.h |
309 |
@@ -1,18 +1,46 @@ |
310 |
#ifndef CKBSYSTEMTRAYICON_H |
311 |
#define CKBSYSTEMTRAYICON_H |
312 |
+#include <QIcon> |
313 |
#include <QSystemTrayIcon> |
314 |
|
315 |
+#ifdef USE_DBUS_MENU |
316 |
+#include "kstatusnotifier/kstatusnotifieritem.h" |
317 |
+class CkbSystemTrayIcon : public KStatusNotifierItem { |
318 |
+#else |
319 |
+#include <QEvent> |
320 |
+#include <QWheelEvent> |
321 |
class CkbSystemTrayIcon : public QSystemTrayIcon { |
322 |
+#endif |
323 |
Q_OBJECT |
324 |
|
325 |
public: |
326 |
- CkbSystemTrayIcon(const QIcon& icon, QObject* parent = 0) |
327 |
- : QSystemTrayIcon(icon, parent) {} |
328 |
+#ifdef USE_DBUS_MENU |
329 |
+ CkbSystemTrayIcon(const QIcon& icon, QObject* parent = 0); |
330 |
+ inline void show() { setStatus(KStatusNotifierItem::Active); } |
331 |
+ inline void setVisible(bool visible) { setStatus((visible ? KStatusNotifierItem::Active : KStatusNotifierItem::Passive)); } |
332 |
+ void setIcon(QIcon icon); |
333 |
+ ~CkbSystemTrayIcon(); |
334 |
+signals: |
335 |
+ // This is never emitted by KStatusNotifierItem |
336 |
+ void activated(QSystemTrayIcon::ActivationReason); |
337 |
+ private: |
338 |
+ QString previousPath; |
339 |
+#else |
340 |
+ CkbSystemTrayIcon(const QIcon& icon, QObject* parent = 0) : QSystemTrayIcon(icon, parent) {} |
341 |
+ virtual bool event(QEvent* evt) |
342 |
+ { |
343 |
+ if(evt->type() == QEvent::Wheel) { |
344 |
+ QWheelEvent* wheelEvt = static_cast<QWheelEvent*>(evt); |
345 |
+ emit scrollRequested(wheelEvt->delta(), wheelEvt->orientation()); |
346 |
+ return true; |
347 |
+ } |
348 |
+ return QSystemTrayIcon::event(evt); |
349 |
+ } |
350 |
|
351 |
- virtual bool event(QEvent* evt); |
352 |
- |
353 |
- signals: |
354 |
- void wheelScrolled(bool up); |
355 |
+ signals: |
356 |
+ void scrollRequested(int delta, Qt::Orientation orientation); |
357 |
|
358 |
+#endif |
359 |
}; |
360 |
+ |
361 |
#endif // CKBSYSTEMTRAYICON_H |
362 |
diff --git a/src/gui/kstatusnotifier/COPYING.LIB b/src/gui/kstatusnotifier/COPYING.LIB |
363 |
new file mode 100644 |
364 |
index 00000000..2d2d780e |
365 |
--- /dev/null |
366 |
+++ b/src/gui/kstatusnotifier/COPYING.LIB |
367 |
@@ -0,0 +1,510 @@ |
368 |
+ |
369 |
+ GNU LESSER GENERAL PUBLIC LICENSE |
370 |
+ Version 2.1, February 1999 |
371 |
+ |
372 |
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc. |
373 |
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
374 |
+ Everyone is permitted to copy and distribute verbatim copies |
375 |
+ of this license document, but changing it is not allowed. |
376 |
+ |
377 |
+[This is the first released version of the Lesser GPL. It also counts |
378 |
+ as the successor of the GNU Library Public License, version 2, hence |
379 |
+ the version number 2.1.] |
380 |
+ |
381 |
+ Preamble |
382 |
+ |
383 |
+ The licenses for most software are designed to take away your |
384 |
+freedom to share and change it. By contrast, the GNU General Public |
385 |
+Licenses are intended to guarantee your freedom to share and change |
386 |
+free software--to make sure the software is free for all its users. |
387 |
+ |
388 |
+ This license, the Lesser General Public License, applies to some |
389 |
+specially designated software packages--typically libraries--of the |
390 |
+Free Software Foundation and other authors who decide to use it. You |
391 |
+can use it too, but we suggest you first think carefully about whether |
392 |
+this license or the ordinary General Public License is the better |
393 |
+strategy to use in any particular case, based on the explanations |
394 |
+below. |
395 |
+ |
396 |
+ When we speak of free software, we are referring to freedom of use, |
397 |
+not price. Our General Public Licenses are designed to make sure that |
398 |
+you have the freedom to distribute copies of free software (and charge |
399 |
+for this service if you wish); that you receive source code or can get |
400 |
+it if you want it; that you can change the software and use pieces of |
401 |
+it in new free programs; and that you are informed that you can do |
402 |
+these things. |
403 |
+ |
404 |
+ To protect your rights, we need to make restrictions that forbid |
405 |
+distributors to deny you these rights or to ask you to surrender these |
406 |
+rights. These restrictions translate to certain responsibilities for |
407 |
+you if you distribute copies of the library or if you modify it. |
408 |
+ |
409 |
+ For example, if you distribute copies of the library, whether gratis |
410 |
+or for a fee, you must give the recipients all the rights that we gave |
411 |
+you. You must make sure that they, too, receive or can get the source |
412 |
+code. If you link other code with the library, you must provide |
413 |
+complete object files to the recipients, so that they can relink them |
414 |
+with the library after making changes to the library and recompiling |
415 |
+it. And you must show them these terms so they know their rights. |
416 |
+ |
417 |
+ We protect your rights with a two-step method: (1) we copyright the |
418 |
+library, and (2) we offer you this license, which gives you legal |
419 |
+permission to copy, distribute and/or modify the library. |
420 |
+ |
421 |
+ To protect each distributor, we want to make it very clear that |
422 |
+there is no warranty for the free library. Also, if the library is |
423 |
+modified by someone else and passed on, the recipients should know |
424 |
+that what they have is not the original version, so that the original |
425 |
+author's reputation will not be affected by problems that might be |
426 |
+introduced by others. |
427 |
+ |
428 |
+ Finally, software patents pose a constant threat to the existence of |
429 |
+any free program. We wish to make sure that a company cannot |
430 |
+effectively restrict the users of a free program by obtaining a |
431 |
+restrictive license from a patent holder. Therefore, we insist that |
432 |
+any patent license obtained for a version of the library must be |
433 |
+consistent with the full freedom of use specified in this license. |
434 |
+ |
435 |
+ Most GNU software, including some libraries, is covered by the |
436 |
+ordinary GNU General Public License. This license, the GNU Lesser |
437 |
+General Public License, applies to certain designated libraries, and |
438 |
+is quite different from the ordinary General Public License. We use |
439 |
+this license for certain libraries in order to permit linking those |
440 |
+libraries into non-free programs. |
441 |
+ |
442 |
+ When a program is linked with a library, whether statically or using |
443 |
+a shared library, the combination of the two is legally speaking a |
444 |
+combined work, a derivative of the original library. The ordinary |
445 |
+General Public License therefore permits such linking only if the |
446 |
+entire combination fits its criteria of freedom. The Lesser General |
447 |
+Public License permits more lax criteria for linking other code with |
448 |
+the library. |
449 |
+ |
450 |
+ We call this license the "Lesser" General Public License because it |
451 |
+does Less to protect the user's freedom than the ordinary General |
452 |
+Public License. It also provides other free software developers Less |
453 |
+of an advantage over competing non-free programs. These disadvantages |
454 |
+are the reason we use the ordinary General Public License for many |
455 |
+libraries. However, the Lesser license provides advantages in certain |
456 |
+special circumstances. |
457 |
+ |
458 |
+ For example, on rare occasions, there may be a special need to |
459 |
+encourage the widest possible use of a certain library, so that it |
460 |
+becomes a de-facto standard. To achieve this, non-free programs must |
461 |
+be allowed to use the library. A more frequent case is that a free |
462 |
+library does the same job as widely used non-free libraries. In this |
463 |
+case, there is little to gain by limiting the free library to free |
464 |
+software only, so we use the Lesser General Public License. |
465 |
+ |
466 |
+ In other cases, permission to use a particular library in non-free |
467 |
+programs enables a greater number of people to use a large body of |
468 |
+free software. For example, permission to use the GNU C Library in |
469 |
+non-free programs enables many more people to use the whole GNU |
470 |
+operating system, as well as its variant, the GNU/Linux operating |
471 |
+system. |
472 |
+ |
473 |
+ Although the Lesser General Public License is Less protective of the |
474 |
+users' freedom, it does ensure that the user of a program that is |
475 |
+linked with the Library has the freedom and the wherewithal to run |
476 |
+that program using a modified version of the Library. |
477 |
+ |
478 |
+ The precise terms and conditions for copying, distribution and |
479 |
+modification follow. Pay close attention to the difference between a |
480 |
+"work based on the library" and a "work that uses the library". The |
481 |
+former contains code derived from the library, whereas the latter must |
482 |
+be combined with the library in order to run. |
483 |
+ |
484 |
+ GNU LESSER GENERAL PUBLIC LICENSE |
485 |
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
486 |
+ |
487 |
+ 0. This License Agreement applies to any software library or other |
488 |
+program which contains a notice placed by the copyright holder or |
489 |
+other authorized party saying it may be distributed under the terms of |
490 |
+this Lesser General Public License (also called "this License"). |
491 |
+Each licensee is addressed as "you". |
492 |
+ |
493 |
+ A "library" means a collection of software functions and/or data |
494 |
+prepared so as to be conveniently linked with application programs |
495 |
+(which use some of those functions and data) to form executables. |
496 |
+ |
497 |
+ The "Library", below, refers to any such software library or work |
498 |
+which has been distributed under these terms. A "work based on the |
499 |
+Library" means either the Library or any derivative work under |
500 |
+copyright law: that is to say, a work containing the Library or a |
501 |
+portion of it, either verbatim or with modifications and/or translated |
502 |
+straightforwardly into another language. (Hereinafter, translation is |
503 |
+included without limitation in the term "modification".) |
504 |
+ |
505 |
+ "Source code" for a work means the preferred form of the work for |
506 |
+making modifications to it. For a library, complete source code means |
507 |
+all the source code for all modules it contains, plus any associated |
508 |
+interface definition files, plus the scripts used to control |
509 |
+compilation and installation of the library. |
510 |
+ |
511 |
+ Activities other than copying, distribution and modification are not |
512 |
+covered by this License; they are outside its scope. The act of |
513 |
+running a program using the Library is not restricted, and output from |
514 |
+such a program is covered only if its contents constitute a work based |
515 |
+on the Library (independent of the use of the Library in a tool for |
516 |
+writing it). Whether that is true depends on what the Library does |
517 |
+and what the program that uses the Library does. |
518 |
+ |
519 |
+ 1. You may copy and distribute verbatim copies of the Library's |
520 |
+complete source code as you receive it, in any medium, provided that |
521 |
+you conspicuously and appropriately publish on each copy an |
522 |
+appropriate copyright notice and disclaimer of warranty; keep intact |
523 |
+all the notices that refer to this License and to the absence of any |
524 |
+warranty; and distribute a copy of this License along with the |
525 |
+Library. |
526 |
+ |
527 |
+ You may charge a fee for the physical act of transferring a copy, |
528 |
+and you may at your option offer warranty protection in exchange for a |
529 |
+fee. |
530 |
+ |
531 |
+ 2. You may modify your copy or copies of the Library or any portion |
532 |
+of it, thus forming a work based on the Library, and copy and |
533 |
+distribute such modifications or work under the terms of Section 1 |
534 |
+above, provided that you also meet all of these conditions: |
535 |
+ |
536 |
+ a) The modified work must itself be a software library. |
537 |
+ |
538 |
+ b) You must cause the files modified to carry prominent notices |
539 |
+ stating that you changed the files and the date of any change. |
540 |
+ |
541 |
+ c) You must cause the whole of the work to be licensed at no |
542 |
+ charge to all third parties under the terms of this License. |
543 |
+ |
544 |
+ d) If a facility in the modified Library refers to a function or a |
545 |
+ table of data to be supplied by an application program that uses |
546 |
+ the facility, other than as an argument passed when the facility |
547 |
+ is invoked, then you must make a good faith effort to ensure that, |
548 |
+ in the event an application does not supply such function or |
549 |
+ table, the facility still operates, and performs whatever part of |
550 |
+ its purpose remains meaningful. |
551 |
+ |
552 |
+ (For example, a function in a library to compute square roots has |
553 |
+ a purpose that is entirely well-defined independent of the |
554 |
+ application. Therefore, Subsection 2d requires that any |
555 |
+ application-supplied function or table used by this function must |
556 |
+ be optional: if the application does not supply it, the square |
557 |
+ root function must still compute square roots.) |
558 |
+ |
559 |
+These requirements apply to the modified work as a whole. If |
560 |
+identifiable sections of that work are not derived from the Library, |
561 |
+and can be reasonably considered independent and separate works in |
562 |
+themselves, then this License, and its terms, do not apply to those |
563 |
+sections when you distribute them as separate works. But when you |
564 |
+distribute the same sections as part of a whole which is a work based |
565 |
+on the Library, the distribution of the whole must be on the terms of |
566 |
+this License, whose permissions for other licensees extend to the |
567 |
+entire whole, and thus to each and every part regardless of who wrote |
568 |
+it. |
569 |
+ |
570 |
+Thus, it is not the intent of this section to claim rights or contest |
571 |
+your rights to work written entirely by you; rather, the intent is to |
572 |
+exercise the right to control the distribution of derivative or |
573 |
+collective works based on the Library. |
574 |
+ |
575 |
+In addition, mere aggregation of another work not based on the Library |
576 |
+with the Library (or with a work based on the Library) on a volume of |
577 |
+a storage or distribution medium does not bring the other work under |
578 |
+the scope of this License. |
579 |
+ |
580 |
+ 3. You may opt to apply the terms of the ordinary GNU General Public |
581 |
+License instead of this License to a given copy of the Library. To do |
582 |
+this, you must alter all the notices that refer to this License, so |
583 |
+that they refer to the ordinary GNU General Public License, version 2, |
584 |
+instead of to this License. (If a newer version than version 2 of the |
585 |
+ordinary GNU General Public License has appeared, then you can specify |
586 |
+that version instead if you wish.) Do not make any other change in |
587 |
+these notices. |
588 |
+ |
589 |
+ Once this change is made in a given copy, it is irreversible for |
590 |
+that copy, so the ordinary GNU General Public License applies to all |
591 |
+subsequent copies and derivative works made from that copy. |
592 |
+ |
593 |
+ This option is useful when you wish to copy part of the code of |
594 |
+the Library into a program that is not a library. |
595 |
+ |
596 |
+ 4. You may copy and distribute the Library (or a portion or |
597 |
+derivative of it, under Section 2) in object code or executable form |
598 |
+under the terms of Sections 1 and 2 above provided that you accompany |
599 |
+it with the complete corresponding machine-readable source code, which |
600 |
+must be distributed under the terms of Sections 1 and 2 above on a |
601 |
+medium customarily used for software interchange. |
602 |
+ |
603 |
+ If distribution of object code is made by offering access to copy |
604 |
+from a designated place, then offering equivalent access to copy the |
605 |
+source code from the same place satisfies the requirement to |
606 |
+distribute the source code, even though third parties are not |
607 |
+compelled to copy the source along with the object code. |
608 |
+ |
609 |
+ 5. A program that contains no derivative of any portion of the |
610 |
+Library, but is designed to work with the Library by being compiled or |
611 |
+linked with it, is called a "work that uses the Library". Such a |
612 |
+work, in isolation, is not a derivative work of the Library, and |
613 |
+therefore falls outside the scope of this License. |
614 |
+ |
615 |
+ However, linking a "work that uses the Library" with the Library |
616 |
+creates an executable that is a derivative of the Library (because it |
617 |
+contains portions of the Library), rather than a "work that uses the |
618 |
+library". The executable is therefore covered by this License. |
619 |
+Section 6 states terms for distribution of such executables. |
620 |
+ |
621 |
+ When a "work that uses the Library" uses material from a header file |
622 |
+that is part of the Library, the object code for the work may be a |
623 |
+derivative work of the Library even though the source code is not. |
624 |
+Whether this is true is especially significant if the work can be |
625 |
+linked without the Library, or if the work is itself a library. The |
626 |
+threshold for this to be true is not precisely defined by law. |
627 |
+ |
628 |
+ If such an object file uses only numerical parameters, data |
629 |
+structure layouts and accessors, and small macros and small inline |
630 |
+functions (ten lines or less in length), then the use of the object |
631 |
+file is unrestricted, regardless of whether it is legally a derivative |
632 |
+work. (Executables containing this object code plus portions of the |
633 |
+Library will still fall under Section 6.) |
634 |
+ |
635 |
+ Otherwise, if the work is a derivative of the Library, you may |
636 |
+distribute the object code for the work under the terms of Section 6. |
637 |
+Any executables containing that work also fall under Section 6, |
638 |
+whether or not they are linked directly with the Library itself. |
639 |
+ |
640 |
+ 6. As an exception to the Sections above, you may also combine or |
641 |
+link a "work that uses the Library" with the Library to produce a |
642 |
+work containing portions of the Library, and distribute that work |
643 |
+under terms of your choice, provided that the terms permit |
644 |
+modification of the work for the customer's own use and reverse |
645 |
+engineering for debugging such modifications. |
646 |
+ |
647 |
+ You must give prominent notice with each copy of the work that the |
648 |
+Library is used in it and that the Library and its use are covered by |
649 |
+this License. You must supply a copy of this License. If the work |
650 |
+during execution displays copyright notices, you must include the |
651 |
+copyright notice for the Library among them, as well as a reference |
652 |
+directing the user to the copy of this License. Also, you must do one |
653 |
+of these things: |
654 |
+ |
655 |
+ a) Accompany the work with the complete corresponding |
656 |
+ machine-readable source code for the Library including whatever |
657 |
+ changes were used in the work (which must be distributed under |
658 |
+ Sections 1 and 2 above); and, if the work is an executable linked |
659 |
+ with the Library, with the complete machine-readable "work that |
660 |
+ uses the Library", as object code and/or source code, so that the |
661 |
+ user can modify the Library and then relink to produce a modified |
662 |
+ executable containing the modified Library. (It is understood |
663 |
+ that the user who changes the contents of definitions files in the |
664 |
+ Library will not necessarily be able to recompile the application |
665 |
+ to use the modified definitions.) |
666 |
+ |
667 |
+ b) Use a suitable shared library mechanism for linking with the |
668 |
+ Library. A suitable mechanism is one that (1) uses at run time a |
669 |
+ copy of the library already present on the user's computer system, |
670 |
+ rather than copying library functions into the executable, and (2) |
671 |
+ will operate properly with a modified version of the library, if |
672 |
+ the user installs one, as long as the modified version is |
673 |
+ interface-compatible with the version that the work was made with. |
674 |
+ |
675 |
+ c) Accompany the work with a written offer, valid for at least |
676 |
+ three years, to give the same user the materials specified in |
677 |
+ Subsection 6a, above, for a charge no more than the cost of |
678 |
+ performing this distribution. |
679 |
+ |
680 |
+ d) If distribution of the work is made by offering access to copy |
681 |
+ from a designated place, offer equivalent access to copy the above |
682 |
+ specified materials from the same place. |
683 |
+ |
684 |
+ e) Verify that the user has already received a copy of these |
685 |
+ materials or that you have already sent this user a copy. |
686 |
+ |
687 |
+ For an executable, the required form of the "work that uses the |
688 |
+Library" must include any data and utility programs needed for |
689 |
+reproducing the executable from it. However, as a special exception, |
690 |
+the materials to be distributed need not include anything that is |
691 |
+normally distributed (in either source or binary form) with the major |
692 |
+components (compiler, kernel, and so on) of the operating system on |
693 |
+which the executable runs, unless that component itself accompanies |
694 |
+the executable. |
695 |
+ |
696 |
+ It may happen that this requirement contradicts the license |
697 |
+restrictions of other proprietary libraries that do not normally |
698 |
+accompany the operating system. Such a contradiction means you cannot |
699 |
+use both them and the Library together in an executable that you |
700 |
+distribute. |
701 |
+ |
702 |
+ 7. You may place library facilities that are a work based on the |
703 |
+Library side-by-side in a single library together with other library |
704 |
+facilities not covered by this License, and distribute such a combined |
705 |
+library, provided that the separate distribution of the work based on |
706 |
+the Library and of the other library facilities is otherwise |
707 |
+permitted, and provided that you do these two things: |
708 |
+ |
709 |
+ a) Accompany the combined library with a copy of the same work |
710 |
+ based on the Library, uncombined with any other library |
711 |
+ facilities. This must be distributed under the terms of the |
712 |
+ Sections above. |
713 |
+ |
714 |
+ b) Give prominent notice with the combined library of the fact |
715 |
+ that part of it is a work based on the Library, and explaining |
716 |
+ where to find the accompanying uncombined form of the same work. |
717 |
+ |
718 |
+ 8. You may not copy, modify, sublicense, link with, or distribute |
719 |
+the Library except as expressly provided under this License. Any |
720 |
+attempt otherwise to copy, modify, sublicense, link with, or |
721 |
+distribute the Library is void, and will automatically terminate your |
722 |
+rights under this License. However, parties who have received copies, |
723 |
+or rights, from you under this License will not have their licenses |
724 |
+terminated so long as such parties remain in full compliance. |
725 |
+ |
726 |
+ 9. You are not required to accept this License, since you have not |
727 |
+signed it. However, nothing else grants you permission to modify or |
728 |
+distribute the Library or its derivative works. These actions are |
729 |
+prohibited by law if you do not accept this License. Therefore, by |
730 |
+modifying or distributing the Library (or any work based on the |
731 |
+Library), you indicate your acceptance of this License to do so, and |
732 |
+all its terms and conditions for copying, distributing or modifying |
733 |
+the Library or works based on it. |
734 |
+ |
735 |
+ 10. Each time you redistribute the Library (or any work based on the |
736 |
+Library), the recipient automatically receives a license from the |
737 |
+original licensor to copy, distribute, link with or modify the Library |
738 |
+subject to these terms and conditions. You may not impose any further |
739 |
+restrictions on the recipients' exercise of the rights granted herein. |
740 |
+You are not responsible for enforcing compliance by third parties with |
741 |
+this License. |
742 |
+ |
743 |
+ 11. If, as a consequence of a court judgment or allegation of patent |
744 |
+infringement or for any other reason (not limited to patent issues), |
745 |
+conditions are imposed on you (whether by court order, agreement or |
746 |
+otherwise) that contradict the conditions of this License, they do not |
747 |
+excuse you from the conditions of this License. If you cannot |
748 |
+distribute so as to satisfy simultaneously your obligations under this |
749 |
+License and any other pertinent obligations, then as a consequence you |
750 |
+may not distribute the Library at all. For example, if a patent |
751 |
+license would not permit royalty-free redistribution of the Library by |
752 |
+all those who receive copies directly or indirectly through you, then |
753 |
+the only way you could satisfy both it and this License would be to |
754 |
+refrain entirely from distribution of the Library. |
755 |
+ |
756 |
+If any portion of this section is held invalid or unenforceable under |
757 |
+any particular circumstance, the balance of the section is intended to |
758 |
+apply, and the section as a whole is intended to apply in other |
759 |
+circumstances. |
760 |
+ |
761 |
+It is not the purpose of this section to induce you to infringe any |
762 |
+patents or other property right claims or to contest validity of any |
763 |
+such claims; this section has the sole purpose of protecting the |
764 |
+integrity of the free software distribution system which is |
765 |
+implemented by public license practices. Many people have made |
766 |
+generous contributions to the wide range of software distributed |
767 |
+through that system in reliance on consistent application of that |
768 |
+system; it is up to the author/donor to decide if he or she is willing |
769 |
+to distribute software through any other system and a licensee cannot |
770 |
+impose that choice. |
771 |
+ |
772 |
+This section is intended to make thoroughly clear what is believed to |
773 |
+be a consequence of the rest of this License. |
774 |
+ |
775 |
+ 12. If the distribution and/or use of the Library is restricted in |
776 |
+certain countries either by patents or by copyrighted interfaces, the |
777 |
+original copyright holder who places the Library under this License |
778 |
+may add an explicit geographical distribution limitation excluding those |
779 |
+countries, so that distribution is permitted only in or among |
780 |
+countries not thus excluded. In such case, this License incorporates |
781 |
+the limitation as if written in the body of this License. |
782 |
+ |
783 |
+ 13. The Free Software Foundation may publish revised and/or new |
784 |
+versions of the Lesser General Public License from time to time. |
785 |
+Such new versions will be similar in spirit to the present version, |
786 |
+but may differ in detail to address new problems or concerns. |
787 |
+ |
788 |
+Each version is given a distinguishing version number. If the Library |
789 |
+specifies a version number of this License which applies to it and |
790 |
+"any later version", you have the option of following the terms and |
791 |
+conditions either of that version or of any later version published by |
792 |
+the Free Software Foundation. If the Library does not specify a |
793 |
+license version number, you may choose any version ever published by |
794 |
+the Free Software Foundation. |
795 |
+ |
796 |
+ 14. If you wish to incorporate parts of the Library into other free |
797 |
+programs whose distribution conditions are incompatible with these, |
798 |
+write to the author to ask for permission. For software which is |
799 |
+copyrighted by the Free Software Foundation, write to the Free |
800 |
+Software Foundation; we sometimes make exceptions for this. Our |
801 |
+decision will be guided by the two goals of preserving the free status |
802 |
+of all derivatives of our free software and of promoting the sharing |
803 |
+and reuse of software generally. |
804 |
+ |
805 |
+ NO WARRANTY |
806 |
+ |
807 |
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO |
808 |
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. |
809 |
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR |
810 |
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY |
811 |
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE |
812 |
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
813 |
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE |
814 |
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME |
815 |
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
816 |
+ |
817 |
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN |
818 |
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY |
819 |
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU |
820 |
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR |
821 |
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE |
822 |
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING |
823 |
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A |
824 |
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
825 |
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
826 |
+DAMAGES. |
827 |
+ |
828 |
+ END OF TERMS AND CONDITIONS |
829 |
+ |
830 |
+ How to Apply These Terms to Your New Libraries |
831 |
+ |
832 |
+ If you develop a new library, and you want it to be of the greatest |
833 |
+possible use to the public, we recommend making it free software that |
834 |
+everyone can redistribute and change. You can do so by permitting |
835 |
+redistribution under these terms (or, alternatively, under the terms |
836 |
+of the ordinary General Public License). |
837 |
+ |
838 |
+ To apply these terms, attach the following notices to the library. |
839 |
+It is safest to attach them to the start of each source file to most |
840 |
+effectively convey the exclusion of warranty; and each file should |
841 |
+have at least the "copyright" line and a pointer to where the full |
842 |
+notice is found. |
843 |
+ |
844 |
+ |
845 |
+ <one line to give the library's name and a brief idea of what it does.> |
846 |
+ Copyright (C) <year> <name of author> |
847 |
+ |
848 |
+ This library is free software; you can redistribute it and/or |
849 |
+ modify it under the terms of the GNU Lesser General Public |
850 |
+ License as published by the Free Software Foundation; either |
851 |
+ version 2.1 of the License, or (at your option) any later version. |
852 |
+ |
853 |
+ This library is distributed in the hope that it will be useful, |
854 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
855 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
856 |
+ Lesser General Public License for more details. |
857 |
+ |
858 |
+ You should have received a copy of the GNU Lesser General Public |
859 |
+ License along with this library; if not, write to the Free Software |
860 |
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
861 |
+ |
862 |
+Also add information on how to contact you by electronic and paper mail. |
863 |
+ |
864 |
+You should also get your employer (if you work as a programmer) or |
865 |
+your school, if any, to sign a "copyright disclaimer" for the library, |
866 |
+if necessary. Here is a sample; alter the names: |
867 |
+ |
868 |
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the |
869 |
+ library `Frob' (a library for tweaking knobs) written by James |
870 |
+ Random Hacker. |
871 |
+ |
872 |
+ <signature of Ty Coon>, 1 April 1990 |
873 |
+ Ty Coon, President of Vice |
874 |
+ |
875 |
+That's all there is to it! |
876 |
+ |
877 |
+ |
878 |
diff --git a/src/gui/kstatusnotifier/kstatusnotifieritem.cpp b/src/gui/kstatusnotifier/kstatusnotifieritem.cpp |
879 |
new file mode 100644 |
880 |
index 00000000..42e4cc0a |
881 |
--- /dev/null |
882 |
+++ b/src/gui/kstatusnotifier/kstatusnotifieritem.cpp |
883 |
@@ -0,0 +1,829 @@ |
884 |
+/* This file is part of the KDE libraries |
885 |
+ Copyright 2009 by Marco Martin <notmart@gmail.com> |
886 |
+ |
887 |
+ This library is free software; you can redistribute it and/or |
888 |
+ modify it under the terms of the GNU Library General Public |
889 |
+ License (LGPL) as published by the Free Software Foundation; |
890 |
+ either version 2 of the License, or (at your option) any later |
891 |
+ version. |
892 |
+ |
893 |
+ This library is distributed in the hope that it will be useful, |
894 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
895 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
896 |
+ Library General Public License for more details. |
897 |
+ |
898 |
+ You should have received a copy of the GNU Library General Public License |
899 |
+ along with this library; see the file COPYING.LIB. If not, write to |
900 |
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
901 |
+ Boston, MA 02110-1301, USA. |
902 |
+*/ |
903 |
+ |
904 |
+#include "kstatusnotifieritem.h" |
905 |
+#include "kstatusnotifieritemprivate_p.h" |
906 |
+#include "kstatusnotifieritemdbus_p.h" |
907 |
+ |
908 |
+#include <QDBusConnection> |
909 |
+#include <QMessageBox> |
910 |
+#include <QPixmap> |
911 |
+#include <QImage> |
912 |
+#include <QApplication> |
913 |
+#include <QMenu> |
914 |
+#include <QMovie> |
915 |
+#include <QPainter> |
916 |
+#include <qstandardpaths.h> |
917 |
+ |
918 |
+#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) |
919 |
+#define QIMAGE_SIZE(x) (x.byteCount()) |
920 |
+#else |
921 |
+#define QIMAGE_SIZE(x) (x.sizeInBytes()) |
922 |
+#endif |
923 |
+ |
924 |
+static const char s_statusNotifierWatcherServiceName[] = "org.kde.StatusNotifierWatcher"; |
925 |
+static const int s_legacyTrayIconSize = 24; |
926 |
+ |
927 |
+#include <dbusmenuexporter.h> |
928 |
+ |
929 |
+KStatusNotifierItem::KStatusNotifierItem(QObject *parent) |
930 |
+ : QObject(parent), |
931 |
+ d(new KStatusNotifierItemPrivate(this)) |
932 |
+{ |
933 |
+ d->init(QString()); |
934 |
+} |
935 |
+ |
936 |
+KStatusNotifierItem::KStatusNotifierItem(const QString &id, QObject *parent) |
937 |
+ : QObject(parent), |
938 |
+ d(new KStatusNotifierItemPrivate(this)) |
939 |
+{ |
940 |
+ d->init(id); |
941 |
+} |
942 |
+ |
943 |
+KStatusNotifierItem::~KStatusNotifierItem() |
944 |
+{ |
945 |
+ delete d->statusNotifierWatcher; |
946 |
+ delete d->notificationsClient; |
947 |
+ delete d->systemTrayIcon; |
948 |
+ if (!qApp->closingDown()) { |
949 |
+ delete d->menu; |
950 |
+ } |
951 |
+ delete d; |
952 |
+} |
953 |
+ |
954 |
+QString KStatusNotifierItem::id() const |
955 |
+{ |
956 |
+ //qDebug() << "id requested" << d->id; |
957 |
+ return d->id; |
958 |
+} |
959 |
+ |
960 |
+void KStatusNotifierItem::setCategory(const ItemCategory category) |
961 |
+{ |
962 |
+ d->category = category; |
963 |
+} |
964 |
+ |
965 |
+KStatusNotifierItem::ItemStatus KStatusNotifierItem::status() const |
966 |
+{ |
967 |
+ return d->status; |
968 |
+} |
969 |
+ |
970 |
+KStatusNotifierItem::ItemCategory KStatusNotifierItem::category() const |
971 |
+{ |
972 |
+ return d->category; |
973 |
+} |
974 |
+ |
975 |
+void KStatusNotifierItem::setTitle(const QString &title) |
976 |
+{ |
977 |
+ d->title = title; |
978 |
+} |
979 |
+ |
980 |
+void KStatusNotifierItem::setStatus(const ItemStatus status) |
981 |
+{ |
982 |
+ if (d->status == status) { |
983 |
+ return; |
984 |
+ } |
985 |
+ |
986 |
+ d->status = status; |
987 |
+ emit d->statusNotifierItemDBus->NewStatus(QString::fromLatin1(metaObject()->enumerator(metaObject()->indexOfEnumerator("ItemStatus")).valueToKey(d->status))); |
988 |
+ |
989 |
+ if (d->systemTrayIcon) { |
990 |
+ d->syncLegacySystemTrayIcon(); |
991 |
+ } |
992 |
+} |
993 |
+ |
994 |
+//normal icon |
995 |
+ |
996 |
+void KStatusNotifierItem::setIconByName(const QString &name) |
997 |
+{ |
998 |
+ if (d->iconName == name) { |
999 |
+ return; |
1000 |
+ } |
1001 |
+ |
1002 |
+ d->serializedIcon = KDbusImageVector(); |
1003 |
+ d->iconName = name; |
1004 |
+ emit d->statusNotifierItemDBus->NewIcon(); |
1005 |
+ if (d->systemTrayIcon) { |
1006 |
+ // It's possible to pass paths as well |
1007 |
+ QIcon trayIcon = QIcon::fromTheme(name); |
1008 |
+ if(trayIcon.isNull()) |
1009 |
+ trayIcon = QIcon(name); |
1010 |
+ d->systemTrayIcon->setIcon(trayIcon); |
1011 |
+ } |
1012 |
+} |
1013 |
+ |
1014 |
+QString KStatusNotifierItem::iconName() const |
1015 |
+{ |
1016 |
+ return d->iconName; |
1017 |
+} |
1018 |
+ |
1019 |
+void KStatusNotifierItem::setIconByPixmap(const QIcon &icon) |
1020 |
+{ |
1021 |
+ if (d->iconName.isEmpty() && d->icon.cacheKey() == icon.cacheKey()) { |
1022 |
+ return; |
1023 |
+ } |
1024 |
+ |
1025 |
+ d->iconName.clear(); |
1026 |
+ d->serializedIcon = d->iconToVector(icon); |
1027 |
+ emit d->statusNotifierItemDBus->NewIcon(); |
1028 |
+ |
1029 |
+ d->icon = icon; |
1030 |
+ if (d->systemTrayIcon) { |
1031 |
+ d->systemTrayIcon->setIcon(icon); |
1032 |
+ } |
1033 |
+} |
1034 |
+ |
1035 |
+QIcon KStatusNotifierItem::iconPixmap() const |
1036 |
+{ |
1037 |
+ return d->icon; |
1038 |
+} |
1039 |
+ |
1040 |
+void KStatusNotifierItem::setOverlayIconByName(const QString &name) |
1041 |
+{ |
1042 |
+ if (d->overlayIconName == name) { |
1043 |
+ return; |
1044 |
+ } |
1045 |
+ |
1046 |
+ d->overlayIconName = name; |
1047 |
+ emit d->statusNotifierItemDBus->NewOverlayIcon(); |
1048 |
+ if (d->systemTrayIcon) { |
1049 |
+ QPixmap iconPixmap = QIcon::fromTheme(d->iconName).pixmap(s_legacyTrayIconSize, s_legacyTrayIconSize); |
1050 |
+ if (!name.isEmpty()) { |
1051 |
+ QPixmap overlayPixmap = QIcon::fromTheme(d->overlayIconName).pixmap(s_legacyTrayIconSize / 2, s_legacyTrayIconSize / 2); |
1052 |
+ QPainter p(&iconPixmap); |
1053 |
+ p.drawPixmap(iconPixmap.width() - overlayPixmap.width(), iconPixmap.height() - overlayPixmap.height(), overlayPixmap); |
1054 |
+ p.end(); |
1055 |
+ } |
1056 |
+ d->systemTrayIcon->setIcon(iconPixmap); |
1057 |
+ } |
1058 |
+} |
1059 |
+ |
1060 |
+QString KStatusNotifierItem::overlayIconName() const |
1061 |
+{ |
1062 |
+ return d->overlayIconName; |
1063 |
+} |
1064 |
+ |
1065 |
+void KStatusNotifierItem::setOverlayIconByPixmap(const QIcon &icon) |
1066 |
+{ |
1067 |
+ if (d->overlayIconName.isEmpty() && d->overlayIcon.cacheKey() == icon.cacheKey()) { |
1068 |
+ return; |
1069 |
+ } |
1070 |
+ |
1071 |
+ d->overlayIconName.clear(); |
1072 |
+ d->serializedOverlayIcon = d->iconToVector(icon); |
1073 |
+ emit d->statusNotifierItemDBus->NewOverlayIcon(); |
1074 |
+ |
1075 |
+ d->overlayIcon = icon; |
1076 |
+ if (d->systemTrayIcon) { |
1077 |
+ QPixmap iconPixmap = d->icon.pixmap(s_legacyTrayIconSize, s_legacyTrayIconSize); |
1078 |
+ QPixmap overlayPixmap = d->overlayIcon.pixmap(s_legacyTrayIconSize / 2, s_legacyTrayIconSize / 2); |
1079 |
+ |
1080 |
+ QPainter p(&iconPixmap); |
1081 |
+ p.drawPixmap(iconPixmap.width() - overlayPixmap.width(), iconPixmap.height() - overlayPixmap.height(), overlayPixmap); |
1082 |
+ p.end(); |
1083 |
+ d->systemTrayIcon->setIcon(iconPixmap); |
1084 |
+ } |
1085 |
+} |
1086 |
+ |
1087 |
+QIcon KStatusNotifierItem::overlayIconPixmap() const |
1088 |
+{ |
1089 |
+ return d->overlayIcon; |
1090 |
+} |
1091 |
+ |
1092 |
+//Icons and movie for requesting attention state |
1093 |
+ |
1094 |
+void KStatusNotifierItem::setAttentionIconByName(const QString &name) |
1095 |
+{ |
1096 |
+ if (d->attentionIconName == name) { |
1097 |
+ return; |
1098 |
+ } |
1099 |
+ |
1100 |
+ d->serializedAttentionIcon = KDbusImageVector(); |
1101 |
+ d->attentionIconName = name; |
1102 |
+ emit d->statusNotifierItemDBus->NewAttentionIcon(); |
1103 |
+} |
1104 |
+ |
1105 |
+QString KStatusNotifierItem::attentionIconName() const |
1106 |
+{ |
1107 |
+ return d->attentionIconName; |
1108 |
+} |
1109 |
+ |
1110 |
+void KStatusNotifierItem::setAttentionIconByPixmap(const QIcon &icon) |
1111 |
+{ |
1112 |
+ if (d->attentionIconName.isEmpty() && d->attentionIcon.cacheKey() == icon.cacheKey()) { |
1113 |
+ return; |
1114 |
+ } |
1115 |
+ |
1116 |
+ d->attentionIconName.clear(); |
1117 |
+ d->serializedAttentionIcon = d->iconToVector(icon); |
1118 |
+ d->attentionIcon = icon; |
1119 |
+ emit d->statusNotifierItemDBus->NewAttentionIcon(); |
1120 |
+} |
1121 |
+ |
1122 |
+QIcon KStatusNotifierItem::attentionIconPixmap() const |
1123 |
+{ |
1124 |
+ return d->attentionIcon; |
1125 |
+} |
1126 |
+ |
1127 |
+void KStatusNotifierItem::setAttentionMovieByName(const QString &name) |
1128 |
+{ |
1129 |
+ if (d->movieName == name) { |
1130 |
+ return; |
1131 |
+ } |
1132 |
+ |
1133 |
+ d->movieName = name; |
1134 |
+ |
1135 |
+ delete d->movie; |
1136 |
+ d->movie = nullptr; |
1137 |
+ |
1138 |
+ emit d->statusNotifierItemDBus->NewAttentionIcon(); |
1139 |
+ |
1140 |
+ if (d->systemTrayIcon) { |
1141 |
+ d->movie = new QMovie(d->movieName); |
1142 |
+ d->systemTrayIcon->setMovie(d->movie); |
1143 |
+ } |
1144 |
+} |
1145 |
+ |
1146 |
+QString KStatusNotifierItem::attentionMovieName() const |
1147 |
+{ |
1148 |
+ return d->movieName; |
1149 |
+} |
1150 |
+ |
1151 |
+//ToolTip |
1152 |
+static void setTrayToolTip(KStatusNotifierLegacyIcon *systemTrayIcon, const QString &title, const QString &) |
1153 |
+{ |
1154 |
+ if (systemTrayIcon) { |
1155 |
+ systemTrayIcon->setToolTip(title); |
1156 |
+ } |
1157 |
+} |
1158 |
+ |
1159 |
+void KStatusNotifierItem::setToolTip(const QString &iconName, const QString &title, const QString &subTitle) |
1160 |
+{ |
1161 |
+ if (d->toolTipIconName == iconName && |
1162 |
+ d->toolTipTitle == title && |
1163 |
+ d->toolTipSubTitle == subTitle) { |
1164 |
+ return; |
1165 |
+ } |
1166 |
+ |
1167 |
+ d->serializedToolTipIcon = KDbusImageVector(); |
1168 |
+ d->toolTipIconName = iconName; |
1169 |
+ |
1170 |
+ d->toolTipTitle = title; |
1171 |
+ setTrayToolTip(d->systemTrayIcon, title, subTitle); |
1172 |
+ d->toolTipSubTitle = subTitle; |
1173 |
+ emit d->statusNotifierItemDBus->NewToolTip(); |
1174 |
+} |
1175 |
+ |
1176 |
+void KStatusNotifierItem::setToolTip(const QIcon &icon, const QString &title, const QString &subTitle) |
1177 |
+{ |
1178 |
+ if (d->toolTipIconName.isEmpty() && d->toolTipIcon.cacheKey() == icon.cacheKey() && |
1179 |
+ d->toolTipTitle == title && |
1180 |
+ d->toolTipSubTitle == subTitle) { |
1181 |
+ return; |
1182 |
+ } |
1183 |
+ |
1184 |
+ d->toolTipIconName.clear(); |
1185 |
+ d->serializedToolTipIcon = d->iconToVector(icon); |
1186 |
+ d->toolTipIcon = icon; |
1187 |
+ |
1188 |
+ d->toolTipTitle = title; |
1189 |
+ setTrayToolTip(d->systemTrayIcon, title, subTitle); |
1190 |
+ |
1191 |
+ d->toolTipSubTitle = subTitle; |
1192 |
+ emit d->statusNotifierItemDBus->NewToolTip(); |
1193 |
+} |
1194 |
+ |
1195 |
+void KStatusNotifierItem::setToolTipIconByName(const QString &name) |
1196 |
+{ |
1197 |
+ if (d->toolTipIconName == name) { |
1198 |
+ return; |
1199 |
+ } |
1200 |
+ |
1201 |
+ d->serializedToolTipIcon = KDbusImageVector(); |
1202 |
+ d->toolTipIconName = name; |
1203 |
+ emit d->statusNotifierItemDBus->NewToolTip(); |
1204 |
+} |
1205 |
+ |
1206 |
+QString KStatusNotifierItem::toolTipIconName() const |
1207 |
+{ |
1208 |
+ return d->toolTipIconName; |
1209 |
+} |
1210 |
+ |
1211 |
+void KStatusNotifierItem::setToolTipIconByPixmap(const QIcon &icon) |
1212 |
+{ |
1213 |
+ if (d->toolTipIconName.isEmpty() && d->toolTipIcon.cacheKey() == icon.cacheKey()) { |
1214 |
+ return; |
1215 |
+ } |
1216 |
+ |
1217 |
+ d->toolTipIconName.clear(); |
1218 |
+ d->serializedToolTipIcon = d->iconToVector(icon); |
1219 |
+ d->toolTipIcon = icon; |
1220 |
+ emit d->statusNotifierItemDBus->NewToolTip(); |
1221 |
+} |
1222 |
+ |
1223 |
+QIcon KStatusNotifierItem::toolTipIconPixmap() const |
1224 |
+{ |
1225 |
+ return d->toolTipIcon; |
1226 |
+} |
1227 |
+ |
1228 |
+void KStatusNotifierItem::setToolTipTitle(const QString &title) |
1229 |
+{ |
1230 |
+ if (d->toolTipTitle == title) { |
1231 |
+ return; |
1232 |
+ } |
1233 |
+ |
1234 |
+ d->toolTipTitle = title; |
1235 |
+ emit d->statusNotifierItemDBus->NewToolTip(); |
1236 |
+ setTrayToolTip(d->systemTrayIcon, title, d->toolTipSubTitle); |
1237 |
+} |
1238 |
+ |
1239 |
+QString KStatusNotifierItem::toolTipTitle() const |
1240 |
+{ |
1241 |
+ return d->toolTipTitle; |
1242 |
+} |
1243 |
+ |
1244 |
+void KStatusNotifierItem::setToolTipSubTitle(const QString &subTitle) |
1245 |
+{ |
1246 |
+ if (d->toolTipSubTitle == subTitle) { |
1247 |
+ return; |
1248 |
+ } |
1249 |
+ |
1250 |
+ d->toolTipSubTitle = subTitle; |
1251 |
+ emit d->statusNotifierItemDBus->NewToolTip(); |
1252 |
+} |
1253 |
+ |
1254 |
+QString KStatusNotifierItem::toolTipSubTitle() const |
1255 |
+{ |
1256 |
+ return d->toolTipSubTitle; |
1257 |
+} |
1258 |
+ |
1259 |
+void KStatusNotifierItem::setContextMenu(QMenu *menu) |
1260 |
+{ |
1261 |
+ if (d->menu && d->menu != menu) { |
1262 |
+ d->menu->removeEventFilter(this); |
1263 |
+ delete d->menu; |
1264 |
+ } |
1265 |
+ |
1266 |
+ if (!menu) { |
1267 |
+ d->menu = nullptr; |
1268 |
+ return; |
1269 |
+ } |
1270 |
+ |
1271 |
+ if (d->systemTrayIcon) { |
1272 |
+ d->systemTrayIcon->setContextMenu(menu); |
1273 |
+ } else if (d->menu != menu) { |
1274 |
+ d->menuObjectPath = QStringLiteral("/MenuBar"); |
1275 |
+ new DBusMenuExporter(d->menuObjectPath, menu, d->statusNotifierItemDBus->dbusConnection()); |
1276 |
+ |
1277 |
+ connect(menu, SIGNAL(aboutToShow()), this, SLOT(contextMenuAboutToShow())); |
1278 |
+ } |
1279 |
+ |
1280 |
+ d->menu = menu; |
1281 |
+ Qt::WindowFlags oldFlags = d->menu->windowFlags(); |
1282 |
+ d->menu->setParent(nullptr); |
1283 |
+ d->menu->setWindowFlags(oldFlags); |
1284 |
+} |
1285 |
+ |
1286 |
+QMenu *KStatusNotifierItem::contextMenu() const |
1287 |
+{ |
1288 |
+ return d->menu; |
1289 |
+} |
1290 |
+ |
1291 |
+void KStatusNotifierItem::setAssociatedWidget(QWidget *associatedWidget) |
1292 |
+{ |
1293 |
+ if (associatedWidget) { |
1294 |
+ d->associatedWidget = associatedWidget->window(); |
1295 |
+ d->associatedWidgetPos = QPoint(-1, -1); |
1296 |
+ } else if (d->associatedWidget) { |
1297 |
+ d->associatedWidget = nullptr; |
1298 |
+ } |
1299 |
+ |
1300 |
+ if (d->systemTrayIcon) { |
1301 |
+ delete d->systemTrayIcon; |
1302 |
+ d->systemTrayIcon = nullptr; |
1303 |
+ d->setLegacySystemTrayEnabled(true); |
1304 |
+ } |
1305 |
+} |
1306 |
+ |
1307 |
+QWidget *KStatusNotifierItem::associatedWidget() const |
1308 |
+{ |
1309 |
+ return d->associatedWidget; |
1310 |
+} |
1311 |
+ |
1312 |
+QList<QAction *> KStatusNotifierItem::actionCollection() const |
1313 |
+{ |
1314 |
+ return d->actionCollection.values(); |
1315 |
+} |
1316 |
+ |
1317 |
+void KStatusNotifierItem::addAction(const QString &name, QAction *action) |
1318 |
+{ |
1319 |
+ d->actionCollection.insert(name, action); |
1320 |
+} |
1321 |
+ |
1322 |
+void KStatusNotifierItem::removeAction(const QString &name) |
1323 |
+{ |
1324 |
+ d->actionCollection.remove(name); |
1325 |
+} |
1326 |
+ |
1327 |
+QAction* KStatusNotifierItem::action(const QString &name) const |
1328 |
+{ |
1329 |
+ return d->actionCollection.value(name); |
1330 |
+} |
1331 |
+ |
1332 |
+void KStatusNotifierItem::showMessage(const QString &title, const QString &message, const QString &icon, int timeout) |
1333 |
+{ |
1334 |
+ if (!d->notificationsClient) { |
1335 |
+ d->notificationsClient = new org::freedesktop::Notifications(QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), |
1336 |
+ QDBusConnection::sessionBus()); |
1337 |
+ } |
1338 |
+ |
1339 |
+ uint id = 0; |
1340 |
+ { |
1341 |
+ QVariantMap hints; |
1342 |
+ |
1343 |
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) |
1344 |
+ QString desktopFileName = QGuiApplication::desktopFileName(); |
1345 |
+#else |
1346 |
+ QString desktopFileName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); |
1347 |
+#endif |
1348 |
+ if (!desktopFileName.isEmpty()) { |
1349 |
+ // handle apps which set the desktopFileName property with filename suffix, |
1350 |
+ // due to unclear API dox (https://bugreports.qt.io/browse/QTBUG-75521) |
1351 |
+ if (desktopFileName.endsWith(QLatin1String(".desktop"))) { |
1352 |
+ desktopFileName.chop(8); |
1353 |
+ } |
1354 |
+ hints.insert(QStringLiteral("desktop-entry"), desktopFileName); |
1355 |
+ } |
1356 |
+ |
1357 |
+ d->notificationsClient->Notify(d->title, id, icon, title, message, QStringList(), hints, timeout); |
1358 |
+ } |
1359 |
+} |
1360 |
+ |
1361 |
+QString KStatusNotifierItem::title() const |
1362 |
+{ |
1363 |
+ return d->title; |
1364 |
+} |
1365 |
+ |
1366 |
+void KStatusNotifierItem::activate(const QPoint &pos) |
1367 |
+{ |
1368 |
+ //if the user activated the icon the NeedsAttention state is no longer necessary |
1369 |
+ //FIXME: always true? |
1370 |
+ if (d->status == NeedsAttention) { |
1371 |
+ d->status = Active; |
1372 |
+ emit d->statusNotifierItemDBus->NewStatus(QString::fromLatin1(metaObject()->enumerator(metaObject()->indexOfEnumerator("ItemStatus")).valueToKey(d->status))); |
1373 |
+ } |
1374 |
+ |
1375 |
+ if (d->associatedWidget && d->associatedWidget == d->menu) { |
1376 |
+ d->statusNotifierItemDBus->ContextMenu(pos.x(), pos.y()); |
1377 |
+ return; |
1378 |
+ } |
1379 |
+ |
1380 |
+ if (d->menu && d->menu->isVisible()) { |
1381 |
+ d->menu->hide(); |
1382 |
+ } |
1383 |
+ |
1384 |
+ if (!d->associatedWidget) { |
1385 |
+ emit activateRequested(true, pos); |
1386 |
+ return; |
1387 |
+ } |
1388 |
+ |
1389 |
+ d->checkVisibility(pos); |
1390 |
+} |
1391 |
+ |
1392 |
+bool KStatusNotifierItemPrivate::checkVisibility(QPoint pos, bool perform) |
1393 |
+{ |
1394 |
+ const bool unmapped = !(associatedWidget->isVisible() && !associatedWidget->isMinimized()); |
1395 |
+ if (perform) { |
1396 |
+ minimizeRestore(unmapped); |
1397 |
+ emit q->activateRequested(unmapped, pos); |
1398 |
+ } |
1399 |
+ return unmapped; |
1400 |
+} |
1401 |
+ |
1402 |
+bool KStatusNotifierItem::eventFilter(QObject *watched, QEvent *event) |
1403 |
+{ |
1404 |
+ if (d->systemTrayIcon == nullptr) { |
1405 |
+ //FIXME: ugly ugly workaround to weird QMenu's focus problems |
1406 |
+ if (watched == d->menu && |
1407 |
+ (event->type() == QEvent::WindowDeactivate || (event->type() == QEvent::MouseButtonRelease && static_cast<QMouseEvent *>(event)->button() == Qt::LeftButton))) { |
1408 |
+ //put at the back of even queue to let the action activate anyways |
1409 |
+ QTimer::singleShot(0, this, [this]() { d->hideMenu(); }); |
1410 |
+ } |
1411 |
+ } |
1412 |
+ return false; |
1413 |
+} |
1414 |
+ |
1415 |
+//KStatusNotifierItemPrivate |
1416 |
+ |
1417 |
+const int KStatusNotifierItemPrivate::s_protocolVersion = 0; |
1418 |
+ |
1419 |
+KStatusNotifierItemPrivate::KStatusNotifierItemPrivate(KStatusNotifierItem *item) |
1420 |
+ : q(item), |
1421 |
+ category(KStatusNotifierItem::ApplicationStatus), |
1422 |
+ status(KStatusNotifierItem::Passive), |
1423 |
+ movie(nullptr), |
1424 |
+ menu(nullptr), |
1425 |
+ associatedWidget(nullptr), |
1426 |
+ titleAction(nullptr), |
1427 |
+ statusNotifierWatcher(nullptr), |
1428 |
+ notificationsClient(nullptr), |
1429 |
+ systemTrayIcon(nullptr) |
1430 |
+{ |
1431 |
+} |
1432 |
+ |
1433 |
+void KStatusNotifierItemPrivate::init(const QString &extraId) |
1434 |
+{ |
1435 |
+ qDBusRegisterMetaType<KDbusImageStruct>(); |
1436 |
+ qDBusRegisterMetaType<KDbusImageVector>(); |
1437 |
+ qDBusRegisterMetaType<KDbusToolTipStruct>(); |
1438 |
+ |
1439 |
+ statusNotifierItemDBus = new KStatusNotifierItemDBus(q); |
1440 |
+ q->setAssociatedWidget(qobject_cast<QWidget *>(q->parent())); |
1441 |
+ |
1442 |
+ QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QString::fromLatin1(s_statusNotifierWatcherServiceName), |
1443 |
+ QDBusConnection::sessionBus(), |
1444 |
+ QDBusServiceWatcher::WatchForOwnerChange, |
1445 |
+ q); |
1446 |
+ QObject::connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), |
1447 |
+ q, SLOT(serviceChange(QString,QString,QString))); |
1448 |
+ |
1449 |
+ //create a default menu, just like in KSystemtrayIcon |
1450 |
+ QMenu *m = new QMenu(associatedWidget); |
1451 |
+ |
1452 |
+ title = QGuiApplication::applicationDisplayName(); |
1453 |
+ if (title.isEmpty()) { |
1454 |
+ title = QCoreApplication::applicationName(); |
1455 |
+ } |
1456 |
+ titleAction = m->addSection(qApp->windowIcon(), title); |
1457 |
+ m->setTitle(title); |
1458 |
+ q->setContextMenu(m); |
1459 |
+ |
1460 |
+ QAction *action = new QAction(q); |
1461 |
+ action->setText(KStatusNotifierItem::tr("Quit")); |
1462 |
+ action->setIcon(QIcon::fromTheme(QStringLiteral("application-exit"))); |
1463 |
+ // cannot yet convert to function-pointer-based connect: |
1464 |
+ // some apps like kalarm or korgac have a hack to rewire the connection |
1465 |
+ // of the "quit" action to a own slot, and rely on the name-based slot to disconnect |
1466 |
+ // TODO: extend KStatusNotifierItem API to support such needs |
1467 |
+ QObject::connect(action, SIGNAL(triggered()), q, SLOT(maybeQuit())); |
1468 |
+ actionCollection.insert(QStringLiteral("quit"), action); |
1469 |
+ |
1470 |
+ id = title; |
1471 |
+ if (!extraId.isEmpty()) { |
1472 |
+ id.append(QLatin1Char('_')).append(extraId); |
1473 |
+ } |
1474 |
+ |
1475 |
+ // Init iconThemePath to the app folder for now |
1476 |
+ iconThemePath = QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("icons"), QStandardPaths::LocateDirectory); |
1477 |
+ |
1478 |
+ registerToDaemon(); |
1479 |
+} |
1480 |
+ |
1481 |
+void KStatusNotifierItemPrivate::registerToDaemon() |
1482 |
+{ |
1483 |
+ //qDebug() << "Registering a client interface to the KStatusNotifierWatcher"; |
1484 |
+ if (!statusNotifierWatcher) { |
1485 |
+ statusNotifierWatcher = new org::kde::StatusNotifierWatcher(QString::fromLatin1(s_statusNotifierWatcherServiceName), QStringLiteral("/StatusNotifierWatcher"), |
1486 |
+ QDBusConnection::sessionBus()); |
1487 |
+ } |
1488 |
+ |
1489 |
+ if (statusNotifierWatcher->isValid()) { |
1490 |
+ // get protocol version in async way |
1491 |
+ QDBusMessage msg = QDBusMessage::createMethodCall(QString::fromLatin1(s_statusNotifierWatcherServiceName), |
1492 |
+ QStringLiteral("/StatusNotifierWatcher"), |
1493 |
+ QStringLiteral("org.freedesktop.DBus.Properties"), |
1494 |
+ QStringLiteral("Get")); |
1495 |
+ msg.setArguments(QVariantList{QStringLiteral("org.kde.StatusNotifierWatcher"), QStringLiteral("ProtocolVersion")}); |
1496 |
+ QDBusPendingCall async = QDBusConnection::sessionBus().asyncCall(msg); |
1497 |
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, q); |
1498 |
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, q, |
1499 |
+ [this, watcher] { |
1500 |
+ watcher->deleteLater(); |
1501 |
+ QDBusPendingReply<QVariant> reply = *watcher; |
1502 |
+ if (reply.isError()) { |
1503 |
+ qDebug() << "Failed to read protocol version of KStatusNotifierWatcher"; |
1504 |
+ setLegacySystemTrayEnabled(true); |
1505 |
+ } else { |
1506 |
+ bool ok = false; |
1507 |
+ const int protocolVersion = reply.value().toInt(&ok); |
1508 |
+ if (ok && protocolVersion == s_protocolVersion) { |
1509 |
+ statusNotifierWatcher->RegisterStatusNotifierItem(statusNotifierItemDBus->service()); |
1510 |
+ setLegacySystemTrayEnabled(false); |
1511 |
+ } else { |
1512 |
+ qDebug() << "KStatusNotifierWatcher has incorrect protocol version"; |
1513 |
+ setLegacySystemTrayEnabled(true); |
1514 |
+ } |
1515 |
+ } |
1516 |
+ } |
1517 |
+ ); |
1518 |
+ } else { |
1519 |
+ qDebug() << "KStatusNotifierWatcher not reachable"; |
1520 |
+ setLegacySystemTrayEnabled(true); |
1521 |
+ } |
1522 |
+} |
1523 |
+ |
1524 |
+void KStatusNotifierItemPrivate::serviceChange(const QString &name, const QString &oldOwner, const QString &newOwner) |
1525 |
+{ |
1526 |
+ Q_UNUSED(name) |
1527 |
+ if (newOwner.isEmpty()) { |
1528 |
+ //unregistered |
1529 |
+ qDebug() << "Connection to the KStatusNotifierWatcher lost"; |
1530 |
+ setLegacyMode(true); |
1531 |
+ delete statusNotifierWatcher; |
1532 |
+ statusNotifierWatcher = nullptr; |
1533 |
+ } else if (oldOwner.isEmpty()) { |
1534 |
+ //registered |
1535 |
+ setLegacyMode(false); |
1536 |
+ } |
1537 |
+} |
1538 |
+ |
1539 |
+void KStatusNotifierItemPrivate::setLegacyMode(bool legacy) |
1540 |
+{ |
1541 |
+ if (legacy) { |
1542 |
+ //unregistered |
1543 |
+ setLegacySystemTrayEnabled(true); |
1544 |
+ } else { |
1545 |
+ //registered |
1546 |
+ registerToDaemon(); |
1547 |
+ } |
1548 |
+} |
1549 |
+ |
1550 |
+void KStatusNotifierItemPrivate::legacyWheelEvent(int delta) |
1551 |
+{ |
1552 |
+ statusNotifierItemDBus->Scroll(-delta, QStringLiteral("vertical")); |
1553 |
+} |
1554 |
+ |
1555 |
+void KStatusNotifierItemPrivate::legacyActivated(QSystemTrayIcon::ActivationReason reason) |
1556 |
+{ |
1557 |
+ if (reason == QSystemTrayIcon::MiddleClick) { |
1558 |
+ emit q->secondaryActivateRequested(systemTrayIcon->geometry().topLeft()); |
1559 |
+ } else if (reason == QSystemTrayIcon::Trigger) { |
1560 |
+ q->activate(systemTrayIcon->geometry().topLeft()); |
1561 |
+ } |
1562 |
+} |
1563 |
+ |
1564 |
+void KStatusNotifierItemPrivate::setLegacySystemTrayEnabled(bool enabled) |
1565 |
+{ |
1566 |
+ if (enabled == (systemTrayIcon != nullptr)) { |
1567 |
+ // already in the correct state |
1568 |
+ return; |
1569 |
+ } |
1570 |
+ |
1571 |
+ if (enabled) { |
1572 |
+ bool isKde = !qEnvironmentVariableIsEmpty("KDE_FULL_SESSION") || qgetenv("XDG_CURRENT_DESKTOP") == "KDE"; |
1573 |
+ if (!systemTrayIcon && !isKde) { |
1574 |
+ if (!QSystemTrayIcon::isSystemTrayAvailable()) { |
1575 |
+ return; |
1576 |
+ } |
1577 |
+ systemTrayIcon = new KStatusNotifierLegacyIcon(associatedWidget); |
1578 |
+ syncLegacySystemTrayIcon(); |
1579 |
+ systemTrayIcon->setToolTip(toolTipTitle); |
1580 |
+ // silence the "icon not set" warning |
1581 |
+ systemTrayIcon->setIcon(QIcon(QPixmap(16, 16))); |
1582 |
+ systemTrayIcon->show(); |
1583 |
+ QObject::connect(systemTrayIcon, SIGNAL(wheel(int)), q, SLOT(legacyWheelEvent(int))); |
1584 |
+ QObject::connect(systemTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), q, SLOT(legacyActivated(QSystemTrayIcon::ActivationReason))); |
1585 |
+ } else if (isKde) { |
1586 |
+ // prevent infinite recursion if the KDE platform plugin is loaded |
1587 |
+ // but SNI is not available; see bug 350785 |
1588 |
+ qDebug() << "env says KDE is running but SNI unavailable -- check " |
1589 |
+ "KDE_FULL_SESSION and XDG_CURRENT_DESKTOP"; |
1590 |
+ return; |
1591 |
+ } |
1592 |
+ |
1593 |
+ if (menu) { |
1594 |
+ menu->setWindowFlags(Qt::Popup); |
1595 |
+ } |
1596 |
+ } else { |
1597 |
+ delete systemTrayIcon; |
1598 |
+ systemTrayIcon = nullptr; |
1599 |
+ |
1600 |
+ if (menu) { |
1601 |
+ menu->setWindowFlags(Qt::Window); |
1602 |
+ } |
1603 |
+ } |
1604 |
+ |
1605 |
+ if (menu) { |
1606 |
+ QMenu *m = menu; |
1607 |
+ menu = nullptr; |
1608 |
+ q->setContextMenu(m); |
1609 |
+ } |
1610 |
+} |
1611 |
+ |
1612 |
+void KStatusNotifierItemPrivate::syncLegacySystemTrayIcon() |
1613 |
+{ |
1614 |
+ // Hide the icon if passive |
1615 |
+ systemTrayIcon->setVisible(status != KStatusNotifierItem::Passive); |
1616 |
+ if (status == KStatusNotifierItem::NeedsAttention) { |
1617 |
+ { |
1618 |
+ if (!movieName.isNull()) { |
1619 |
+ if (!movie) { |
1620 |
+ movie = new QMovie(movieName); |
1621 |
+ } |
1622 |
+ systemTrayIcon->setMovie(movie); |
1623 |
+ } else if (!attentionIconName.isNull()) { |
1624 |
+ systemTrayIcon->setIcon(QIcon::fromTheme(attentionIconName)); |
1625 |
+ } else { |
1626 |
+ systemTrayIcon->setIcon(attentionIcon); |
1627 |
+ } |
1628 |
+ } |
1629 |
+ } else { |
1630 |
+ if (!iconName.isNull()) { |
1631 |
+ systemTrayIcon->setIcon(QIcon::fromTheme(iconName)); |
1632 |
+ } else { |
1633 |
+ systemTrayIcon->setIcon(icon); |
1634 |
+ } |
1635 |
+ } |
1636 |
+ |
1637 |
+ systemTrayIcon->setToolTip(toolTipTitle); |
1638 |
+} |
1639 |
+ |
1640 |
+void KStatusNotifierItemPrivate::contextMenuAboutToShow() |
1641 |
+{ |
1642 |
+ |
1643 |
+} |
1644 |
+ |
1645 |
+void KStatusNotifierItemPrivate::maybeQuit() |
1646 |
+{ |
1647 |
+ |
1648 |
+} |
1649 |
+ |
1650 |
+void KStatusNotifierItemPrivate::minimizeRestore() |
1651 |
+{ |
1652 |
+ q->activate(systemTrayIcon ? systemTrayIcon->geometry().topLeft() : QPoint(0, 0)); |
1653 |
+} |
1654 |
+ |
1655 |
+void KStatusNotifierItemPrivate::hideMenu() |
1656 |
+{ |
1657 |
+ menu->hide(); |
1658 |
+} |
1659 |
+ |
1660 |
+void KStatusNotifierItemPrivate::minimizeRestore(bool show) |
1661 |
+{ |
1662 |
+ if (show) { |
1663 |
+ auto state = (associatedWidget->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive; |
1664 |
+ associatedWidget->setWindowState(state); |
1665 |
+ associatedWidget->show(); |
1666 |
+ associatedWidget->raise(); |
1667 |
+ } else { |
1668 |
+ associatedWidget->hide(); |
1669 |
+ } |
1670 |
+} |
1671 |
+ |
1672 |
+KDbusImageStruct KStatusNotifierItemPrivate::imageToStruct(const QImage &image) |
1673 |
+{ |
1674 |
+ KDbusImageStruct icon; |
1675 |
+ icon.width = image.size().width(); |
1676 |
+ icon.height = image.size().height(); |
1677 |
+ if (image.format() == QImage::Format_ARGB32) { |
1678 |
+ icon.data = QByteArray((char *)image.bits(), QIMAGE_SIZE(image)); |
1679 |
+ } else { |
1680 |
+ QImage image32 = image.convertToFormat(QImage::Format_ARGB32); |
1681 |
+ icon.data = QByteArray((char *)image32.bits(), QIMAGE_SIZE(image32)); |
1682 |
+ } |
1683 |
+ |
1684 |
+ //swap to network byte order if we are little endian |
1685 |
+ if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { |
1686 |
+ quint32 *uintBuf = (quint32 *) icon.data.data(); |
1687 |
+ for (uint i = 0; i < icon.data.size() / sizeof(quint32); ++i) { |
1688 |
+ *uintBuf = qToBigEndian(*uintBuf); |
1689 |
+ ++uintBuf; |
1690 |
+ } |
1691 |
+ } |
1692 |
+ |
1693 |
+ return icon; |
1694 |
+} |
1695 |
+ |
1696 |
+KDbusImageVector KStatusNotifierItemPrivate::iconToVector(const QIcon &icon) |
1697 |
+{ |
1698 |
+ KDbusImageVector iconVector; |
1699 |
+ |
1700 |
+ QPixmap iconPixmap; |
1701 |
+ |
1702 |
+ //if an icon exactly that size wasn't found don't add it to the vector |
1703 |
+ const auto lstSizes = icon.availableSizes(); |
1704 |
+ for (QSize size : lstSizes) { |
1705 |
+ iconPixmap = icon.pixmap(size); |
1706 |
+ iconVector.append(imageToStruct(iconPixmap.toImage())); |
1707 |
+ } |
1708 |
+ return iconVector; |
1709 |
+} |
1710 |
+ |
1711 |
+#include "moc_kstatusnotifieritem.cpp" |
1712 |
+#include "moc_kstatusnotifieritemprivate_p.cpp" |
1713 |
diff --git a/src/gui/kstatusnotifier/kstatusnotifieritem.h b/src/gui/kstatusnotifier/kstatusnotifieritem.h |
1714 |
new file mode 100644 |
1715 |
index 00000000..99e490ca |
1716 |
--- /dev/null |
1717 |
+++ b/src/gui/kstatusnotifier/kstatusnotifieritem.h |
1718 |
@@ -0,0 +1,483 @@ |
1719 |
+/* This file is part of the KDE libraries |
1720 |
+ Copyright 2009 by Marco Martin <notmart@gmail.com> |
1721 |
+ |
1722 |
+ This library is free software; you can redistribute it and/or |
1723 |
+ modify it under the terms of the GNU Library General Public |
1724 |
+ License (LGPL) as published by the Free Software Foundation; |
1725 |
+ either version 2 of the License, or (at your option) any later |
1726 |
+ version. |
1727 |
+ |
1728 |
+ This library is distributed in the hope that it will be useful, |
1729 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
1730 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1731 |
+ Library General Public License for more details. |
1732 |
+ |
1733 |
+ You should have received a copy of the GNU Library General Public License |
1734 |
+ along with this library; see the file COPYING.LIB. If not, write to |
1735 |
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
1736 |
+ Boston, MA 02110-1301, USA. |
1737 |
+*/ |
1738 |
+ |
1739 |
+#ifndef KSTATUSNOTIFIERITEM_H |
1740 |
+#define KSTATUSNOTIFIERITEM_H |
1741 |
+ |
1742 |
+#include <QObject> |
1743 |
+#include <QString> |
1744 |
+#include <QPoint> |
1745 |
+ |
1746 |
+class QAction; |
1747 |
+class QMenu; |
1748 |
+ |
1749 |
+class KStatusNotifierItemPrivate; |
1750 |
+ |
1751 |
+/** |
1752 |
+ * @class KStatusNotifierItem kstatusnotifieritem.h KStatusNotifierItem |
1753 |
+ * |
1754 |
+ * \brief %KDE Status notifier Item protocol implementation |
1755 |
+ * |
1756 |
+ * This class implements the Status notifier Item D-Bus specification. |
1757 |
+ * It provides an icon similar to the classical systemtray icons, |
1758 |
+ * with some key differences: |
1759 |
+ * |
1760 |
+ * - the actual representation is done by the systemtray (or the app behaving |
1761 |
+ * like it) itself, not by this app. Since 4.5 this also includes the menu, |
1762 |
+ * which means you cannot use embed widgets in the menu. |
1763 |
+ * |
1764 |
+ * - there is communication between the systemtray and the icon owner, so the |
1765 |
+ * system tray can know if the application is in a normal or in a requesting |
1766 |
+ * attention state. |
1767 |
+ * |
1768 |
+ * - icons are divided in categories, so the systemtray can represent in a |
1769 |
+ * different way the icons from normal applications and for instance the ones |
1770 |
+ * about hardware status. |
1771 |
+ * |
1772 |
+ * Whenever possible you should prefer passing icon by name rather than by |
1773 |
+ * pixmap because: |
1774 |
+ * |
1775 |
+ * - it is much lighter on D-Bus (no need to pass all image pixels). |
1776 |
+ * |
1777 |
+ * - it makes it possible for the systemtray to load an icon of the appropriate |
1778 |
+ * size or to replace your icon with a systemtray specific icon which matches |
1779 |
+ * with the desktop theme. |
1780 |
+ * |
1781 |
+ * - some implementations of the system tray do not support passing icons by |
1782 |
+ * pixmap and will show a blank icon instead. |
1783 |
+ * |
1784 |
+ * @author Marco Martin <notmart@gmail.com> |
1785 |
+ * @since 4.4 |
1786 |
+ */ |
1787 |
+class KStatusNotifierItem : public QObject |
1788 |
+{ |
1789 |
+ Q_OBJECT |
1790 |
+ |
1791 |
+ Q_PROPERTY(ItemCategory category READ category WRITE setCategory) |
1792 |
+ Q_PROPERTY(QString title READ title WRITE setTitle) |
1793 |
+ Q_PROPERTY(ItemStatus status READ status WRITE setStatus) |
1794 |
+ Q_PROPERTY(QString iconName READ iconName WRITE setIconByName) |
1795 |
+ Q_PROPERTY(QString overlayIconName READ overlayIconName WRITE setOverlayIconByName) |
1796 |
+ Q_PROPERTY(QString attentionIconName READ attentionIconName WRITE setAttentionIconByName) |
1797 |
+ Q_PROPERTY(QString toolTipIconName READ toolTipIconName WRITE setToolTipIconByName) |
1798 |
+ Q_PROPERTY(QString toolTipTitle READ toolTipTitle WRITE setToolTipTitle) |
1799 |
+ Q_PROPERTY(QString toolTipSubTitle READ toolTipSubTitle WRITE setToolTipSubTitle) |
1800 |
+ |
1801 |
+ friend class KStatusNotifierItemDBus; |
1802 |
+ friend class KStatusNotifierItemPrivate; |
1803 |
+public: |
1804 |
+ /** |
1805 |
+ * All the possible status this icon can have, depending on the |
1806 |
+ * importance of the events that happens in the parent application |
1807 |
+ */ |
1808 |
+ enum ItemStatus { |
1809 |
+ /// Nothing is happening in the application, so showing this icon is not required |
1810 |
+ Passive = 1, |
1811 |
+ /// The application is doing something, or it is important that the |
1812 |
+ /// icon is always reachable from the user |
1813 |
+ Active = 2, |
1814 |
+ /// The application requests the attention of the user, for instance |
1815 |
+ /// battery running out or a new IM message was received |
1816 |
+ NeedsAttention = 3 |
1817 |
+ }; |
1818 |
+ Q_ENUM(ItemStatus) |
1819 |
+ |
1820 |
+ /** |
1821 |
+ * Different kinds of applications announce their type to the systemtray, |
1822 |
+ * so can be drawn in a different way or in a different place |
1823 |
+ */ |
1824 |
+ enum ItemCategory { |
1825 |
+ /// An icon for a normal application, can be seen as its taskbar entry |
1826 |
+ ApplicationStatus = 1, |
1827 |
+ /// This is a communication oriented application; this icon will be used |
1828 |
+ /// for things such as the notification of a new message |
1829 |
+ Communications = 2, |
1830 |
+ /// This is a system service, it can show itself in the system tray if |
1831 |
+ /// it requires interaction from the user or wants to inform him about |
1832 |
+ /// something |
1833 |
+ SystemServices = 3, |
1834 |
+ /// This application shows hardware status or a means to control it |
1835 |
+ Hardware = 4, |
1836 |
+ Reserved = 129 |
1837 |
+ }; |
1838 |
+ Q_ENUM(ItemCategory) |
1839 |
+ |
1840 |
+ /** |
1841 |
+ * Construct a new status notifier item |
1842 |
+ * |
1843 |
+ * @param parent the parent object for this object. If the object passed in as |
1844 |
+ * a parent is also a QWidget, it will be used as the main application window |
1845 |
+ * represented by this icon and will be shown/hidden when an activation is requested. |
1846 |
+ * @see associatedWidget |
1847 |
+ **/ |
1848 |
+ explicit KStatusNotifierItem(QObject *parent = nullptr); |
1849 |
+ |
1850 |
+ /** |
1851 |
+ * Construct a new status notifier item with a unique identifier. |
1852 |
+ * If your application has more than one status notifier item and the user |
1853 |
+ * should be able to manipulate them separately (e.g. mark them for hiding |
1854 |
+ * in a user interface), the id can be used to differentiate between them. |
1855 |
+ * |
1856 |
+ * The id should remain consistent even between application restarts. |
1857 |
+ * Status notifier items without ids default to the application's name for the id. |
1858 |
+ * This id may be used, for instance, by hosts displaying status notifier items to |
1859 |
+ * associate configuration information with this item in a way that can persist |
1860 |
+ * between sessions or application restarts. |
1861 |
+ * |
1862 |
+ * @param id the unique id for this icon |
1863 |
+ * @param parent the parent object for this object. If the object passed in as |
1864 |
+ * a parent is also a QWidget, it will be used as the main application window |
1865 |
+ * represented by this icon and will be shown/hidden when an activation is requested. |
1866 |
+ * @see associatedWidget |
1867 |
+ **/ |
1868 |
+ explicit KStatusNotifierItem(const QString &id, QObject *parent = nullptr); |
1869 |
+ |
1870 |
+ ~KStatusNotifierItem() override; |
1871 |
+ |
1872 |
+ /** |
1873 |
+ * @return The id which was specified in the constructor. This should be |
1874 |
+ * guaranteed to be consistent between application starts and |
1875 |
+ * untranslated, as host applications displaying items may use it for |
1876 |
+ * storing configuration related to this item. |
1877 |
+ */ |
1878 |
+ QString id() const; |
1879 |
+ |
1880 |
+ /** |
1881 |
+ * Sets the category for this icon, usually it's needed to call this function only once |
1882 |
+ * |
1883 |
+ * @param category the new category for this icon |
1884 |
+ */ |
1885 |
+ void setCategory(const ItemCategory category); |
1886 |
+ |
1887 |
+ /** |
1888 |
+ * @return the application category |
1889 |
+ */ |
1890 |
+ ItemCategory category() const; |
1891 |
+ |
1892 |
+ /** |
1893 |
+ * Sets a title for this icon |
1894 |
+ */ |
1895 |
+ void setTitle(const QString &title); |
1896 |
+ |
1897 |
+ /** |
1898 |
+ * @return the title of this icon |
1899 |
+ */ |
1900 |
+ QString title() const; |
1901 |
+ |
1902 |
+ /** |
1903 |
+ * Sets a new status for this icon. |
1904 |
+ */ |
1905 |
+ void setStatus(const ItemStatus status); |
1906 |
+ |
1907 |
+ /** |
1908 |
+ * @return the current application status |
1909 |
+ */ |
1910 |
+ ItemStatus status() const; |
1911 |
+ |
1912 |
+ //Main icon related functions |
1913 |
+ /** |
1914 |
+ * Sets a new main icon for the system tray |
1915 |
+ * |
1916 |
+ * @param name it must be a QIcon::fromTheme compatible name, this is |
1917 |
+ * the preferred way to set an icon |
1918 |
+ */ |
1919 |
+ void setIconByName(const QString &name); |
1920 |
+ |
1921 |
+ /** |
1922 |
+ * @return the name of the main icon to be displayed |
1923 |
+ * if image() is not empty this will always return an empty string |
1924 |
+ */ |
1925 |
+ QString iconName() const; |
1926 |
+ |
1927 |
+ /** |
1928 |
+ * Sets a new main icon for the system tray |
1929 |
+ * |
1930 |
+ * @param pixmap our icon, use setIcon(const QString) when possible |
1931 |
+ */ |
1932 |
+ void setIconByPixmap(const QIcon &icon); |
1933 |
+ |
1934 |
+ /** |
1935 |
+ * @return a pixmap of the icon |
1936 |
+ */ |
1937 |
+ QIcon iconPixmap() const; |
1938 |
+ |
1939 |
+ /** |
1940 |
+ * Sets an icon to be used as overlay for the main one |
1941 |
+ * @param icon name, if name is and empty QString() |
1942 |
+ * (and overlayIconPixmap() is empty too) the icon will be removed |
1943 |
+ */ |
1944 |
+ void setOverlayIconByName(const QString &name); |
1945 |
+ |
1946 |
+ /** |
1947 |
+ * @return the name of the icon to be used as overlay fr the main one |
1948 |
+ */ |
1949 |
+ QString overlayIconName() const; |
1950 |
+ |
1951 |
+ /** |
1952 |
+ * Sets an icon to be used as overlay for the main one |
1953 |
+ * setOverlayIconByPixmap(QIcon()) will remove the overlay when |
1954 |
+ * overlayIconName() is empty too. |
1955 |
+ * |
1956 |
+ * @param pixmap our overlay icon, use setOverlayIcon(const QString) when possible. |
1957 |
+ */ |
1958 |
+ void setOverlayIconByPixmap(const QIcon &icon); |
1959 |
+ |
1960 |
+ /** |
1961 |
+ * @return a pixmap of the icon |
1962 |
+ */ |
1963 |
+ QIcon overlayIconPixmap() const; |
1964 |
+ |
1965 |
+ //Requesting attention icon |
1966 |
+ |
1967 |
+ /** |
1968 |
+ * Sets a new icon that should be used when the application |
1969 |
+ * wants to request attention (usually the systemtray |
1970 |
+ * will blink between this icon and the main one) |
1971 |
+ * |
1972 |
+ * @param name QIcon::fromTheme compatible name of icon to use |
1973 |
+ */ |
1974 |
+ void setAttentionIconByName(const QString &name); |
1975 |
+ |
1976 |
+ /** |
1977 |
+ * @return the name of the icon to be displayed when the application |
1978 |
+ * is requesting the user's attention |
1979 |
+ * if attentionImage() is not empty this will always return an empty string |
1980 |
+ */ |
1981 |
+ QString attentionIconName() const; |
1982 |
+ |
1983 |
+ /** |
1984 |
+ * Sets the pixmap of the requesting attention icon. |
1985 |
+ * Use setAttentionIcon(const QString) instead when possible. |
1986 |
+ * |
1987 |
+ * @param icon QIcon to use for requesting attention. |
1988 |
+ */ |
1989 |
+ void setAttentionIconByPixmap(const QIcon &icon); |
1990 |
+ |
1991 |
+ /** |
1992 |
+ * @return a pixmap of the requesting attention icon |
1993 |
+ */ |
1994 |
+ QIcon attentionIconPixmap() const; |
1995 |
+ |
1996 |
+ /** |
1997 |
+ * Sets a movie as the requesting attention icon. |
1998 |
+ * This overrides anything set in setAttentionIcon() |
1999 |
+ */ |
2000 |
+ void setAttentionMovieByName(const QString &name); |
2001 |
+ |
2002 |
+ /** |
2003 |
+ * @return the name of the movie to be displayed when the application is |
2004 |
+ * requesting the user attention |
2005 |
+ */ |
2006 |
+ QString attentionMovieName() const; |
2007 |
+ |
2008 |
+ //ToolTip handling |
2009 |
+ /** |
2010 |
+ * Sets a new toolTip or this icon, a toolTip is composed of an icon, |
2011 |
+ * a title and a text, all fields are optional. |
2012 |
+ * |
2013 |
+ * @param iconName a QIcon::fromTheme compatible name for the tootip icon |
2014 |
+ * @param title tootip title |
2015 |
+ * @param subTitle subtitle for the toolTip |
2016 |
+ */ |
2017 |
+ void setToolTip(const QString &iconName, const QString &title, const QString &subTitle); |
2018 |
+ |
2019 |
+ /** |
2020 |
+ * Sets a new toolTip or this status notifier item. |
2021 |
+ * This is an overloaded member provided for convenience |
2022 |
+ */ |
2023 |
+ void setToolTip(const QIcon &icon, const QString &title, const QString &subTitle); |
2024 |
+ |
2025 |
+ /** |
2026 |
+ * Set a new icon for the toolTip |
2027 |
+ * |
2028 |
+ * @param name the name for the icon |
2029 |
+ */ |
2030 |
+ void setToolTipIconByName(const QString &name); |
2031 |
+ |
2032 |
+ /** |
2033 |
+ * @return the name of the toolTip icon |
2034 |
+ * if toolTipImage() is not empty this will always return an empty string |
2035 |
+ */ |
2036 |
+ QString toolTipIconName() const; |
2037 |
+ |
2038 |
+ /** |
2039 |
+ * Set a new icon for the toolTip. |
2040 |
+ * |
2041 |
+ * Use setToolTipIconByName(QString) if possible. |
2042 |
+ * @param pixmap representing the icon |
2043 |
+ */ |
2044 |
+ void setToolTipIconByPixmap(const QIcon &icon); |
2045 |
+ |
2046 |
+ /** |
2047 |
+ * @return a serialization of the toolTip icon data |
2048 |
+ */ |
2049 |
+ QIcon toolTipIconPixmap() const; |
2050 |
+ |
2051 |
+ /** |
2052 |
+ * Sets a new title for the toolTip |
2053 |
+ */ |
2054 |
+ void setToolTipTitle(const QString &title); |
2055 |
+ |
2056 |
+ /** |
2057 |
+ * @return the title of the main icon toolTip |
2058 |
+ */ |
2059 |
+ QString toolTipTitle() const; |
2060 |
+ |
2061 |
+ /** |
2062 |
+ * Sets a new subtitle for the toolTip |
2063 |
+ */ |
2064 |
+ void setToolTipSubTitle(const QString &subTitle); |
2065 |
+ |
2066 |
+ /** |
2067 |
+ * @return the subtitle of the main icon toolTip |
2068 |
+ */ |
2069 |
+ QString toolTipSubTitle() const; |
2070 |
+ |
2071 |
+ /** |
2072 |
+ * Sets a new context menu for this StatusNotifierItem. |
2073 |
+ * the menu will be shown with a contextMenu(int,int) |
2074 |
+ * call by the systemtray over D-Bus |
2075 |
+ * usually you don't need to call this unless you want to use |
2076 |
+ * a custom QMenu subclass as context menu. |
2077 |
+ * |
2078 |
+ * The KStatusNotifierItem instance takes ownership of the menu, |
2079 |
+ * and will delete it upon its destruction. |
2080 |
+ */ |
2081 |
+ void setContextMenu(QMenu *menu); |
2082 |
+ |
2083 |
+ /** |
2084 |
+ * Access the context menu associated to this status notifier item |
2085 |
+ */ |
2086 |
+ QMenu *contextMenu() const; |
2087 |
+ |
2088 |
+ /** |
2089 |
+ * Sets the main widget associated with this StatusNotifierItem |
2090 |
+ * |
2091 |
+ * If you pass contextMenu() as a parent then the menu will be displayed |
2092 |
+ * when the user activate the icon. In this case the activate() method will |
2093 |
+ * not be called and the activateRequested() signal will not be emitted |
2094 |
+ * |
2095 |
+ * @param parent the new main widget: must be a top level window, |
2096 |
+ * if it's not parent->window() will be used instead. |
2097 |
+ */ |
2098 |
+ void setAssociatedWidget(QWidget *parent); |
2099 |
+ |
2100 |
+ /** |
2101 |
+ * Access the main widget associated with this StatusNotifierItem |
2102 |
+ */ |
2103 |
+ QWidget *associatedWidget() const; |
2104 |
+ |
2105 |
+ /** |
2106 |
+ * All the actions present in the menu |
2107 |
+ */ |
2108 |
+ QList<QAction *> actionCollection() const; |
2109 |
+ |
2110 |
+ /** |
2111 |
+ * Adds an action to the actionCollection() |
2112 |
+ * |
2113 |
+ * @param name the name of the action |
2114 |
+ * @param action the action we want to add |
2115 |
+ */ |
2116 |
+ void addAction(const QString &name, QAction *action); |
2117 |
+ |
2118 |
+ /** |
2119 |
+ * Removes an action from the collection |
2120 |
+ * |
2121 |
+ * @param name the name of the action |
2122 |
+ */ |
2123 |
+ void removeAction(const QString &name); |
2124 |
+ |
2125 |
+ /** |
2126 |
+ * Retrieves an action from the action collection |
2127 |
+ * by the action name |
2128 |
+ * |
2129 |
+ * @param name the name of the action to retrieve |
2130 |
+ * @since 5.12 |
2131 |
+ */ |
2132 |
+ QAction *action(const QString &name) const; |
2133 |
+ |
2134 |
+ /** |
2135 |
+ * Shows the user a notification. If possible use KNotify instead |
2136 |
+ * |
2137 |
+ * @param title message title |
2138 |
+ * @param message the actual text shown to the user |
2139 |
+ * @param icon icon to be shown to the user |
2140 |
+ * @param timeout how much time will elaps before hiding the message |
2141 |
+ */ |
2142 |
+ void showMessage(const QString &title, const QString &message, const QString &icon, int timeout = 10000); |
2143 |
+ |
2144 |
+public Q_SLOTS: |
2145 |
+ |
2146 |
+ /** |
2147 |
+ * Shows the main widget and try to position it on top |
2148 |
+ * of the other windows, if the widget is already visible, hide it. |
2149 |
+ * |
2150 |
+ * @param pos if it's a valid position it represents the mouse coordinates when the event was triggered |
2151 |
+ */ |
2152 |
+ virtual void activate(const QPoint &pos = QPoint()); |
2153 |
+ |
2154 |
+Q_SIGNALS: |
2155 |
+ /** |
2156 |
+ * Inform the host application that the mouse wheel |
2157 |
+ * (or another mean of scrolling that the visualization provides) has been used |
2158 |
+ * |
2159 |
+ * @param delta the amount of scrolling, can be either positive or negative |
2160 |
+ * @param orientation direction of the scrolling, can be either horizontal or vertical |
2161 |
+ */ |
2162 |
+ void scrollRequested(int delta, Qt::Orientation orientation); |
2163 |
+ |
2164 |
+ /** |
2165 |
+ * Inform the host application that an activation has been requested, |
2166 |
+ * for instance left mouse click, but this is not guaranteed since |
2167 |
+ * it's dependent from the visualization |
2168 |
+ * @param active if it's true the application asked for the activation |
2169 |
+ * of the main window, if it's false it asked for hiding |
2170 |
+ * @param pos the position in the screen where the user clicked to |
2171 |
+ * trigger this signal, QPoint() if it's not the consequence of a mouse click. |
2172 |
+ */ |
2173 |
+ void activateRequested(bool active, const QPoint &pos); |
2174 |
+ |
2175 |
+ /** |
2176 |
+ * Alternate activate action, |
2177 |
+ * for instance right mouse click, but this is not guaranteed since |
2178 |
+ * it's dependent from the visualization |
2179 |
+ * |
2180 |
+ * @param pos the position in the screen where the user clicked to |
2181 |
+ * trigger this signal, QPoint() if it's not the consequence of a mouse click. |
2182 |
+ */ |
2183 |
+ void secondaryActivateRequested(const QPoint &pos); |
2184 |
+ |
2185 |
+protected: |
2186 |
+ bool eventFilter(QObject *watched, QEvent *event) override; |
2187 |
+ |
2188 |
+private: |
2189 |
+ KStatusNotifierItemPrivate *const d; |
2190 |
+ |
2191 |
+ Q_PRIVATE_SLOT(d, void serviceChange(const QString &name, |
2192 |
+ const QString &oldOwner, |
2193 |
+ const QString &newOwner)) |
2194 |
+ Q_PRIVATE_SLOT(d, void contextMenuAboutToShow()) |
2195 |
+ Q_PRIVATE_SLOT(d, void maybeQuit()) |
2196 |
+ Q_PRIVATE_SLOT(d, void minimizeRestore()) |
2197 |
+ Q_PRIVATE_SLOT(d, void legacyWheelEvent(int)) |
2198 |
+ Q_PRIVATE_SLOT(d, void legacyActivated(QSystemTrayIcon::ActivationReason)) |
2199 |
+}; |
2200 |
+ |
2201 |
+#endif |
2202 |
diff --git a/src/gui/kstatusnotifier/kstatusnotifieritemdbus_p.cpp b/src/gui/kstatusnotifier/kstatusnotifieritemdbus_p.cpp |
2203 |
new file mode 100644 |
2204 |
index 00000000..3f89c66c |
2205 |
--- /dev/null |
2206 |
+++ b/src/gui/kstatusnotifier/kstatusnotifieritemdbus_p.cpp |
2207 |
@@ -0,0 +1,292 @@ |
2208 |
+/* This file is part of the KDE libraries |
2209 |
+ Copyright 2009 by Marco Martin <notmart@gmail.com> |
2210 |
+ |
2211 |
+ This library is free software; you can redistribute it and/or |
2212 |
+ modify it under the terms of the GNU Library General Public |
2213 |
+ License (LGPL) as published by the Free Software Foundation; |
2214 |
+ either version 2 of the License, or (at your option) any later |
2215 |
+ version. |
2216 |
+ |
2217 |
+ This library is distributed in the hope that it will be useful, |
2218 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
2219 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2220 |
+ Library General Public License for more details. |
2221 |
+ |
2222 |
+ You should have received a copy of the GNU Library General Public License |
2223 |
+ along with this library; see the file COPYING.LIB. If not, write to |
2224 |
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
2225 |
+ Boston, MA 02110-1301, USA. |
2226 |
+*/ |
2227 |
+ |
2228 |
+#include "kstatusnotifieritemdbus_p.h" |
2229 |
+#include "kstatusnotifieritemprivate_p.h" |
2230 |
+#include "kstatusnotifieritem.h" |
2231 |
+ |
2232 |
+#include <QDBusConnection> |
2233 |
+#include <QMenu> |
2234 |
+ |
2235 |
+#include "statusnotifierwatcher_interface.h" |
2236 |
+#include "statusnotifieritemadaptor.h" |
2237 |
+ |
2238 |
+__inline int toInt(WId wid) |
2239 |
+{ |
2240 |
+ return (int)wid; |
2241 |
+} |
2242 |
+ |
2243 |
+// Marshall the ImageStruct data into a D-BUS argument |
2244 |
+const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageStruct &icon) |
2245 |
+{ |
2246 |
+ argument.beginStructure(); |
2247 |
+ argument << icon.width; |
2248 |
+ argument << icon.height; |
2249 |
+ argument << icon.data; |
2250 |
+ argument.endStructure(); |
2251 |
+ return argument; |
2252 |
+} |
2253 |
+ |
2254 |
+// Retrieve the ImageStruct data from the D-BUS argument |
2255 |
+const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageStruct &icon) |
2256 |
+{ |
2257 |
+ qint32 width; |
2258 |
+ qint32 height; |
2259 |
+ QByteArray data; |
2260 |
+ |
2261 |
+ argument.beginStructure(); |
2262 |
+ argument >> width; |
2263 |
+ argument >> height; |
2264 |
+ argument >> data; |
2265 |
+ argument.endStructure(); |
2266 |
+ |
2267 |
+ icon.width = width; |
2268 |
+ icon.height = height; |
2269 |
+ icon.data = data; |
2270 |
+ |
2271 |
+ return argument; |
2272 |
+} |
2273 |
+ |
2274 |
+// Marshall the ImageVector data into a D-BUS argument |
2275 |
+const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageVector &iconVector) |
2276 |
+{ |
2277 |
+ argument.beginArray(qMetaTypeId<KDbusImageStruct>()); |
2278 |
+ for (int i = 0; i < iconVector.size(); ++i) { |
2279 |
+ argument << iconVector[i]; |
2280 |
+ } |
2281 |
+ argument.endArray(); |
2282 |
+ return argument; |
2283 |
+} |
2284 |
+ |
2285 |
+// Retrieve the ImageVector data from the D-BUS argument |
2286 |
+const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageVector &iconVector) |
2287 |
+{ |
2288 |
+ argument.beginArray(); |
2289 |
+ iconVector.clear(); |
2290 |
+ |
2291 |
+ while (!argument.atEnd()) { |
2292 |
+ KDbusImageStruct element; |
2293 |
+ argument >> element; |
2294 |
+ iconVector.append(element); |
2295 |
+ } |
2296 |
+ |
2297 |
+ argument.endArray(); |
2298 |
+ |
2299 |
+ return argument; |
2300 |
+} |
2301 |
+ |
2302 |
+// Marshall the ToolTipStruct data into a D-BUS argument |
2303 |
+const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusToolTipStruct &toolTip) |
2304 |
+{ |
2305 |
+ argument.beginStructure(); |
2306 |
+ argument << toolTip.icon; |
2307 |
+ argument << toolTip.image; |
2308 |
+ argument << toolTip.title; |
2309 |
+ argument << toolTip.subTitle; |
2310 |
+ argument.endStructure(); |
2311 |
+ return argument; |
2312 |
+} |
2313 |
+ |
2314 |
+// Retrieve the ToolTipStruct data from the D-BUS argument |
2315 |
+const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusToolTipStruct &toolTip) |
2316 |
+{ |
2317 |
+ QString icon; |
2318 |
+ KDbusImageVector image; |
2319 |
+ QString title; |
2320 |
+ QString subTitle; |
2321 |
+ |
2322 |
+ argument.beginStructure(); |
2323 |
+ argument >> icon; |
2324 |
+ argument >> image; |
2325 |
+ argument >> title; |
2326 |
+ argument >> subTitle; |
2327 |
+ argument.endStructure(); |
2328 |
+ |
2329 |
+ toolTip.icon = icon; |
2330 |
+ toolTip.image = image; |
2331 |
+ toolTip.title = title; |
2332 |
+ toolTip.subTitle = subTitle; |
2333 |
+ |
2334 |
+ return argument; |
2335 |
+} |
2336 |
+ |
2337 |
+int KStatusNotifierItemDBus::s_serviceCount = 0; |
2338 |
+ |
2339 |
+KStatusNotifierItemDBus::KStatusNotifierItemDBus(KStatusNotifierItem *parent) |
2340 |
+ : QObject(parent), |
2341 |
+ m_statusNotifierItem(parent), |
2342 |
+ m_connId(QStringLiteral("org.kde.StatusNotifierItem-%1-%2") |
2343 |
+ .arg(QCoreApplication::applicationPid()) |
2344 |
+ .arg(++s_serviceCount)), |
2345 |
+ m_dbus(QDBusConnection(m_connId)) |
2346 |
+{ |
2347 |
+ m_dbus = QDBusConnection::connectToBus(QDBusConnection::SessionBus, m_connId); |
2348 |
+ |
2349 |
+ new StatusNotifierItemAdaptor(this); |
2350 |
+ m_dbus.registerObject(QStringLiteral("/StatusNotifierItem"), this); |
2351 |
+} |
2352 |
+ |
2353 |
+KStatusNotifierItemDBus::~KStatusNotifierItemDBus() |
2354 |
+{ |
2355 |
+ m_dbus.unregisterObject(QStringLiteral("/StatusNotifierItem")); |
2356 |
+ m_dbus.disconnectFromBus(m_connId); |
2357 |
+} |
2358 |
+ |
2359 |
+QDBusConnection KStatusNotifierItemDBus::dbusConnection() const |
2360 |
+{ |
2361 |
+ return m_dbus; |
2362 |
+} |
2363 |
+ |
2364 |
+QString KStatusNotifierItemDBus::service() const |
2365 |
+{ |
2366 |
+ return m_dbus.baseService(); |
2367 |
+} |
2368 |
+ |
2369 |
+bool KStatusNotifierItemDBus::ItemIsMenu() const |
2370 |
+{ |
2371 |
+ return (m_statusNotifierItem->d->associatedWidget == m_statusNotifierItem->d->menu); |
2372 |
+} |
2373 |
+ |
2374 |
+//DBUS slots |
2375 |
+ |
2376 |
+QString KStatusNotifierItemDBus::Category() const |
2377 |
+{ |
2378 |
+ return QLatin1String(m_statusNotifierItem->metaObject()->enumerator(m_statusNotifierItem->metaObject()->indexOfEnumerator("ItemCategory")).valueToKey(m_statusNotifierItem->category())); |
2379 |
+} |
2380 |
+ |
2381 |
+QString KStatusNotifierItemDBus::Title() const |
2382 |
+{ |
2383 |
+ return m_statusNotifierItem->title(); |
2384 |
+} |
2385 |
+ |
2386 |
+QString KStatusNotifierItemDBus::Id() const |
2387 |
+{ |
2388 |
+ return m_statusNotifierItem->id(); |
2389 |
+} |
2390 |
+ |
2391 |
+QString KStatusNotifierItemDBus::Status() const |
2392 |
+{ |
2393 |
+ return QLatin1String(m_statusNotifierItem->metaObject()->enumerator(m_statusNotifierItem->metaObject()->indexOfEnumerator("ItemStatus")).valueToKey(m_statusNotifierItem->status())); |
2394 |
+} |
2395 |
+ |
2396 |
+int KStatusNotifierItemDBus::WindowId() const |
2397 |
+{ |
2398 |
+ if (m_statusNotifierItem->d->associatedWidget && m_statusNotifierItem->d->associatedWidget != m_statusNotifierItem->d->menu) { |
2399 |
+ return toInt(m_statusNotifierItem->d->associatedWidget->winId()); |
2400 |
+ } else { |
2401 |
+ return 0; |
2402 |
+ } |
2403 |
+} |
2404 |
+ |
2405 |
+//Icon |
2406 |
+ |
2407 |
+QString KStatusNotifierItemDBus::IconName() const |
2408 |
+{ |
2409 |
+ return m_statusNotifierItem->iconName(); |
2410 |
+} |
2411 |
+ |
2412 |
+KDbusImageVector KStatusNotifierItemDBus::IconPixmap() const |
2413 |
+{ |
2414 |
+ return m_statusNotifierItem->d->serializedIcon; |
2415 |
+} |
2416 |
+ |
2417 |
+QString KStatusNotifierItemDBus::OverlayIconName() const |
2418 |
+{ |
2419 |
+ return m_statusNotifierItem->overlayIconName(); |
2420 |
+} |
2421 |
+ |
2422 |
+KDbusImageVector KStatusNotifierItemDBus::OverlayIconPixmap() const |
2423 |
+{ |
2424 |
+ return m_statusNotifierItem->d->serializedOverlayIcon; |
2425 |
+} |
2426 |
+ |
2427 |
+//Requesting attention icon and movie |
2428 |
+ |
2429 |
+QString KStatusNotifierItemDBus::AttentionIconName() const |
2430 |
+{ |
2431 |
+ return m_statusNotifierItem->attentionIconName(); |
2432 |
+} |
2433 |
+ |
2434 |
+KDbusImageVector KStatusNotifierItemDBus::AttentionIconPixmap() const |
2435 |
+{ |
2436 |
+ return m_statusNotifierItem->d->serializedAttentionIcon; |
2437 |
+} |
2438 |
+ |
2439 |
+QString KStatusNotifierItemDBus::AttentionMovieName() const |
2440 |
+{ |
2441 |
+ return m_statusNotifierItem->d->movieName; |
2442 |
+} |
2443 |
+ |
2444 |
+//ToolTip |
2445 |
+ |
2446 |
+KDbusToolTipStruct KStatusNotifierItemDBus::ToolTip() const |
2447 |
+{ |
2448 |
+ KDbusToolTipStruct toolTip; |
2449 |
+ toolTip.icon = m_statusNotifierItem->toolTipIconName(); |
2450 |
+ toolTip.image = m_statusNotifierItem->d->serializedToolTipIcon; |
2451 |
+ toolTip.title = m_statusNotifierItem->toolTipTitle(); |
2452 |
+ toolTip.subTitle = m_statusNotifierItem->toolTipSubTitle(); |
2453 |
+ |
2454 |
+ return toolTip; |
2455 |
+} |
2456 |
+ |
2457 |
+QString KStatusNotifierItemDBus::IconThemePath() const |
2458 |
+{ |
2459 |
+ return m_statusNotifierItem->d->iconThemePath; |
2460 |
+} |
2461 |
+ |
2462 |
+//Menu |
2463 |
+QDBusObjectPath KStatusNotifierItemDBus::Menu() const |
2464 |
+{ |
2465 |
+ return QDBusObjectPath(m_statusNotifierItem->d->menuObjectPath); |
2466 |
+} |
2467 |
+ |
2468 |
+//Interaction |
2469 |
+ |
2470 |
+void KStatusNotifierItemDBus::ContextMenu(int x, int y) |
2471 |
+{ |
2472 |
+ if (!m_statusNotifierItem->d->menu) { |
2473 |
+ return; |
2474 |
+ } |
2475 |
+ |
2476 |
+ //TODO: nicer placement, possible? |
2477 |
+ if (!m_statusNotifierItem->d->menu->isVisible()) { |
2478 |
+ m_statusNotifierItem->d->menu->popup(QPoint(x, y)); |
2479 |
+ } else { |
2480 |
+ m_statusNotifierItem->d->menu->hide(); |
2481 |
+ } |
2482 |
+} |
2483 |
+ |
2484 |
+void KStatusNotifierItemDBus::Activate(int x, int y) |
2485 |
+{ |
2486 |
+ m_statusNotifierItem->activate(QPoint(x, y)); |
2487 |
+} |
2488 |
+ |
2489 |
+void KStatusNotifierItemDBus::SecondaryActivate(int x, int y) |
2490 |
+{ |
2491 |
+ emit m_statusNotifierItem->secondaryActivateRequested(QPoint(x, y)); |
2492 |
+} |
2493 |
+ |
2494 |
+void KStatusNotifierItemDBus::Scroll(int delta, const QString &orientation) |
2495 |
+{ |
2496 |
+ Qt::Orientation dir = (orientation.toLower() == QLatin1String("horizontal") ? Qt::Horizontal : Qt::Vertical); |
2497 |
+ emit m_statusNotifierItem->scrollRequested(-delta, dir); |
2498 |
+} |
2499 |
+ |
2500 |
diff --git a/src/gui/kstatusnotifier/kstatusnotifieritemdbus_p.h b/src/gui/kstatusnotifier/kstatusnotifieritemdbus_p.h |
2501 |
new file mode 100644 |
2502 |
index 00000000..068aa2f3 |
2503 |
--- /dev/null |
2504 |
+++ b/src/gui/kstatusnotifier/kstatusnotifieritemdbus_p.h |
2505 |
@@ -0,0 +1,246 @@ |
2506 |
+/* This file is part of the KDE libraries |
2507 |
+ Copyright 2009 by Marco Martin <notmart@gmail.com> |
2508 |
+ |
2509 |
+ This library is free software; you can redistribute it and/or |
2510 |
+ modify it under the terms of the GNU Library General Public |
2511 |
+ License (LGPL) as published by the Free Software Foundation; |
2512 |
+ either version 2 of the License, or (at your option) any later |
2513 |
+ version. |
2514 |
+ |
2515 |
+ This library is distributed in the hope that it will be useful, |
2516 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
2517 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2518 |
+ Library General Public License for more details. |
2519 |
+ |
2520 |
+ You should have received a copy of the GNU Library General Public License |
2521 |
+ along with this library; see the file COPYING.LIB. If not, write to |
2522 |
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
2523 |
+ Boston, MA 02110-1301, USA. |
2524 |
+*/ |
2525 |
+ |
2526 |
+#ifndef KSTATUSNOTIFIERITEMDBUS_H |
2527 |
+#define KSTATUSNOTIFIERITEMDBUS_H |
2528 |
+ |
2529 |
+#include <QObject> |
2530 |
+#include <QString> |
2531 |
+#include <QDBusArgument> |
2532 |
+#include <QDBusConnection> |
2533 |
+#include <QDBusObjectPath> |
2534 |
+#include <QVector> |
2535 |
+ |
2536 |
+//Custom message type for DBus |
2537 |
+struct KDbusImageStruct { |
2538 |
+ int width; |
2539 |
+ int height; |
2540 |
+ QByteArray data; |
2541 |
+}; |
2542 |
+ |
2543 |
+typedef QVector<KDbusImageStruct> KDbusImageVector; |
2544 |
+ |
2545 |
+struct KDbusToolTipStruct { |
2546 |
+ QString icon; |
2547 |
+ KDbusImageVector image; |
2548 |
+ QString title; |
2549 |
+ QString subTitle; |
2550 |
+}; |
2551 |
+ |
2552 |
+class KStatusNotifierItem; |
2553 |
+ |
2554 |
+class KStatusNotifierItemDBus : public QObject |
2555 |
+{ |
2556 |
+ Q_OBJECT |
2557 |
+ |
2558 |
+ Q_PROPERTY(QString Category READ Category) |
2559 |
+ Q_PROPERTY(QString Id READ Id) |
2560 |
+ Q_PROPERTY(QString Title READ Title) |
2561 |
+ Q_PROPERTY(QString Status READ Status) |
2562 |
+ Q_PROPERTY(int WindowId READ WindowId) |
2563 |
+ Q_PROPERTY(bool ItemIsMenu READ ItemIsMenu) |
2564 |
+ Q_PROPERTY(QString IconName READ IconName) |
2565 |
+ Q_PROPERTY(KDbusImageVector IconPixmap READ IconPixmap) |
2566 |
+ Q_PROPERTY(QString OverlayIconName READ OverlayIconName) |
2567 |
+ Q_PROPERTY(KDbusImageVector OverlayIconPixmap READ OverlayIconPixmap) |
2568 |
+ Q_PROPERTY(QString AttentionIconName READ AttentionIconName) |
2569 |
+ Q_PROPERTY(KDbusImageVector AttentionIconPixmap READ AttentionIconPixmap) |
2570 |
+ Q_PROPERTY(QString AttentionMovieName READ AttentionMovieName) |
2571 |
+ Q_PROPERTY(KDbusToolTipStruct ToolTip READ ToolTip) |
2572 |
+ Q_PROPERTY(QString IconThemePath READ IconThemePath) |
2573 |
+ Q_PROPERTY(QDBusObjectPath Menu READ Menu) |
2574 |
+ |
2575 |
+ friend class KStatusNotifierItem; |
2576 |
+public: |
2577 |
+ explicit KStatusNotifierItemDBus(KStatusNotifierItem *parent); |
2578 |
+ ~KStatusNotifierItemDBus(); |
2579 |
+ |
2580 |
+ /** |
2581 |
+ * @return the dbus connection used by this object |
2582 |
+ */ |
2583 |
+ QDBusConnection dbusConnection() const; |
2584 |
+ |
2585 |
+ /** |
2586 |
+ * @return the service this object is registered on the bus under |
2587 |
+ */ |
2588 |
+ QString service() const; |
2589 |
+ |
2590 |
+ /** |
2591 |
+ * @return the category of the application associated to this item |
2592 |
+ * @see Category |
2593 |
+ */ |
2594 |
+ QString Category() const; |
2595 |
+ |
2596 |
+ /** |
2597 |
+ * @return the id of this item |
2598 |
+ */ |
2599 |
+ QString Id() const; |
2600 |
+ |
2601 |
+ /** |
2602 |
+ * @return the title of this item |
2603 |
+ */ |
2604 |
+ QString Title() const; |
2605 |
+ |
2606 |
+ /** |
2607 |
+ * @return The status of this item |
2608 |
+ * @see Status |
2609 |
+ */ |
2610 |
+ QString Status() const; |
2611 |
+ |
2612 |
+ /** |
2613 |
+ * @return The id of the main window of the application that controls the item |
2614 |
+ */ |
2615 |
+ int WindowId() const; |
2616 |
+ |
2617 |
+ /** |
2618 |
+ * @return The item only support the context menu, the visualization should prefer sending ContextMenu() instead of Activate() |
2619 |
+ */ |
2620 |
+ bool ItemIsMenu() const; |
2621 |
+ |
2622 |
+ /** |
2623 |
+ * @return the name of the main icon to be displayed |
2624 |
+ * if image() is not empty this will always return an empty string |
2625 |
+ */ |
2626 |
+ QString IconName() const; |
2627 |
+ |
2628 |
+ /** |
2629 |
+ * @return a serialization of the icon data |
2630 |
+ */ |
2631 |
+ KDbusImageVector IconPixmap() const; |
2632 |
+ |
2633 |
+ /** |
2634 |
+ * @return the name of the overlay of the main icon to be displayed |
2635 |
+ * if image() is not empty this will always return an empty string |
2636 |
+ */ |
2637 |
+ QString OverlayIconName() const; |
2638 |
+ |
2639 |
+ /** |
2640 |
+ * @return a serialization of the icon data |
2641 |
+ */ |
2642 |
+ KDbusImageVector OverlayIconPixmap() const; |
2643 |
+ |
2644 |
+ /** |
2645 |
+ * @return the name of the icon to be displayed when the application |
2646 |
+ * is requesting the user's attention |
2647 |
+ * if attentionImage() is not empty this will always return an empty string |
2648 |
+ */ |
2649 |
+ QString AttentionIconName() const; |
2650 |
+ |
2651 |
+ /** |
2652 |
+ * @return a serialization of the requesting attention icon data |
2653 |
+ */ |
2654 |
+ KDbusImageVector AttentionIconPixmap() const; |
2655 |
+ |
2656 |
+ /** |
2657 |
+ * @return the name of the attention movie |
2658 |
+ */ |
2659 |
+ QString AttentionMovieName() const; |
2660 |
+ |
2661 |
+ /** |
2662 |
+ * all the data needed for a tooltip |
2663 |
+ */ |
2664 |
+ KDbusToolTipStruct ToolTip() const; |
2665 |
+ |
2666 |
+ /** |
2667 |
+ * @return path to extra icon theme, to load application specific icons |
2668 |
+ */ |
2669 |
+ QString IconThemePath() const; |
2670 |
+ |
2671 |
+ /** |
2672 |
+ * @return object path to the dbusmenu object |
2673 |
+ */ |
2674 |
+ QDBusObjectPath Menu() const; |
2675 |
+ |
2676 |
+public Q_SLOTS: |
2677 |
+ //interaction |
2678 |
+ /** |
2679 |
+ * Shows the context menu associated to this item |
2680 |
+ * at the desired screen position |
2681 |
+ */ |
2682 |
+ void ContextMenu(int x, int y); |
2683 |
+ |
2684 |
+ /** |
2685 |
+ * Shows the main widget and try to position it on top |
2686 |
+ * of the other windows, if the widget is already visible, hide it. |
2687 |
+ */ |
2688 |
+ void Activate(int x, int y); |
2689 |
+ |
2690 |
+ /** |
2691 |
+ * The user activated the item in an alternate way (for instance with middle mouse button, this depends from the systray implementation) |
2692 |
+ */ |
2693 |
+ void SecondaryActivate(int x, int y); |
2694 |
+ |
2695 |
+ /** |
2696 |
+ * Inform this item that the mouse wheel was used on its representation |
2697 |
+ */ |
2698 |
+ void Scroll(int delta, const QString &orientation); |
2699 |
+ |
2700 |
+Q_SIGNALS: |
2701 |
+ /** |
2702 |
+ * Inform the systemtray that the own main icon has been changed, |
2703 |
+ * so should be reloaded |
2704 |
+ */ |
2705 |
+ void NewIcon(); |
2706 |
+ |
2707 |
+ /** |
2708 |
+ * Inform the systemtray that there is a new icon to be used as overlay |
2709 |
+ */ |
2710 |
+ void NewOverlayIcon(); |
2711 |
+ |
2712 |
+ /** |
2713 |
+ * Inform the systemtray that the requesting attention icon |
2714 |
+ * has been changed, so should be reloaded |
2715 |
+ */ |
2716 |
+ void NewAttentionIcon(); |
2717 |
+ |
2718 |
+ /** |
2719 |
+ * Inform the systemtray that something in the tooltip has been changed |
2720 |
+ */ |
2721 |
+ void NewToolTip(); |
2722 |
+ |
2723 |
+ /** |
2724 |
+ * Signal the new status when it has been changed |
2725 |
+ * @see Status |
2726 |
+ */ |
2727 |
+ void NewStatus(const QString &status); |
2728 |
+ |
2729 |
+private: |
2730 |
+ KStatusNotifierItem *m_statusNotifierItem; |
2731 |
+ QString m_connId; |
2732 |
+ QDBusConnection m_dbus; |
2733 |
+ static int s_serviceCount; |
2734 |
+}; |
2735 |
+ |
2736 |
+const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageStruct &icon); |
2737 |
+const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageStruct &icon); |
2738 |
+ |
2739 |
+Q_DECLARE_METATYPE(KDbusImageStruct) |
2740 |
+ |
2741 |
+const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageVector &iconVector); |
2742 |
+const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageVector &iconVector); |
2743 |
+ |
2744 |
+Q_DECLARE_METATYPE(KDbusImageVector) |
2745 |
+ |
2746 |
+const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusToolTipStruct &toolTip); |
2747 |
+const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusToolTipStruct &toolTip); |
2748 |
+ |
2749 |
+Q_DECLARE_METATYPE(KDbusToolTipStruct) |
2750 |
+ |
2751 |
+#endif |
2752 |
diff --git a/src/gui/kstatusnotifier/kstatusnotifieritemprivate_p.h b/src/gui/kstatusnotifier/kstatusnotifieritemprivate_p.h |
2753 |
new file mode 100644 |
2754 |
index 00000000..c3275aeb |
2755 |
--- /dev/null |
2756 |
+++ b/src/gui/kstatusnotifier/kstatusnotifieritemprivate_p.h |
2757 |
@@ -0,0 +1,171 @@ |
2758 |
+/* This file is part of the KDE libraries |
2759 |
+ Copyright 2009 by Marco Martin <notmart@gmail.com> |
2760 |
+ |
2761 |
+ This library is free software; you can redistribute it and/or |
2762 |
+ modify it under the terms of the GNU Library General Public |
2763 |
+ License (LGPL) as published by the Free Software Foundation; |
2764 |
+ either version 2 of the License, or (at your option) any later |
2765 |
+ version. |
2766 |
+ |
2767 |
+ This library is distributed in the hope that it will be useful, |
2768 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
2769 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2770 |
+ Library General Public License for more details. |
2771 |
+ |
2772 |
+ You should have received a copy of the GNU Library General Public License |
2773 |
+ along with this library; see the file COPYING.LIB. If not, write to |
2774 |
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
2775 |
+ Boston, MA 02110-1301, USA. |
2776 |
+*/ |
2777 |
+ |
2778 |
+#ifndef KSTATUSNOTIFIERITEMPRIVATE_H |
2779 |
+#define KSTATUSNOTIFIERITEMPRIVATE_H |
2780 |
+ |
2781 |
+#include <QObject> |
2782 |
+#include <QString> |
2783 |
+#include <QMovie> |
2784 |
+#include <QSystemTrayIcon> |
2785 |
+#include <QWheelEvent> |
2786 |
+ |
2787 |
+#include "kstatusnotifieritem.h" |
2788 |
+#include "kstatusnotifieritemdbus_p.h" |
2789 |
+ |
2790 |
+#include "statusnotifierwatcher_interface.h" |
2791 |
+#include "notifications_interface.h" |
2792 |
+ |
2793 |
+class KSystemTrayIcon; |
2794 |
+class QMenu; |
2795 |
+class QAction; |
2796 |
+ |
2797 |
+// this class is needed because we can't just put an event filter on it: |
2798 |
+// the events that are passed to QSystemTrayIcon are done so in a way that |
2799 |
+// bypasses the usual event filtering mechanisms *sigh* |
2800 |
+class KStatusNotifierLegacyIcon : public QSystemTrayIcon |
2801 |
+{ |
2802 |
+ Q_OBJECT |
2803 |
+ |
2804 |
+public: |
2805 |
+ KStatusNotifierLegacyIcon(QObject *parent) |
2806 |
+ : QSystemTrayIcon(parent) |
2807 |
+ { |
2808 |
+ } |
2809 |
+ |
2810 |
+ bool event(QEvent *e) override |
2811 |
+ { |
2812 |
+ if (e->type() == QEvent::Wheel) { |
2813 |
+ QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(e); |
2814 |
+ emit wheel(wheelEvent->angleDelta().y()); |
2815 |
+ } |
2816 |
+ |
2817 |
+ return false; |
2818 |
+ } |
2819 |
+ |
2820 |
+ void setMovie(QMovie *movie) |
2821 |
+ { |
2822 |
+ if (m_movie.data() == movie) { |
2823 |
+ return; |
2824 |
+ } |
2825 |
+ |
2826 |
+ delete m_movie.data(); |
2827 |
+ m_movie = movie; |
2828 |
+ |
2829 |
+ if (!movie) { |
2830 |
+ return; |
2831 |
+ } |
2832 |
+ |
2833 |
+ movie->setParent(this); |
2834 |
+ movie->setCacheMode(QMovie::CacheAll); |
2835 |
+ connect(movie, &QMovie::frameChanged, this, &KStatusNotifierLegacyIcon::slotNewFrame); |
2836 |
+ } |
2837 |
+ |
2838 |
+ void setIconWithMask(QIcon &icon, bool isMask) |
2839 |
+ { |
2840 |
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) |
2841 |
+ icon.setIsMask(isMask); |
2842 |
+#endif |
2843 |
+ QSystemTrayIcon::setIcon(icon); |
2844 |
+ } |
2845 |
+ |
2846 |
+Q_SIGNALS: |
2847 |
+ void wheel(int); |
2848 |
+ |
2849 |
+private Q_SLOTS: |
2850 |
+ void slotNewFrame() |
2851 |
+ { |
2852 |
+ if (m_movie) { |
2853 |
+ setIcon(QIcon(m_movie.data()->currentPixmap())); |
2854 |
+ } |
2855 |
+ } |
2856 |
+ |
2857 |
+private: |
2858 |
+ QPointer<QMovie> m_movie; |
2859 |
+}; |
2860 |
+ |
2861 |
+class KStatusNotifierItemPrivate |
2862 |
+{ |
2863 |
+public: |
2864 |
+ KStatusNotifierItemPrivate(KStatusNotifierItem *item); |
2865 |
+ |
2866 |
+ void init(const QString &extraId); |
2867 |
+ void registerToDaemon(); |
2868 |
+ void serviceChange(const QString &name, const QString &oldOwner, const QString &newOwner); |
2869 |
+ void setLegacySystemTrayEnabled(bool enabled); |
2870 |
+ void syncLegacySystemTrayIcon(); |
2871 |
+ void contextMenuAboutToShow(); |
2872 |
+ void maybeQuit(); |
2873 |
+ void minimizeRestore(); |
2874 |
+ void minimizeRestore(bool show); |
2875 |
+ void hideMenu(); |
2876 |
+ void setLegacyMode(bool legacy); |
2877 |
+ void checkForRegisteredHosts(); |
2878 |
+ void legacyWheelEvent(int delta); |
2879 |
+ void legacyActivated(QSystemTrayIcon::ActivationReason reason); |
2880 |
+ |
2881 |
+ KDbusImageStruct imageToStruct(const QImage &image); |
2882 |
+ KDbusImageVector iconToVector(const QIcon &icon); |
2883 |
+ bool checkVisibility(QPoint pos, bool perform = true); |
2884 |
+ |
2885 |
+ static const int s_protocolVersion; |
2886 |
+ |
2887 |
+ KStatusNotifierItem *q; |
2888 |
+ |
2889 |
+ KStatusNotifierItem::ItemCategory category; |
2890 |
+ QString id; |
2891 |
+ QString title; |
2892 |
+ KStatusNotifierItem::ItemStatus status; |
2893 |
+ |
2894 |
+ QString iconName; |
2895 |
+ KDbusImageVector serializedIcon; |
2896 |
+ QIcon icon; |
2897 |
+ |
2898 |
+ QString overlayIconName; |
2899 |
+ KDbusImageVector serializedOverlayIcon; |
2900 |
+ QIcon overlayIcon; |
2901 |
+ |
2902 |
+ QString attentionIconName; |
2903 |
+ QIcon attentionIcon; |
2904 |
+ KDbusImageVector serializedAttentionIcon; |
2905 |
+ QString movieName; |
2906 |
+ QPointer<QMovie> movie; |
2907 |
+ |
2908 |
+ QString toolTipIconName; |
2909 |
+ KDbusImageVector serializedToolTipIcon; |
2910 |
+ QIcon toolTipIcon; |
2911 |
+ QString toolTipTitle; |
2912 |
+ QString toolTipSubTitle; |
2913 |
+ QString iconThemePath; |
2914 |
+ QString menuObjectPath; |
2915 |
+ |
2916 |
+ QMenu *menu; |
2917 |
+ QHash<QString, QAction *> actionCollection; |
2918 |
+ QWidget *associatedWidget; |
2919 |
+ QPoint associatedWidgetPos; |
2920 |
+ QAction *titleAction; |
2921 |
+ org::kde::StatusNotifierWatcher *statusNotifierWatcher; |
2922 |
+ org::freedesktop::Notifications *notificationsClient; |
2923 |
+ |
2924 |
+ KStatusNotifierLegacyIcon *systemTrayIcon; |
2925 |
+ KStatusNotifierItemDBus *statusNotifierItemDBus; |
2926 |
+}; |
2927 |
+ |
2928 |
+#endif |
2929 |
diff --git a/src/gui/kstatusnotifier/org.freedesktop.Notifications.xml b/src/gui/kstatusnotifier/org.freedesktop.Notifications.xml |
2930 |
new file mode 100644 |
2931 |
index 00000000..62345f2b |
2932 |
--- /dev/null |
2933 |
+++ b/src/gui/kstatusnotifier/org.freedesktop.Notifications.xml |
2934 |
@@ -0,0 +1,37 @@ |
2935 |
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
2936 |
+<node> |
2937 |
+ <interface name="org.freedesktop.Notifications"> |
2938 |
+ <signal name="NotificationClosed"> |
2939 |
+ <arg name="id" type="u" direction="out"/> |
2940 |
+ <arg name="reason" type="u" direction="out"/> |
2941 |
+ </signal> |
2942 |
+ <signal name="ActionInvoked"> |
2943 |
+ <arg name="id" type="u" direction="out"/> |
2944 |
+ <arg name="action_key" type="s" direction="out"/> |
2945 |
+ </signal> |
2946 |
+ <method name="Notify"> |
2947 |
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In6" value="QVariantMap"/> |
2948 |
+ <arg type="u" direction="out"/> |
2949 |
+ <arg name="app_name" type="s" direction="in"/> |
2950 |
+ <arg name="replaces_id" type="u" direction="in"/> |
2951 |
+ <arg name="app_icon" type="s" direction="in"/> |
2952 |
+ <arg name="summary" type="s" direction="in"/> |
2953 |
+ <arg name="body" type="s" direction="in"/> |
2954 |
+ <arg name="actions" type="as" direction="in"/> |
2955 |
+ <arg name="hints" type="a{sv}" direction="in"/> |
2956 |
+ <arg name="timeout" type="i" direction="in"/> |
2957 |
+ </method> |
2958 |
+ <method name="CloseNotification"> |
2959 |
+ <arg name="id" type="u" direction="in"/> |
2960 |
+ </method> |
2961 |
+ <method name="GetCapabilities"> |
2962 |
+ <arg type="as" name="caps" direction="out"/> |
2963 |
+ </method> |
2964 |
+ <method name="GetServerInformation"> |
2965 |
+ <arg type="s" name="name" direction="out"/> |
2966 |
+ <arg type="s" name="vendor" direction="out"/> |
2967 |
+ <arg type="s" name="version" direction="out"/> |
2968 |
+ <arg type="s" name="spec_version" direction="out"/> |
2969 |
+ </method> |
2970 |
+ </interface> |
2971 |
+</node> |
2972 |
diff --git a/src/gui/kstatusnotifier/org.kde.StatusNotifierItem.xml b/src/gui/kstatusnotifier/org.kde.StatusNotifierItem.xml |
2973 |
new file mode 100644 |
2974 |
index 00000000..7866a746 |
2975 |
--- /dev/null |
2976 |
+++ b/src/gui/kstatusnotifier/org.kde.StatusNotifierItem.xml |
2977 |
@@ -0,0 +1,96 @@ |
2978 |
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
2979 |
+<node> |
2980 |
+ <interface name="org.kde.StatusNotifierItem"> |
2981 |
+ |
2982 |
+ <property name="Category" type="s" access="read"/> |
2983 |
+ <property name="Id" type="s" access="read"/> |
2984 |
+ <property name="Title" type="s" access="read"/> |
2985 |
+ <property name="Status" type="s" access="read"/> |
2986 |
+ <property name="WindowId" type="i" access="read"/> |
2987 |
+ |
2988 |
+ <!-- An additional path to add to the theme search path to find the icons specified above. --> |
2989 |
+ <property name="IconThemePath" type="s" access="read"/> |
2990 |
+ <property name="Menu" type="o" access="read"/> |
2991 |
+ <property name="ItemIsMenu" type="b" access="read"/> |
2992 |
+ |
2993 |
+ |
2994 |
+ <!-- main icon --> |
2995 |
+ <!-- names are preferred over pixmaps --> |
2996 |
+ <property name="IconName" type="s" access="read"/> |
2997 |
+ |
2998 |
+ <!--struct containing width, height and image data--> |
2999 |
+ <property name="IconPixmap" type="a(iiay)" access="read"> |
3000 |
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/> |
3001 |
+ </property> |
3002 |
+ |
3003 |
+ <property name="OverlayIconName" type="s" access="read"/> |
3004 |
+ |
3005 |
+ <property name="OverlayIconPixmap" type="a(iiay)" access="read"> |
3006 |
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/> |
3007 |
+ </property> |
3008 |
+ |
3009 |
+ |
3010 |
+ <!-- Requesting attention icon --> |
3011 |
+ <property name="AttentionIconName" type="s" access="read"/> |
3012 |
+ |
3013 |
+ <!--same definition as image--> |
3014 |
+ <property name="AttentionIconPixmap" type="a(iiay)" access="read"> |
3015 |
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/> |
3016 |
+ </property> |
3017 |
+ |
3018 |
+ <property name="AttentionMovieName" type="s" access="read"/> |
3019 |
+ |
3020 |
+ |
3021 |
+ |
3022 |
+ <!-- tooltip data --> |
3023 |
+ |
3024 |
+ <!--(iiay) is an image--> |
3025 |
+ <property name="ToolTip" type="(sa(iiay)ss)" access="read"> |
3026 |
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusToolTipStruct"/> |
3027 |
+ </property> |
3028 |
+ |
3029 |
+ |
3030 |
+ <!-- interaction: the systemtray wants the application to do something --> |
3031 |
+ <method name="ContextMenu"> |
3032 |
+ <!-- we're passing the coordinates of the icon, so the app knows where to put the popup window --> |
3033 |
+ <arg name="x" type="i" direction="in"/> |
3034 |
+ <arg name="y" type="i" direction="in"/> |
3035 |
+ </method> |
3036 |
+ |
3037 |
+ <method name="Activate"> |
3038 |
+ <arg name="x" type="i" direction="in"/> |
3039 |
+ <arg name="y" type="i" direction="in"/> |
3040 |
+ </method> |
3041 |
+ |
3042 |
+ <method name="SecondaryActivate"> |
3043 |
+ <arg name="x" type="i" direction="in"/> |
3044 |
+ <arg name="y" type="i" direction="in"/> |
3045 |
+ </method> |
3046 |
+ |
3047 |
+ <method name="Scroll"> |
3048 |
+ <arg name="delta" type="i" direction="in"/> |
3049 |
+ <arg name="orientation" type="s" direction="in"/> |
3050 |
+ </method> |
3051 |
+ |
3052 |
+ <!-- Signals: the client wants to change something in the status--> |
3053 |
+ <signal name="NewTitle"> |
3054 |
+ </signal> |
3055 |
+ |
3056 |
+ <signal name="NewIcon"> |
3057 |
+ </signal> |
3058 |
+ |
3059 |
+ <signal name="NewAttentionIcon"> |
3060 |
+ </signal> |
3061 |
+ |
3062 |
+ <signal name="NewOverlayIcon"> |
3063 |
+ </signal> |
3064 |
+ |
3065 |
+ <signal name="NewToolTip"> |
3066 |
+ </signal> |
3067 |
+ |
3068 |
+ <signal name="NewStatus"> |
3069 |
+ <arg name="status" type="s"/> |
3070 |
+ </signal> |
3071 |
+ |
3072 |
+ </interface> |
3073 |
+</node> |
3074 |
diff --git a/src/gui/kstatusnotifier/org.kde.StatusNotifierWatcher.xml b/src/gui/kstatusnotifier/org.kde.StatusNotifierWatcher.xml |
3075 |
new file mode 100644 |
3076 |
index 00000000..2eb1a7a0 |
3077 |
--- /dev/null |
3078 |
+++ b/src/gui/kstatusnotifier/org.kde.StatusNotifierWatcher.xml |
3079 |
@@ -0,0 +1,42 @@ |
3080 |
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
3081 |
+<node> |
3082 |
+ <interface name="org.kde.StatusNotifierWatcher"> |
3083 |
+ |
3084 |
+ <!-- methods --> |
3085 |
+ <method name="RegisterStatusNotifierItem"> |
3086 |
+ <arg name="service" type="s" direction="in"/> |
3087 |
+ </method> |
3088 |
+ |
3089 |
+ <method name="RegisterStatusNotifierHost"> |
3090 |
+ <arg name="service" type="s" direction="in"/> |
3091 |
+ </method> |
3092 |
+ |
3093 |
+ |
3094 |
+ <!-- properties --> |
3095 |
+ |
3096 |
+ <property name="RegisteredStatusNotifierItems" type="as" access="read"> |
3097 |
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QStringList"/> |
3098 |
+ </property> |
3099 |
+ |
3100 |
+ <property name="IsStatusNotifierHostRegistered" type="b" access="read"/> |
3101 |
+ |
3102 |
+ <property name="ProtocolVersion" type="i" access="read"/> |
3103 |
+ |
3104 |
+ |
3105 |
+ <!-- signals --> |
3106 |
+ |
3107 |
+ <signal name="StatusNotifierItemRegistered"> |
3108 |
+ <arg type="s"/> |
3109 |
+ </signal> |
3110 |
+ |
3111 |
+ <signal name="StatusNotifierItemUnregistered"> |
3112 |
+ <arg type="s"/> |
3113 |
+ </signal> |
3114 |
+ |
3115 |
+ <signal name="StatusNotifierHostRegistered"> |
3116 |
+ </signal> |
3117 |
+ |
3118 |
+ <signal name="StatusNotifierHostUnregistered"> |
3119 |
+ </signal> |
3120 |
+ </interface> |
3121 |
+</node> |
3122 |
diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp |
3123 |
index d16f9877..0da7c8e7 100644 |
3124 |
--- a/src/gui/mainwindow.cpp |
3125 |
+++ b/src/gui/mainwindow.cpp |
3126 |
@@ -31,36 +31,6 @@ int MainWindow::signalHandlerFd[2] = {0, 0}; |
3127 |
|
3128 |
MainWindow* MainWindow::mainWindow = 0; |
3129 |
|
3130 |
-#ifdef USE_LIBAPPINDICATOR |
3131 |
-extern "C" { |
3132 |
- void quitIndicator(GtkMenu* menu, gpointer data) { |
3133 |
- Q_UNUSED(menu); |
3134 |
- MainWindow* window = static_cast<MainWindow*>(data); |
3135 |
- window->quitApp(); |
3136 |
- } |
3137 |
- |
3138 |
- void restoreIndicator(GtkMenu* menu, gpointer data) { |
3139 |
- Q_UNUSED(menu); |
3140 |
- MainWindow* window = static_cast<MainWindow*>(data); |
3141 |
- window->showWindow(); |
3142 |
- } |
3143 |
- |
3144 |
- void indicatorScroll(AppIndicator* indicator, guint steps, GdkScrollDirection direction, gpointer data) { |
3145 |
- MainWindow* window = static_cast<MainWindow*>(data); |
3146 |
- switch(direction) { |
3147 |
- case GDK_SCROLL_UP: |
3148 |
- emit window->trayIconScrolled(true); |
3149 |
- break; |
3150 |
- case GDK_SCROLL_DOWN: |
3151 |
- emit window->trayIconScrolled(false); |
3152 |
- break; |
3153 |
- default: |
3154 |
- break; |
3155 |
- } |
3156 |
- } |
3157 |
-} |
3158 |
-#endif |
3159 |
- |
3160 |
#if defined(Q_OS_MACOS) && !defined(OS_MAC_LEGACY) |
3161 |
bool is_catalina_or_higher(){ |
3162 |
// Get macOS version. If Catalina or higher, start the daemon agent as the current user to request for HID permission. |
3163 |
@@ -161,60 +131,15 @@ MainWindow::MainWindow(QWidget *parent) : |
3164 |
restoreAction = new QAction(tr("Restore"), this); |
3165 |
closeAction = new QAction(tr("Quit"), this); |
3166 |
changeTrayIconAction = new QAction(tr("Monochrome Tray Icon"), this); |
3167 |
- |
3168 |
-#ifdef USE_LIBAPPINDICATOR |
3169 |
- QProcessEnvironment procEnv = QProcessEnvironment::systemEnvironment(); |
3170 |
- |
3171 |
- QString desktop = procEnv.value("XDG_CURRENT_DESKTOP", QString("")).toLower(); |
3172 |
- QString qpaTheme = procEnv.value("QT_QPA_PLATFORMTHEME", QString("")).toLower(); |
3173 |
- QString ckbnextAppindicator = procEnv.value("CKB_NEXT_USE_APPINDICATOR", QString("")).toLower(); |
3174 |
- QStringList appIndicatorOn = QStringList() << "yes" << "on" << "1"; |
3175 |
- QStringList appIndicatorOff = QStringList() << "no" << "off" << "0"; |
3176 |
- |
3177 |
- useAppindicator = false; |
3178 |
- trayIcon = 0; |
3179 |
- |
3180 |
- if(((desktop == "unity" || qpaTheme == "appmenu-qt5" || qpaTheme == "gtk2") && !appIndicatorOff.contains(ckbnextAppindicator)) || appIndicatorOn.contains(ckbnextAppindicator)){ |
3181 |
- qDebug() << "Using AppIndicator"; |
3182 |
- useAppindicator = true; |
3183 |
- |
3184 |
- indicatorMenu = gtk_menu_new(); |
3185 |
- indicatorMenuRestoreItem = gtk_menu_item_new_with_label("Restore"); |
3186 |
- indicatorMenuQuitItem = gtk_menu_item_new_with_label("Quit"); |
3187 |
- |
3188 |
- gtk_menu_shell_append(GTK_MENU_SHELL(indicatorMenu), indicatorMenuRestoreItem); |
3189 |
- gtk_menu_shell_append(GTK_MENU_SHELL(indicatorMenu), indicatorMenuQuitItem); |
3190 |
- |
3191 |
- g_signal_connect(indicatorMenuQuitItem, "activate", |
3192 |
- G_CALLBACK(quitIndicator), this); |
3193 |
- g_signal_connect(indicatorMenuRestoreItem, "activate", |
3194 |
- G_CALLBACK(restoreIndicator), this); |
3195 |
- |
3196 |
- gtk_widget_show(indicatorMenuRestoreItem); |
3197 |
- gtk_widget_show(indicatorMenuQuitItem); |
3198 |
- |
3199 |
- indicator = app_indicator_new("ckb-next", "indicator-messages", APP_INDICATOR_CATEGORY_APPLICATION_STATUS); |
3200 |
- |
3201 |
- app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE); |
3202 |
- app_indicator_set_menu(indicator, GTK_MENU(indicatorMenu)); |
3203 |
- app_indicator_set_icon(indicator, "ckb-next"); |
3204 |
- |
3205 |
- // Catch scroll events |
3206 |
- g_signal_connect(indicator, "scroll-event", G_CALLBACK(indicatorScroll), this); |
3207 |
- } else |
3208 |
-#endif |
3209 |
- { |
3210 |
- qDebug() << "Using QSytemTrayIcon"; |
3211 |
- trayIconMenu = new QMenu(this); |
3212 |
- trayIconMenu->addAction(changeTrayIconAction); |
3213 |
- trayIconMenu->addAction(restoreAction); |
3214 |
- trayIconMenu->addAction(closeAction); |
3215 |
- trayIcon = new CkbSystemTrayIcon(getIcon(), this); |
3216 |
- trayIcon->setContextMenu(trayIconMenu); |
3217 |
- trayIcon->show(); |
3218 |
- connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconClicked(QSystemTrayIcon::ActivationReason))); |
3219 |
- connect(trayIcon, &CkbSystemTrayIcon::wheelScrolled, this, &MainWindow::handleTrayScrollEvt); |
3220 |
- } |
3221 |
+ trayIconMenu = new QMenu(this); |
3222 |
+ trayIconMenu->addAction(changeTrayIconAction); |
3223 |
+ trayIconMenu->addAction(restoreAction); |
3224 |
+ trayIconMenu->addAction(closeAction); |
3225 |
+ trayIcon = new CkbSystemTrayIcon(getIcon(), this); |
3226 |
+ trayIcon->setContextMenu(trayIconMenu); |
3227 |
+ trayIcon->show(); |
3228 |
+ connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconClicked(QSystemTrayIcon::ActivationReason))); |
3229 |
+ connect(trayIcon, &CkbSystemTrayIcon::scrollRequested, this, &MainWindow::handleTrayScrollEvt); |
3230 |
toggleTrayIcon(!CkbSettings::get("Program/SuppressTrayIcon").toBool()); |
3231 |
|
3232 |
#ifdef Q_OS_MACOS |
3233 |
@@ -307,7 +232,8 @@ MainWindow::MainWindow(QWidget *parent) : |
3234 |
#endif |
3235 |
} |
3236 |
|
3237 |
-void MainWindow::handleTrayScrollEvt(bool up){ |
3238 |
+void MainWindow::handleTrayScrollEvt(int delta, Qt::Orientation orientation){ |
3239 |
+ bool up = delta > 0; |
3240 |
emit trayIconScrolled(up); |
3241 |
} |
3242 |
|
3243 |
@@ -320,12 +246,7 @@ void MainWindow::checkForCkbUpdates(){ |
3244 |
} |
3245 |
|
3246 |
void MainWindow::toggleTrayIcon(bool visible){ |
3247 |
-#ifdef USE_LIBAPPINDICATOR |
3248 |
- if(useAppindicator) |
3249 |
- app_indicator_set_status(indicator, visible ? APP_INDICATOR_STATUS_ACTIVE : APP_INDICATOR_STATUS_PASSIVE); |
3250 |
- else |
3251 |
-#endif |
3252 |
- trayIcon->setVisible(visible); |
3253 |
+ trayIcon->setVisible(visible); |
3254 |
} |
3255 |
|
3256 |
void MainWindow::addDevice(Kb* device){ |
3257 |
diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h |
3258 |
index b9021420..c668d5ba 100644 |
3259 |
--- a/src/gui/mainwindow.h |
3260 |
+++ b/src/gui/mainwindow.h |
3261 |
@@ -15,17 +15,6 @@ |
3262 |
#include "ckbupdater.h" |
3263 |
#endif |
3264 |
|
3265 |
-#ifdef USE_LIBAPPINDICATOR |
3266 |
-// 'signals' has to be undefined as GTK has its own signal mechanism |
3267 |
-#undef signals |
3268 |
-extern "C" { |
3269 |
- #include <libappindicator/app-indicator.h> |
3270 |
- #include <gtk/gtk.h> |
3271 |
-} |
3272 |
-// Redefine QT signals as per qtbase/src/corelib/kernel/qobjectdefs.h |
3273 |
-#define signals Q_SIGNALS |
3274 |
-#endif |
3275 |
- |
3276 |
namespace Ui { |
3277 |
class MainWindow; |
3278 |
} |
3279 |
@@ -51,15 +40,6 @@ class MainWindow : public QMainWindow |
3280 |
QAction* restoreAction; |
3281 |
QAction* closeAction; |
3282 |
QAction* changeTrayIconAction; |
3283 |
- |
3284 |
-#ifdef USE_LIBAPPINDICATOR |
3285 |
- bool useAppindicator; |
3286 |
- AppIndicator* indicator; |
3287 |
- GtkWidget* indicatorMenu; |
3288 |
- GtkWidget* indicatorMenuQuitItem; |
3289 |
- GtkWidget* indicatorMenuRestoreItem; |
3290 |
-#endif |
3291 |
- |
3292 |
QMenu* trayIconMenu; |
3293 |
CkbSystemTrayIcon* trayIcon; |
3294 |
void closeEvent(QCloseEvent *event); |
3295 |
@@ -84,7 +64,7 @@ public slots: |
3296 |
void checkForCkbUpdates(); |
3297 |
void changeTrayIconToMonochrome(); |
3298 |
void changeTrayIconToRGB(); |
3299 |
- void handleTrayScrollEvt(bool up); |
3300 |
+ void handleTrayScrollEvt(int delta, Qt::Orientation orientation); |
3301 |
|
3302 |
signals: |
3303 |
void switchToProfileCLI(QString profile); |
3304 |
@@ -96,7 +76,6 @@ private slots: |
3305 |
void updateVersion(); |
3306 |
void checkFwUpdates(); |
3307 |
void timerTick(); |
3308 |
- void iconClicked(QSystemTrayIcon::ActivationReason reason); |
3309 |
void cleanup(); |
3310 |
void showFwUpdateNotification(QWidget* widget, float version); |
3311 |
void QSignalHandler(); |
3312 |
@@ -104,7 +83,7 @@ private slots: |
3313 |
#if defined(Q_OS_MACOS) && !defined(OS_MAC_LEGACY) |
3314 |
void appleRequestHidTimer(); |
3315 |
#endif |
3316 |
- |
3317 |
+ void iconClicked(QSystemTrayIcon::ActivationReason reason); |
3318 |
private: |
3319 |
Ui::MainWindow *ui; |
3320 |
QSocketNotifier* sigNotifier; |