1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qdbusmenutypes_p.h" |
41 | |
42 | #include <QDBusConnection> |
43 | #include <QDBusMetaType> |
44 | #include <QImage> |
45 | #include <QIcon> |
46 | #include <QImage> |
47 | #include <QPixmap> |
48 | #include <QDebug> |
49 | #include <QtEndian> |
50 | #include <QBuffer> |
51 | #include <private/qkeysequence_p.h> |
52 | #include <qpa/qplatformmenu.h> |
53 | #include "qdbusplatformmenu_p.h" |
54 | |
55 | QT_BEGIN_NAMESPACE |
56 | |
57 | const QDBusArgument &(QDBusArgument &arg, const QDBusMenuItem &item) |
58 | { |
59 | arg.beginStructure(); |
60 | arg << item.m_id << item.m_properties; |
61 | arg.endStructure(); |
62 | return arg; |
63 | } |
64 | |
65 | const QDBusArgument &(const QDBusArgument &arg, QDBusMenuItem &item) |
66 | { |
67 | arg.beginStructure(); |
68 | arg >> item.m_id >> item.m_properties; |
69 | arg.endStructure(); |
70 | return arg; |
71 | } |
72 | |
73 | const QDBusArgument &(QDBusArgument &arg, const QDBusMenuItemKeys &keys) |
74 | { |
75 | arg.beginStructure(); |
76 | arg << keys.id << keys.properties; |
77 | arg.endStructure(); |
78 | return arg; |
79 | } |
80 | |
81 | const QDBusArgument &(const QDBusArgument &arg, QDBusMenuItemKeys &keys) |
82 | { |
83 | arg.beginStructure(); |
84 | arg >> keys.id >> keys.properties; |
85 | arg.endStructure(); |
86 | return arg; |
87 | } |
88 | |
89 | uint QDBusMenuLayoutItem::(int id, int depth, const QStringList &propertyNames, const QDBusPlatformMenu *) |
90 | { |
91 | qCDebug(qLcMenu) << id << "depth" << depth << propertyNames; |
92 | m_id = id; |
93 | if (id == 0) { |
94 | m_properties.insert(akey: QLatin1String("children-display" ), avalue: QLatin1String("submenu" )); |
95 | if (topLevelMenu) |
96 | populate(menu: topLevelMenu, depth, propertyNames); |
97 | return 1; // revision |
98 | } |
99 | |
100 | QDBusPlatformMenuItem *item = QDBusPlatformMenuItem::byId(id); |
101 | if (item) { |
102 | const QDBusPlatformMenu * = static_cast<const QDBusPlatformMenu *>(item->menu()); |
103 | |
104 | if (menu) { |
105 | if (depth != 0) |
106 | populate(menu, depth, propertyNames); |
107 | return menu->revision(); |
108 | } |
109 | } |
110 | |
111 | return 1; // revision |
112 | } |
113 | |
114 | void QDBusMenuLayoutItem::(const QDBusPlatformMenu *, int depth, const QStringList &propertyNames) |
115 | { |
116 | const auto items = menu->items(); |
117 | for (QDBusPlatformMenuItem *item : items) { |
118 | QDBusMenuLayoutItem child; |
119 | child.populate(item, depth: depth - 1, propertyNames); |
120 | m_children << child; |
121 | } |
122 | } |
123 | |
124 | void QDBusMenuLayoutItem::(const QDBusPlatformMenuItem *item, int depth, const QStringList &propertyNames) |
125 | { |
126 | m_id = item->dbusID(); |
127 | QDBusMenuItem proxy(item); |
128 | m_properties = proxy.m_properties; |
129 | |
130 | const QDBusPlatformMenu * = static_cast<const QDBusPlatformMenu *>(item->menu()); |
131 | if (depth != 0 && menu) |
132 | populate(menu, depth, propertyNames); |
133 | } |
134 | |
135 | const QDBusArgument &(QDBusArgument &arg, const QDBusMenuLayoutItem &item) |
136 | { |
137 | arg.beginStructure(); |
138 | arg << item.m_id << item.m_properties; |
139 | arg.beginArray(elementMetaTypeId: qMetaTypeId<QDBusVariant>()); |
140 | for (const QDBusMenuLayoutItem &child : item.m_children) |
141 | arg << QDBusVariant(QVariant::fromValue<QDBusMenuLayoutItem>(value: child)); |
142 | arg.endArray(); |
143 | arg.endStructure(); |
144 | return arg; |
145 | } |
146 | |
147 | const QDBusArgument &(const QDBusArgument &arg, QDBusMenuLayoutItem &item) |
148 | { |
149 | arg.beginStructure(); |
150 | arg >> item.m_id >> item.m_properties; |
151 | arg.beginArray(); |
152 | while (!arg.atEnd()) { |
153 | QDBusVariant dbusVariant; |
154 | arg >> dbusVariant; |
155 | QDBusArgument childArgument = qvariant_cast<QDBusArgument>(v: dbusVariant.variant()); |
156 | |
157 | QDBusMenuLayoutItem child; |
158 | childArgument >> child; |
159 | item.m_children.append(t: child); |
160 | } |
161 | arg.endArray(); |
162 | arg.endStructure(); |
163 | return arg; |
164 | } |
165 | |
166 | void QDBusMenuItem::() |
167 | { |
168 | qDBusRegisterMetaType<QDBusMenuItem>(); |
169 | qDBusRegisterMetaType<QDBusMenuItemList>(); |
170 | qDBusRegisterMetaType<QDBusMenuItemKeys>(); |
171 | qDBusRegisterMetaType<QDBusMenuItemKeysList>(); |
172 | qDBusRegisterMetaType<QDBusMenuLayoutItem>(); |
173 | qDBusRegisterMetaType<QDBusMenuLayoutItemList>(); |
174 | qDBusRegisterMetaType<QDBusMenuEvent>(); |
175 | qDBusRegisterMetaType<QDBusMenuEventList>(); |
176 | qDBusRegisterMetaType<QDBusMenuShortcut>(); |
177 | } |
178 | |
179 | QDBusMenuItem::(const QDBusPlatformMenuItem *item) |
180 | : m_id(item->dbusID()) |
181 | { |
182 | if (item->isSeparator()) { |
183 | m_properties.insert(akey: QLatin1String("type" ), avalue: QLatin1String("separator" )); |
184 | } else { |
185 | m_properties.insert(akey: QLatin1String("label" ), avalue: convertMnemonic(label: item->text())); |
186 | if (item->menu()) |
187 | m_properties.insert(akey: QLatin1String("children-display" ), avalue: QLatin1String("submenu" )); |
188 | m_properties.insert(akey: QLatin1String("enabled" ), avalue: item->isEnabled()); |
189 | if (item->isCheckable()) { |
190 | QString toggleType = item->hasExclusiveGroup() ? QLatin1String("radio" ) : QLatin1String("checkmark" ); |
191 | m_properties.insert(akey: QLatin1String("toggle-type" ), avalue: toggleType); |
192 | m_properties.insert(akey: QLatin1String("toggle-state" ), avalue: item->isChecked() ? 1 : 0); |
193 | } |
194 | #ifndef QT_NO_SHORTCUT |
195 | const QKeySequence &scut = item->shortcut(); |
196 | if (!scut.isEmpty()) { |
197 | QDBusMenuShortcut shortcut = convertKeySequence(sequence: scut); |
198 | m_properties.insert(akey: QLatin1String("shortcut" ), avalue: QVariant::fromValue(value: shortcut)); |
199 | } |
200 | #endif |
201 | const QIcon &icon = item->icon(); |
202 | if (!icon.name().isEmpty()) { |
203 | m_properties.insert(akey: QLatin1String("icon-name" ), avalue: icon.name()); |
204 | } else if (!icon.isNull()) { |
205 | QBuffer buf; |
206 | icon.pixmap(extent: 16).save(device: &buf, format: "PNG" ); |
207 | m_properties.insert(akey: QLatin1String("icon-data" ), avalue: buf.data()); |
208 | } |
209 | } |
210 | m_properties.insert(akey: QLatin1String("visible" ), avalue: item->isVisible()); |
211 | } |
212 | |
213 | QDBusMenuItemList QDBusMenuItem::(const QList<int> &ids, const QStringList &propertyNames) |
214 | { |
215 | Q_UNUSED(propertyNames) |
216 | QDBusMenuItemList ret; |
217 | const QList<const QDBusPlatformMenuItem *> items = QDBusPlatformMenuItem::byIds(ids); |
218 | ret.reserve(asize: items.size()); |
219 | for (const QDBusPlatformMenuItem *item : items) |
220 | ret << QDBusMenuItem(item); |
221 | return ret; |
222 | } |
223 | |
224 | QString QDBusMenuItem::(const QString &label) |
225 | { |
226 | // convert only the first occurrence of ampersand which is not at the end |
227 | // dbusmenu uses underscore instead of ampersand |
228 | int idx = label.indexOf(c: QLatin1Char('&')); |
229 | if (idx < 0 || idx == label.length() - 1) |
230 | return label; |
231 | QString ret(label); |
232 | ret[idx] = QLatin1Char('_'); |
233 | return ret; |
234 | } |
235 | |
236 | #ifndef QT_NO_SHORTCUT |
237 | QDBusMenuShortcut QDBusMenuItem::(const QKeySequence &sequence) |
238 | { |
239 | QDBusMenuShortcut shortcut; |
240 | for (int i = 0; i < sequence.count(); ++i) { |
241 | QStringList tokens; |
242 | int key = sequence[i]; |
243 | if (key & Qt::MetaModifier) |
244 | tokens << QStringLiteral("Super" ); |
245 | if (key & Qt::ControlModifier) |
246 | tokens << QStringLiteral("Control" ); |
247 | if (key & Qt::AltModifier) |
248 | tokens << QStringLiteral("Alt" ); |
249 | if (key & Qt::ShiftModifier) |
250 | tokens << QStringLiteral("Shift" ); |
251 | if (key & Qt::KeypadModifier) |
252 | tokens << QStringLiteral("Num" ); |
253 | |
254 | QString keyName = QKeySequencePrivate::keyName(key, format: QKeySequence::PortableText); |
255 | if (keyName == QLatin1String("+" )) |
256 | tokens << QStringLiteral("plus" ); |
257 | else if (keyName == QLatin1String("-" )) |
258 | tokens << QStringLiteral("minus" ); |
259 | else |
260 | tokens << keyName; |
261 | shortcut << tokens; |
262 | } |
263 | return shortcut; |
264 | } |
265 | #endif |
266 | |
267 | const QDBusArgument &(QDBusArgument &arg, const QDBusMenuEvent &ev) |
268 | { |
269 | arg.beginStructure(); |
270 | arg << ev.m_id << ev.m_eventId << ev.m_data << ev.m_timestamp; |
271 | arg.endStructure(); |
272 | return arg; |
273 | } |
274 | |
275 | const QDBusArgument &(const QDBusArgument &arg, QDBusMenuEvent &ev) |
276 | { |
277 | arg.beginStructure(); |
278 | arg >> ev.m_id >> ev.m_eventId >> ev.m_data >> ev.m_timestamp; |
279 | arg.endStructure(); |
280 | return arg; |
281 | } |
282 | |
283 | #ifndef QT_NO_DEBUG_STREAM |
284 | QDebug (QDebug d, const QDBusMenuItem &item) |
285 | { |
286 | QDebugStateSaver saver(d); |
287 | d.nospace(); |
288 | d << "QDBusMenuItem(id=" << item.m_id << ", properties=" << item.m_properties << ')'; |
289 | return d; |
290 | } |
291 | |
292 | QDebug (QDebug d, const QDBusMenuLayoutItem &item) |
293 | { |
294 | QDebugStateSaver saver(d); |
295 | d.nospace(); |
296 | d << "QDBusMenuLayoutItem(id=" << item.m_id << ", properties=" << item.m_properties << ", " << item.m_children.count() << " children)" ; |
297 | return d; |
298 | } |
299 | #endif |
300 | |
301 | QT_END_NAMESPACE |
302 | |