Changeset View
Changeset View
Standalone View
Standalone View
plugin/libdbusmenuqt/dbusmenuimporter.cpp
Show All 14 Lines | 1 | /* This file is part of the dbusmenu-qt library | |||
---|---|---|---|---|---|
15 | 15 | | |||
16 | You should have received a copy of the GNU Library General Public License | 16 | You should have received a copy of the GNU Library General Public License | ||
17 | along with this library; see the file COPYING.LIB. If not, write to | 17 | along with this library; see the file COPYING.LIB. If not, write to | ||
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | Boston, MA 02110-1301, USA. | 19 | Boston, MA 02110-1301, USA. | ||
20 | */ | 20 | */ | ||
21 | #include "dbusmenuimporter.h" | 21 | #include "dbusmenuimporter.h" | ||
22 | 22 | | |||
23 | #include "debug.h" | ||||
24 | | ||||
23 | // Qt | 25 | // Qt | ||
24 | #include <QCoreApplication> | 26 | #include <QCoreApplication> | ||
25 | #include <QDBusConnection> | 27 | #include <QDBusConnection> | ||
26 | #include <QDBusInterface> | 28 | #include <QDBusInterface> | ||
27 | #include <QDBusReply> | 29 | #include <QDBusReply> | ||
28 | #include <QDBusVariant> | 30 | #include <QDBusVariant> | ||
29 | #include <QFont> | 31 | #include <QFont> | ||
30 | #include <QMenu> | 32 | #include <QMenu> | ||
Show All 10 Lines | |||||
41 | #include "dbusmenushortcut_p.h" | 43 | #include "dbusmenushortcut_p.h" | ||
42 | #include "utils_p.h" | 44 | #include "utils_p.h" | ||
43 | 45 | | |||
44 | // Generated | 46 | // Generated | ||
45 | #include "dbusmenu_interface.h" | 47 | #include "dbusmenu_interface.h" | ||
46 | 48 | | |||
47 | //#define BENCHMARK | 49 | //#define BENCHMARK | ||
48 | #ifdef BENCHMARK | 50 | #ifdef BENCHMARK | ||
49 | #include <QTime> | | |||
50 | static QTime sChrono; | 51 | static QTime sChrono; | ||
51 | #endif | 52 | #endif | ||
52 | 53 | | |||
53 | #define DMRETURN_IF_FAIL(cond) if (!(cond)) { \ | 54 | #define DMRETURN_IF_FAIL(cond) if (!(cond)) { \ | ||
54 | qWarning() << "Condition failed: " #cond; \ | 55 | qCWarning(DBUSMENUQT) << "Condition failed: " #cond; \ | ||
55 | return; \ | 56 | return; \ | ||
56 | } | 57 | } | ||
57 | 58 | | |||
58 | static const char *DBUSMENU_PROPERTY_ID = "_dbusmenu_id"; | 59 | static const char *DBUSMENU_PROPERTY_ID = "_dbusmenu_id"; | ||
59 | static const char *DBUSMENU_PROPERTY_ICON_NAME = "_dbusmenu_icon_name"; | 60 | static const char *DBUSMENU_PROPERTY_ICON_NAME = "_dbusmenu_icon_name"; | ||
60 | static const char *DBUSMENU_PROPERTY_ICON_DATA_HASH = "_dbusmenu_icon_data_hash"; | 61 | static const char *DBUSMENU_PROPERTY_ICON_DATA_HASH = "_dbusmenu_icon_data_hash"; | ||
61 | 62 | | |||
62 | static QAction *createKdeTitle(QAction *action, QWidget *parent) | 63 | static QAction *createKdeTitle(QAction *action, QWidget *parent) | ||
63 | { | 64 | { | ||
64 | QToolButton *titleWidget = new QToolButton(0); | 65 | QToolButton *titleWidget = new QToolButton(nullptr); | ||
65 | QFont font = titleWidget->font(); | 66 | QFont font = titleWidget->font(); | ||
66 | font.setBold(true); | 67 | font.setBold(true); | ||
67 | titleWidget->setFont(font); | 68 | titleWidget->setFont(font); | ||
68 | titleWidget->setIcon(action->icon()); | 69 | titleWidget->setIcon(action->icon()); | ||
69 | titleWidget->setText(action->text()); | 70 | titleWidget->setText(action->text()); | ||
70 | titleWidget->setDown(true); | 71 | titleWidget->setDown(true); | ||
71 | titleWidget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); | 72 | titleWidget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); | ||
72 | 73 | | |||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Line(s) | 177 | } else if (key == QLatin1String("icon-name")) { | |||
177 | updateActionIconByName(action, value); | 178 | updateActionIconByName(action, value); | ||
178 | } else if (key == QLatin1String("icon-data")) { | 179 | } else if (key == QLatin1String("icon-data")) { | ||
179 | updateActionIconByData(action, value); | 180 | updateActionIconByData(action, value); | ||
180 | } else if (key == QLatin1String("visible")) { | 181 | } else if (key == QLatin1String("visible")) { | ||
181 | updateActionVisible(action, value); | 182 | updateActionVisible(action, value); | ||
182 | } else if (key == QLatin1String("shortcut")) { | 183 | } else if (key == QLatin1String("shortcut")) { | ||
183 | updateActionShortcut(action, value); | 184 | updateActionShortcut(action, value); | ||
184 | } else { | 185 | } else { | ||
185 | qWarning() << "Unhandled property update" << key; | 186 | qDebug(DBUSMENUQT) << "Unhandled property update" << key; | ||
186 | } | 187 | } | ||
187 | } | 188 | } | ||
188 | 189 | | |||
189 | void updateActionLabel(QAction *action, const QVariant &value) | 190 | void updateActionLabel(QAction *action, const QVariant &value) | ||
190 | { | 191 | { | ||
191 | QString text = swapMnemonicChar(value.toString(), '_', '&'); | 192 | QString text = swapMnemonicChar(value.toString(), '_', '&'); | ||
192 | action->setText(text); | 193 | action->setText(text); | ||
193 | } | 194 | } | ||
Show All 31 Lines | 224 | { | |||
225 | uint dataHash = qHash(data); | 226 | uint dataHash = qHash(data); | ||
226 | uint previousDataHash = action->property(DBUSMENU_PROPERTY_ICON_DATA_HASH).toUInt(); | 227 | uint previousDataHash = action->property(DBUSMENU_PROPERTY_ICON_DATA_HASH).toUInt(); | ||
227 | if (previousDataHash == dataHash) { | 228 | if (previousDataHash == dataHash) { | ||
228 | return; | 229 | return; | ||
229 | } | 230 | } | ||
230 | action->setProperty(DBUSMENU_PROPERTY_ICON_DATA_HASH, dataHash); | 231 | action->setProperty(DBUSMENU_PROPERTY_ICON_DATA_HASH, dataHash); | ||
231 | QPixmap pix; | 232 | QPixmap pix; | ||
232 | if (!pix.loadFromData(data)) { | 233 | if (!pix.loadFromData(data)) { | ||
233 | qWarning() << "Failed to decode icon-data property for action" << action->text(); | 234 | qDebug(DBUSMENUQT) << "Failed to decode icon-data property for action" << action->text(); | ||
234 | action->setIcon(QIcon()); | 235 | action->setIcon(QIcon()); | ||
235 | return; | 236 | return; | ||
236 | } | 237 | } | ||
237 | action->setIcon(QIcon(pix)); | 238 | action->setIcon(QIcon(pix)); | ||
238 | } | 239 | } | ||
239 | 240 | | |||
240 | void updateActionVisible(QAction *action, const QVariant &value) | 241 | void updateActionVisible(QAction *action, const QVariant &value) | ||
241 | { | 242 | { | ||
Show All 11 Lines | |||||
253 | 254 | | |||
254 | QMenu *menuForId(int id) const | 255 | QMenu *menuForId(int id) const | ||
255 | { | 256 | { | ||
256 | if (id == 0) { | 257 | if (id == 0) { | ||
257 | return q->menu(); | 258 | return q->menu(); | ||
258 | } | 259 | } | ||
259 | QAction *action = m_actionForId.value(id); | 260 | QAction *action = m_actionForId.value(id); | ||
260 | if (!action) { | 261 | if (!action) { | ||
261 | return 0; | 262 | return nullptr; | ||
262 | } | 263 | } | ||
263 | return action->menu(); | 264 | return action->menu(); | ||
264 | } | 265 | } | ||
265 | 266 | | |||
266 | void slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList); | 267 | void slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList); | ||
267 | 268 | | |||
268 | void sendEvent(int id, const QString &eventId) | 269 | void sendEvent(int id, const QString &eventId) | ||
269 | { | 270 | { | ||
270 | m_interface->Event(id, eventId, QDBusVariant(QString()), 0u); | 271 | m_interface->Event(id, eventId, QDBusVariant(QString()), 0u); | ||
271 | } | 272 | } | ||
272 | }; | 273 | }; | ||
273 | 274 | | |||
274 | DBusMenuImporter::DBusMenuImporter(const QString &service, const QString &path, QObject *parent) | 275 | DBusMenuImporter::DBusMenuImporter(const QString &service, const QString &path, QObject *parent) | ||
275 | : QObject(parent) | 276 | : QObject(parent) | ||
276 | , d(new DBusMenuImporterPrivate) | 277 | , d(new DBusMenuImporterPrivate) | ||
277 | { | 278 | { | ||
278 | DBusMenuTypes_register(); | 279 | DBusMenuTypes_register(); | ||
279 | 280 | | |||
280 | d->q = this; | 281 | d->q = this; | ||
281 | d->m_interface = new DBusMenuInterface(service, path, QDBusConnection::sessionBus(), this); | 282 | d->m_interface = new DBusMenuInterface(service, path, QDBusConnection::sessionBus(), this); | ||
282 | d->m_menu = 0; | 283 | d->m_menu = nullptr; | ||
283 | 284 | | |||
284 | d->m_pendingLayoutUpdateTimer = new QTimer(this); | 285 | d->m_pendingLayoutUpdateTimer = new QTimer(this); | ||
285 | d->m_pendingLayoutUpdateTimer->setSingleShot(true); | 286 | d->m_pendingLayoutUpdateTimer->setSingleShot(true); | ||
286 | connect(d->m_pendingLayoutUpdateTimer, &QTimer::timeout, this, &DBusMenuImporter::processPendingLayoutUpdates); | 287 | connect(d->m_pendingLayoutUpdateTimer, &QTimer::timeout, this, &DBusMenuImporter::processPendingLayoutUpdates); | ||
287 | 288 | | |||
288 | connect(d->m_interface, &DBusMenuInterface::LayoutUpdated, this, &DBusMenuImporter::slotLayoutUpdated); | 289 | connect(d->m_interface, &DBusMenuInterface::LayoutUpdated, this, &DBusMenuImporter::slotLayoutUpdated); | ||
289 | connect(d->m_interface, &DBusMenuInterface::ItemActivationRequested, this, &DBusMenuImporter::slotItemActivationRequested); | 290 | connect(d->m_interface, &DBusMenuInterface::ItemActivationRequested, this, &DBusMenuImporter::slotItemActivationRequested); | ||
290 | connect(d->m_interface, &DBusMenuInterface::ItemsPropertiesUpdated, this, [this](const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList) { | 291 | connect(d->m_interface, &DBusMenuInterface::ItemsPropertiesUpdated, this, [this](const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList) { | ||
Show All 31 Lines | 320 | { | |||
322 | Q_FOREACH(int id, ids) { | 323 | Q_FOREACH(int id, ids) { | ||
323 | d->refresh(id); | 324 | d->refresh(id); | ||
324 | } | 325 | } | ||
325 | } | 326 | } | ||
326 | 327 | | |||
327 | QMenu *DBusMenuImporter::menu() const | 328 | QMenu *DBusMenuImporter::menu() const | ||
328 | { | 329 | { | ||
329 | if (!d->m_menu) { | 330 | if (!d->m_menu) { | ||
330 | d->m_menu = d->createMenu(0); | 331 | d->m_menu = d->createMenu(nullptr); | ||
331 | } | 332 | } | ||
332 | return d->m_menu; | 333 | return d->m_menu; | ||
333 | } | 334 | } | ||
334 | 335 | | |||
335 | void DBusMenuImporterPrivate::slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList) | 336 | void DBusMenuImporterPrivate::slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList) | ||
336 | { | 337 | { | ||
337 | Q_FOREACH(const DBusMenuItem &item, updatedList) { | 338 | Q_FOREACH(const DBusMenuItem &item, updatedList) { | ||
338 | QAction *action = m_actionForId.value(item.id); | 339 | QAction *action = m_actionForId.value(item.id); | ||
Show All 39 Lines | |||||
378 | { | 379 | { | ||
379 | int parentId = watcher->property(DBUSMENU_PROPERTY_ID).toInt(); | 380 | int parentId = watcher->property(DBUSMENU_PROPERTY_ID).toInt(); | ||
380 | watcher->deleteLater(); | 381 | watcher->deleteLater(); | ||
381 | 382 | | |||
382 | QMenu *menu = d->menuForId(parentId); | 383 | QMenu *menu = d->menuForId(parentId); | ||
383 | 384 | | |||
384 | QDBusPendingReply<uint, DBusMenuLayoutItem> reply = *watcher; | 385 | QDBusPendingReply<uint, DBusMenuLayoutItem> reply = *watcher; | ||
385 | if (!reply.isValid()) { | 386 | if (!reply.isValid()) { | ||
386 | qWarning() << reply.error().message(); | 387 | qDebug(DBUSMENUQT) << reply.error().message(); | ||
387 | if (menu) { | 388 | if (menu) { | ||
388 | emit menuUpdated(menu); | 389 | emit menuUpdated(menu); | ||
389 | } | 390 | } | ||
390 | return; | 391 | return; | ||
391 | } | 392 | } | ||
392 | 393 | | |||
393 | #ifdef BENCHMARK | 394 | #ifdef BENCHMARK | ||
394 | DMDEBUG << "- items received:" << sChrono.elapsed() << "ms"; | 395 | DMDEBUG << "- items received:" << sChrono.elapsed() << "ms"; | ||
395 | #endif | 396 | #endif | ||
396 | DBusMenuLayoutItem rootItem = reply.argumentAt<1>(); | 397 | DBusMenuLayoutItem rootItem = reply.argumentAt<1>(); | ||
397 | 398 | | |||
398 | if (!menu) { | 399 | if (!menu) { | ||
399 | qWarning() << "No menu for id" << parentId; | 400 | qDebug(DBUSMENUQT) << "No menu for id" << parentId; | ||
400 | return; | 401 | return; | ||
401 | } | 402 | } | ||
402 | 403 | | |||
403 | //remove outdated actions | 404 | //remove outdated actions | ||
404 | QSet<int> newDBusMenuItemIds; | 405 | QSet<int> newDBusMenuItemIds; | ||
405 | newDBusMenuItemIds.reserve(rootItem.children.count()); | 406 | newDBusMenuItemIds.reserve(rootItem.children.count()); | ||
406 | for (const DBusMenuLayoutItem &item: rootItem.children) { | 407 | for (const DBusMenuLayoutItem &item: rootItem.children) { | ||
407 | newDBusMenuItemIds << item.id; | 408 | newDBusMenuItemIds << item.id; | ||
408 | } | 409 | } | ||
409 | for (QAction *action: menu->actions()) { | 410 | for (QAction *action: menu->actions()) { | ||
410 | int id = action->property(DBUSMENU_PROPERTY_ID).toInt(); | 411 | int id = action->property(DBUSMENU_PROPERTY_ID).toInt(); | ||
411 | if (! newDBusMenuItemIds.contains(id)) { | 412 | if (! newDBusMenuItemIds.contains(id)) { | ||
413 | menu->removeAction(action); | ||||
412 | action->deleteLater(); | 414 | action->deleteLater(); | ||
413 | d->m_actionForId.remove(id); | 415 | d->m_actionForId.remove(id); | ||
414 | } | 416 | } | ||
415 | } | 417 | } | ||
416 | 418 | | |||
417 | //insert or update new actions into our menu | 419 | //insert or update new actions into our menu | ||
418 | for (const DBusMenuLayoutItem &dbusMenuItem: rootItem.children) { | 420 | for (const DBusMenuLayoutItem &dbusMenuItem: rootItem.children) { | ||
419 | DBusMenuImporterPrivate::ActionForId::Iterator it = d->m_actionForId.find(dbusMenuItem.id); | 421 | DBusMenuImporterPrivate::ActionForId::Iterator it = d->m_actionForId.find(dbusMenuItem.id); | ||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Line(s) | 469 | { | |||
472 | 474 | | |||
473 | int id = action->property(DBUSMENU_PROPERTY_ID).toInt(); | 475 | int id = action->property(DBUSMENU_PROPERTY_ID).toInt(); | ||
474 | 476 | | |||
475 | auto call = d->m_interface->AboutToShow(id); | 477 | auto call = d->m_interface->AboutToShow(id); | ||
476 | QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); | 478 | QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); | ||
477 | watcher->setProperty(DBUSMENU_PROPERTY_ID, id); | 479 | watcher->setProperty(DBUSMENU_PROPERTY_ID, id); | ||
478 | connect(watcher, &QDBusPendingCallWatcher::finished, this, | 480 | connect(watcher, &QDBusPendingCallWatcher::finished, this, | ||
479 | &DBusMenuImporter::slotAboutToShowDBusCallFinished); | 481 | &DBusMenuImporter::slotAboutToShowDBusCallFinished); | ||
482 | | ||||
483 | // Firefox deliberately ignores "aboutToShow" whereas Qt ignores" opened", so we'll just send both all the time... | ||||
484 | d->sendEvent(id, QStringLiteral("opened")); | ||||
480 | } | 485 | } | ||
481 | 486 | | |||
482 | void DBusMenuImporter::slotAboutToShowDBusCallFinished(QDBusPendingCallWatcher *watcher) | 487 | void DBusMenuImporter::slotAboutToShowDBusCallFinished(QDBusPendingCallWatcher *watcher) | ||
483 | { | 488 | { | ||
484 | int id = watcher->property(DBUSMENU_PROPERTY_ID).toInt(); | 489 | int id = watcher->property(DBUSMENU_PROPERTY_ID).toInt(); | ||
485 | watcher->deleteLater(); | 490 | watcher->deleteLater(); | ||
486 | 491 | | |||
487 | QMenu *menu = d->menuForId(id); | 492 | QMenu *menu = d->menuForId(id); | ||
488 | if (!menu) { | 493 | if (!menu) { | ||
489 | return; | 494 | return; | ||
490 | } | 495 | } | ||
491 | 496 | | |||
492 | QDBusPendingReply<bool> reply = *watcher; | 497 | QDBusPendingReply<bool> reply = *watcher; | ||
493 | if (reply.isError()) { | 498 | if (reply.isError()) { | ||
494 | qWarning() << "Call to AboutToShow() failed:" << reply.error().message(); | 499 | qDebug(DBUSMENUQT) << "Call to AboutToShow() failed:" << reply.error().message(); | ||
495 | menuUpdated(menu); | 500 | menuUpdated(menu); | ||
496 | return; | 501 | return; | ||
497 | } | 502 | } | ||
498 | //Note, this isn't used by Qt's QPT - but we get a LayoutChanged emitted before | 503 | //Note, this isn't used by Qt's QPT - but we get a LayoutChanged emitted before | ||
499 | //this returns, which equates to the same thing | 504 | //this returns, which equates to the same thing | ||
500 | bool needRefresh = reply.argumentAt<0>(); | 505 | bool needRefresh = reply.argumentAt<0>(); | ||
501 | 506 | | |||
502 | if (needRefresh || menu->actions().isEmpty()) { | 507 | if (needRefresh || menu->actions().isEmpty()) { | ||
Show All 17 Lines | |||||
520 | } | 525 | } | ||
521 | 526 | | |||
522 | void DBusMenuImporter::slotMenuAboutToShow() | 527 | void DBusMenuImporter::slotMenuAboutToShow() | ||
523 | { | 528 | { | ||
524 | QMenu *menu = qobject_cast<QMenu*>(sender()); | 529 | QMenu *menu = qobject_cast<QMenu*>(sender()); | ||
525 | Q_ASSERT(menu); | 530 | Q_ASSERT(menu); | ||
526 | 531 | | |||
527 | updateMenu(menu); | 532 | updateMenu(menu); | ||
528 | | ||||
529 | QAction *action = menu->menuAction(); | | |||
530 | Q_ASSERT(action); | | |||
531 | | ||||
532 | int id = action->property(DBUSMENU_PROPERTY_ID).toInt(); | | |||
533 | d->sendEvent(id, QStringLiteral("opened")); | | |||
534 | } | 533 | } | ||
535 | 534 | | |||
536 | QMenu *DBusMenuImporter::createMenu(QWidget *parent) | 535 | QMenu *DBusMenuImporter::createMenu(QWidget *parent) | ||
537 | { | 536 | { | ||
538 | return new QMenu(parent); | 537 | return new QMenu(parent); | ||
539 | } | 538 | } | ||
540 | 539 | | |||
541 | QIcon DBusMenuImporter::iconForName(const QString &/*name*/) | 540 | QIcon DBusMenuImporter::iconForName(const QString &/*name*/) | ||
542 | { | 541 | { | ||
543 | return QIcon(); | 542 | return QIcon(); | ||
544 | } | 543 | } | ||
545 | 544 | | |||
546 | #include "moc_dbusmenuimporter.cpp" | 545 | #include "moc_dbusmenuimporter.cpp" |