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
43QT_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
51QDBusMenuBar::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
66QDBusMenuBar::~QDBusMenuBar()
67{
68 unregisterMenuBar();
69 delete m_menuAdaptor;
70 delete m_menu;
71 qDeleteAll(m_menuItems);
72}
73
74QDBusPlatformMenuItem *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
90void 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
100void 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
108void QDBusMenuBar::removeMenu(QPlatformMenu *menu)
109{
110 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu);
111 m_menu->removeMenuItem(menuItem);
112 m_menu->emitUpdated();
113}
114
115void QDBusMenuBar::syncMenu(QPlatformMenu *menu)
116{
117 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu);
118 updateMenuItem(menuItem, menu);
119}
120
121void QDBusMenuBar::handleReparent(QWindow *newParentWindow)
122{
123 if (newParentWindow) {
124 unregisterMenuBar();
125 m_windowId = newParentWindow->winId();
126 registerMenuBar();
127 }
128}
129
130QPlatformMenu *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
138QPlatformMenu *QDBusMenuBar::createMenu() const
139{
140 return new QDBusPlatformMenu;
141}
142
143void 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
162void 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
179QT_END_NAMESPACE
180