1// Copyright (C) 2016 Dmitry Shachnev <mitya57@gmail.com>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qdbusmenubar_p.h"
5#include "qdbusmenuregistrarproxy_p.h"
6
7QT_BEGIN_NAMESPACE
8
9using namespace Qt::StringLiterals;
10
11/* note: do not change these to QStringLiteral;
12 we are unloaded before QtDBus is done using the strings.
13 */
14#define REGISTRAR_SERVICE "com.canonical.AppMenu.Registrar"_L1
15#define REGISTRAR_PATH "/com/canonical/AppMenu/Registrar"_L1
16
17QDBusMenuBar::QDBusMenuBar()
18 : QPlatformMenuBar()
19 , m_menu(new QDBusPlatformMenu())
20 , m_menuAdaptor(new QDBusMenuAdaptor(m_menu))
21 , m_windowId(0)
22{
23 QDBusMenuItem::registerDBusTypes();
24 connect(sender: m_menu, signal: &QDBusPlatformMenu::propertiesUpdated,
25 context: m_menuAdaptor, slot: &QDBusMenuAdaptor::ItemsPropertiesUpdated);
26 connect(sender: m_menu, signal: &QDBusPlatformMenu::updated,
27 context: m_menuAdaptor, slot: &QDBusMenuAdaptor::LayoutUpdated);
28 connect(sender: m_menu, signal: &QDBusPlatformMenu::popupRequested,
29 context: m_menuAdaptor, slot: &QDBusMenuAdaptor::ItemActivationRequested);
30}
31
32QDBusMenuBar::~QDBusMenuBar()
33{
34 unregisterMenuBar();
35 delete m_menuAdaptor;
36 delete m_menu;
37 qDeleteAll(c: m_menuItems);
38}
39
40QDBusPlatformMenuItem *QDBusMenuBar::menuItemForMenu(QPlatformMenu *menu)
41{
42 if (!menu)
43 return nullptr;
44 quintptr tag = menu->tag();
45 const auto it = m_menuItems.constFind(key: tag);
46 if (it != m_menuItems.cend()) {
47 return *it;
48 } else {
49 QDBusPlatformMenuItem *item = new QDBusPlatformMenuItem;
50 updateMenuItem(item, menu);
51 m_menuItems.insert(key: tag, value: item);
52 return item;
53 }
54}
55
56void QDBusMenuBar::updateMenuItem(QDBusPlatformMenuItem *item, QPlatformMenu *menu)
57{
58 const QDBusPlatformMenu *ourMenu = qobject_cast<const QDBusPlatformMenu *>(object: menu);
59 item->setText(ourMenu->text());
60 item->setIcon(ourMenu->icon());
61 item->setEnabled(ourMenu->isEnabled());
62 item->setVisible(ourMenu->isVisible());
63 item->setMenu(menu);
64}
65
66void QDBusMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before)
67{
68 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu);
69 QDBusPlatformMenuItem *beforeItem = menuItemForMenu(menu: before);
70 m_menu->insertMenuItem(menuItem, before: beforeItem);
71 m_menu->emitUpdated();
72}
73
74void QDBusMenuBar::removeMenu(QPlatformMenu *menu)
75{
76 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu);
77 m_menu->removeMenuItem(menuItem);
78 m_menu->emitUpdated();
79}
80
81void QDBusMenuBar::syncMenu(QPlatformMenu *menu)
82{
83 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu);
84 updateMenuItem(item: menuItem, menu);
85}
86
87void QDBusMenuBar::handleReparent(QWindow *newParentWindow)
88{
89 if (newParentWindow) {
90 unregisterMenuBar();
91 m_windowId = newParentWindow->winId();
92 registerMenuBar();
93 }
94}
95
96QPlatformMenu *QDBusMenuBar::menuForTag(quintptr tag) const
97{
98 QDBusPlatformMenuItem *menuItem = m_menuItems.value(key: tag);
99 if (menuItem)
100 return const_cast<QPlatformMenu *>(menuItem->menu());
101 return nullptr;
102}
103
104QPlatformMenu *QDBusMenuBar::createMenu() const
105{
106 return new QDBusPlatformMenu;
107}
108
109void QDBusMenuBar::registerMenuBar()
110{
111 static uint menuBarId = 0;
112
113 QDBusConnection connection = QDBusConnection::sessionBus();
114 m_objectPath = QStringLiteral("/MenuBar/%1").arg(a: ++menuBarId);
115 if (!connection.registerObject(path: m_objectPath, object: m_menu))
116 return;
117
118 QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, this);
119 QDBusPendingReply<> r = registrar.RegisterWindow(windowId: m_windowId, menuObjectPath: QDBusObjectPath(m_objectPath));
120 r.waitForFinished();
121 if (r.isError()) {
122 qWarning(msg: "Failed to register window menu, reason: %s (\"%s\")",
123 qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message()));
124 connection.unregisterObject(path: m_objectPath);
125 }
126}
127
128void QDBusMenuBar::unregisterMenuBar()
129{
130 QDBusConnection connection = QDBusConnection::sessionBus();
131
132 if (m_windowId) {
133 QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, this);
134 QDBusPendingReply<> r = registrar.UnregisterWindow(windowId: m_windowId);
135 r.waitForFinished();
136 if (r.isError())
137 qWarning(msg: "Failed to unregister window menu, reason: %s (\"%s\")",
138 qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message()));
139 }
140
141 if (!m_objectPath.isEmpty())
142 connection.unregisterObject(path: m_objectPath);
143}
144
145QT_END_NAMESPACE
146
147#include "moc_qdbusmenubar_p.cpp"
148

source code of qtbase/src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp