1// Copyright (C) 2009 Marco Martin <notmart@gmail.com>
2// Copyright (C) 2016 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QT_NO_SYSTEMTRAYICON
6
7#include "qdbustraytypes_p.h"
8
9#include <QDBusConnection>
10#include <QDBusMetaType>
11#include <QImage>
12#include <QIcon>
13#include <QIconEngine>
14#include <QImage>
15#include <QPixmap>
16#include <QDebug>
17#include <QtEndian>
18#include <QPainter>
19#include <QGuiApplication>
20#include <qpa/qplatformmenu.h>
21#include <private/qdbusplatformmenu_p.h>
22#include <private/qicon_p.h>
23
24QT_BEGIN_NAMESPACE
25
26QT_IMPL_METATYPE_EXTERN(QXdgDBusImageStruct)
27QT_IMPL_METATYPE_EXTERN(QXdgDBusImageVector)
28QT_IMPL_METATYPE_EXTERN(QXdgDBusToolTipStruct)
29
30static const int IconSizeLimit = 64;
31static const int IconNormalSmallSize = 22;
32static const int IconNormalMediumSize = 64;
33
34QXdgDBusImageVector iconToQXdgDBusImageVector(const QIcon &icon)
35{
36 QXdgDBusImageVector ret;
37 if (icon.isNull())
38 return ret;
39 QIconEngine *engine = const_cast<QIcon &>(icon).data_ptr()->engine;
40 QList<QSize> sizes = engine->availableSizes(mode: QIcon::Normal, state: QIcon::Off);
41
42 // Omit any size larger than 64 px, to save D-Bus bandwidth;
43 // ensure that 22px or smaller exists, because it's a common size;
44 // and ensure that something between 22px and 64px exists, for better scaling to other sizes.
45 bool hasSmallIcon = false;
46 bool hasMediumIcon = false;
47 QList<QSize> toRemove;
48 for (const QSize &size : std::as_const(t&: sizes)) {
49 int maxSize = qMax(a: size.width(), b: size.height());
50 if (maxSize <= IconNormalSmallSize)
51 hasSmallIcon = true;
52 else if (maxSize <= IconNormalMediumSize)
53 hasMediumIcon = true;
54 else if (maxSize > IconSizeLimit)
55 toRemove << size;
56 }
57 for (const QSize &size : std::as_const(t&: toRemove))
58 sizes.removeOne(t: size);
59 if (!hasSmallIcon)
60 sizes.append(t: QSize(IconNormalSmallSize, IconNormalSmallSize));
61 if (!hasMediumIcon)
62 sizes.append(t: QSize(IconNormalMediumSize, IconNormalMediumSize));
63
64 ret.reserve(asize: sizes.size());
65 for (const QSize &size : std::as_const(t&: sizes)) {
66 // Protocol specifies ARGB32 format in network byte order
67 QImage im = engine->pixmap(size, mode: QIcon::Normal, state: QIcon::Off).toImage().convertToFormat(f: QImage::Format_ARGB32);
68 // letterbox if necessary to make it square
69 if (im.height() != im.width()) {
70 int maxSize = qMax(a: im.width(), b: im.height());
71 QImage padded(maxSize, maxSize, QImage::Format_ARGB32);
72 padded.fill(color: Qt::transparent);
73 QPainter painter(&padded);
74 painter.drawImage(x: (maxSize - im.width()) / 2, y: (maxSize - im.height()) / 2, image: im);
75 im = padded;
76 }
77 // copy and endian-convert
78 QXdgDBusImageStruct kim(im.width(), im.height());
79 qToBigEndian<quint32>(source: im.constBits(), count: im.width() * im.height(), dest: kim.data.data());
80
81 ret << kim;
82 }
83 return ret;
84}
85
86// Marshall the ImageStruct data into a D-Bus argument
87const QDBusArgument &operator<<(QDBusArgument &argument, const QXdgDBusImageStruct &icon)
88{
89 argument.beginStructure();
90 argument << icon.width;
91 argument << icon.height;
92 argument << icon.data;
93 argument.endStructure();
94 return argument;
95}
96
97// Retrieve the ImageStruct data from the D-Bus argument
98const QDBusArgument &operator>>(const QDBusArgument &argument, QXdgDBusImageStruct &icon)
99{
100 qint32 width;
101 qint32 height;
102 QByteArray data;
103
104 argument.beginStructure();
105 argument >> width;
106 argument >> height;
107 argument >> data;
108 argument.endStructure();
109
110 icon.width = width;
111 icon.height = height;
112 icon.data = data;
113
114 return argument;
115}
116
117// Marshall the ImageVector data into a D-Bus argument
118const QDBusArgument &operator<<(QDBusArgument &argument, const QXdgDBusImageVector &iconVector)
119{
120 argument.beginArray(elementMetaTypeId: qMetaTypeId<QXdgDBusImageStruct>());
121 for (int i = 0; i < iconVector.size(); ++i) {
122 argument << iconVector[i];
123 }
124 argument.endArray();
125 return argument;
126}
127
128// Retrieve the ImageVector data from the D-Bus argument
129const QDBusArgument &operator>>(const QDBusArgument &argument, QXdgDBusImageVector &iconVector)
130{
131 argument.beginArray();
132 iconVector.clear();
133
134 while (!argument.atEnd()) {
135 QXdgDBusImageStruct element;
136 argument >> element;
137 iconVector.append(t: element);
138 }
139
140 argument.endArray();
141
142 return argument;
143}
144
145// Marshall the ToolTipStruct data into a D-Bus argument
146const QDBusArgument &operator<<(QDBusArgument &argument, const QXdgDBusToolTipStruct &toolTip)
147{
148 argument.beginStructure();
149 argument << toolTip.icon;
150 argument << toolTip.image;
151 argument << toolTip.title;
152 argument << toolTip.subTitle;
153 argument.endStructure();
154 return argument;
155}
156
157// Retrieve the ToolTipStruct data from the D-Bus argument
158const QDBusArgument &operator>>(const QDBusArgument &argument, QXdgDBusToolTipStruct &toolTip)
159{
160 QString icon;
161 QXdgDBusImageVector image;
162 QString title;
163 QString subTitle;
164
165 argument.beginStructure();
166 argument >> icon;
167 argument >> image;
168 argument >> title;
169 argument >> subTitle;
170 argument.endStructure();
171
172 toolTip.icon = icon;
173 toolTip.image = image;
174 toolTip.title = title;
175 toolTip.subTitle = subTitle;
176
177 return argument;
178}
179
180QT_END_NAMESPACE
181#endif // QT_NO_SYSTEMTRAYICON
182

source code of qtbase/src/gui/platform/unix/dbustray/qdbustraytypes.cpp