1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Dmitry Shachnev <mitya57@gmail.com>
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 "qdbusmenubar_p.h"
41 #include "qdbusmenuregistrarproxy_p.h"
42
43 QT_BEGIN_NAMESPACE
44
45 /* note: do not change these to QStringLiteral;
46 we are unloaded before QtDBus is done using the strings.
47 */
48 #define REGISTRAR_SERVICE QLatin1String("com.canonical.AppMenu.Registrar")
49 #define REGISTRAR_PATH QLatin1String("/com/canonical/AppMenu/Registrar")
50
QDBusMenuBar()51 QDBusMenuBar::QDBusMenuBar()
52 : QPlatformMenuBar()
53 , m_menu(new QDBusPlatformMenu())
54 , m_menuAdaptor(new QDBusMenuAdaptor(m_menu))
55 , m_windowId(0)
56 {
57 QDBusMenuItem::registerDBusTypes();
58 connect(m_menu, &QDBusPlatformMenu::propertiesUpdated,
59 m_menuAdaptor, &QDBusMenuAdaptor::ItemsPropertiesUpdated);
60 connect(m_menu, &QDBusPlatformMenu::updated,
61 m_menuAdaptor, &QDBusMenuAdaptor::LayoutUpdated);
62 connect(m_menu, &QDBusPlatformMenu::popupRequested,
63 m_menuAdaptor, &QDBusMenuAdaptor::ItemActivationRequested);
64 }
65
~QDBusMenuBar()66 QDBusMenuBar::~QDBusMenuBar()
67 {
68 unregisterMenuBar();
69 delete m_menuAdaptor;
70 delete m_menu;
71 qDeleteAll(m_menuItems);
72 }
73
menuItemForMenu(QPlatformMenu * menu)74 QDBusPlatformMenuItem *QDBusMenuBar::menuItemForMenu(QPlatformMenu *menu)
75 {
76 if (!menu)
77 return nullptr;
78 quintptr tag = menu->tag();
79 const auto it = m_menuItems.constFind(tag);
80 if (it != m_menuItems.cend()) {
81 return *it;
82 } else {
83 QDBusPlatformMenuItem *item = new QDBusPlatformMenuItem;
84 updateMenuItem(item, menu);
85 m_menuItems.insert(tag, item);
86 return item;
87 }
88 }
89
updateMenuItem(QDBusPlatformMenuItem * item,QPlatformMenu * menu)90 void QDBusMenuBar::updateMenuItem(QDBusPlatformMenuItem *item, QPlatformMenu *menu)
91 {
92 const QDBusPlatformMenu *ourMenu = qobject_cast<const QDBusPlatformMenu *>(menu);
93 item->setText(ourMenu->text());
94 item->setIcon(ourMenu->icon());
95 item->setEnabled(ourMenu->isEnabled());
96 item->setVisible(ourMenu->isVisible());
97 item->setMenu(menu);
98 }
99
insertMenu(QPlatformMenu * menu,QPlatformMenu * before)100 void QDBusMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before)
101 {
102 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu);
103 QDBusPlatformMenuItem *beforeItem = menuItemForMenu(before);
104 m_menu->insertMenuItem(menuItem, beforeItem);
105 m_menu->emitUpdated();
106 }
107
removeMenu(QPlatformMenu * menu)108 void QDBusMenuBar::removeMenu(QPlatformMenu *menu)
109 {
110 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu);
111 m_menu->removeMenuItem(menuItem);
112 m_menu->emitUpdated();
113 }
114
syncMenu(QPlatformMenu * menu)115 void QDBusMenuBar::syncMenu(QPlatformMenu *menu)
116 {
117 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu);
118 updateMenuItem(menuItem, menu);
119 }
120
handleReparent(QWindow * newParentWindow)121 void QDBusMenuBar::handleReparent(QWindow *newParentWindow)
122 {
123 if (newParentWindow) {
124 unregisterMenuBar();
125 m_windowId = newParentWindow->winId();
126 registerMenuBar();
127 }
128 }
129
menuForTag(quintptr tag) const130 QPlatformMenu *QDBusMenuBar::menuForTag(quintptr tag) const
131 {
132 QDBusPlatformMenuItem *menuItem = m_menuItems.value(tag);
133 if (menuItem)
134 return const_cast<QPlatformMenu *>(menuItem->menu());
135 return nullptr;
136 }
137
createMenu() const138 QPlatformMenu *QDBusMenuBar::createMenu() const
139 {
140 return new QDBusPlatformMenu;
141 }
142
registerMenuBar()143 void QDBusMenuBar::registerMenuBar()
144 {
145 static uint menuBarId = 0;
146
147 QDBusConnection connection = QDBusConnection::sessionBus();
148 m_objectPath = QStringLiteral("/MenuBar/%1").arg(++menuBarId);
149 if (!connection.registerObject(m_objectPath, m_menu))
150 return;
151
152 QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, this);
153 QDBusPendingReply<> r = registrar.RegisterWindow(m_windowId, QDBusObjectPath(m_objectPath));
154 r.waitForFinished();
155 if (r.isError()) {
156 qWarning("Failed to register window menu, reason: %s (\"%s\")",
157 qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message()));
158 connection.unregisterObject(m_objectPath);
159 }
160 }
161
unregisterMenuBar()162 void QDBusMenuBar::unregisterMenuBar()
163 {
164 QDBusConnection connection = QDBusConnection::sessionBus();
165
166 if (m_windowId) {
167 QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, this);
168 QDBusPendingReply<> r = registrar.UnregisterWindow(m_windowId);
169 r.waitForFinished();
170 if (r.isError())
171 qWarning("Failed to unregister window menu, reason: %s (\"%s\")",
172 qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message()));
173 }
174
175 if (!m_objectPath.isEmpty())
176 connection.unregisterObject(m_objectPath);
177 }
178
179 QT_END_NAMESPACE
180