/[packages]/cauldron/ckb-next/current/SOURCES/0001-Replace-AppIndicator-with-minimal-KStatusNotifier.patch
ViewVC logotype

Contents of /cauldron/ckb-next/current/SOURCES/0001-Replace-AppIndicator-with-minimal-KStatusNotifier.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1617995 - (show annotations) (download)
Sat Aug 22 15:00:34 2020 UTC (3 years, 7 months ago) by daviddavid
File size: 120088 byte(s)
- add upstream to replace AppIndicator with minimal KStatusNotifier

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;

  ViewVC Help
Powered by ViewVC 1.1.30