File indexing completed on 2024-11-24 05:00:56
0001 /* 0002 0003 SPDX-FileCopyrightText: 2016 Dmitry Shachnev <mitya57@gmail.com> 0004 SPDX-FileContributor: The Qt Company <https://www.qt.io/licensing/> 0005 0006 SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KFQF-Accepted-GPL OR LicenseRef-Qt-Commercial 0007 0008 */ 0009 0010 #include "qdbusmenubar_p.h" 0011 0012 QT_BEGIN_NAMESPACE 0013 0014 /* note: do not change these to QStringLiteral; 0015 we are unloaded before QtDBus is done using the strings. 0016 */ 0017 #define REGISTRAR_SERVICE QLatin1String("com.canonical.AppMenu.Registrar") 0018 #define REGISTRAR_PATH QLatin1String("/com/canonical/AppMenu/Registrar") 0019 0020 QDBusMenuBar::QDBusMenuBar(KdePlatformTheme *platformTheme) 0021 : QPlatformMenuBar() 0022 , m_menu(new QDBusPlatformMenu()) 0023 , m_menuAdaptor(new QDBusMenuAdaptor(m_menu)) 0024 , m_platformTheme(platformTheme) 0025 { 0026 QDBusMenuItem::registerDBusTypes(); 0027 connect(m_menu, &QDBusPlatformMenu::propertiesUpdated, m_menuAdaptor, &QDBusMenuAdaptor::ItemsPropertiesUpdated); 0028 connect(m_menu, &QDBusPlatformMenu::updated, m_menuAdaptor, &QDBusMenuAdaptor::LayoutUpdated); 0029 connect(m_menu, SIGNAL(popupRequested(int, uint)), m_menuAdaptor, SIGNAL(ItemActivationRequested(int, uint))); 0030 } 0031 0032 QDBusMenuBar::~QDBusMenuBar() 0033 { 0034 if (s_globalMenuBar == this) { 0035 s_globalMenuBar = nullptr; 0036 m_platformTheme->globalMenuBarNoLongerExists(); 0037 } 0038 0039 if (this == s_menuBars.value(m_window)) 0040 s_menuBars.remove(m_window); 0041 0042 unregisterMenuBarX11(m_window); 0043 delete m_menuAdaptor; 0044 delete m_menu; 0045 qDeleteAll(m_menuItems); 0046 } 0047 0048 QDBusPlatformMenuItem *QDBusMenuBar::menuItemForMenu(QPlatformMenu *menu) 0049 { 0050 if (!menu) 0051 return nullptr; 0052 quintptr tag = menu->tag(); 0053 const auto it = m_menuItems.constFind(tag); 0054 if (it != m_menuItems.cend()) { 0055 return *it; 0056 } else { 0057 QDBusPlatformMenuItem *item = new QDBusPlatformMenuItem; 0058 updateMenuItem(item, menu); 0059 m_menuItems.insert(tag, item); 0060 return item; 0061 } 0062 } 0063 0064 void QDBusMenuBar::updateMenuItem(QDBusPlatformMenuItem *item, QPlatformMenu *menu) 0065 { 0066 const QDBusPlatformMenu *ourMenu = qobject_cast<const QDBusPlatformMenu *>(menu); 0067 item->setText(ourMenu->text()); 0068 item->setIcon(ourMenu->icon()); 0069 item->setEnabled(ourMenu->isEnabled()); 0070 item->setVisible(ourMenu->isVisible()); 0071 item->setMenu(menu); 0072 } 0073 0074 void QDBusMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before) 0075 { 0076 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu); 0077 QDBusPlatformMenuItem *beforeItem = menuItemForMenu(before); 0078 m_menu->insertMenuItem(menuItem, beforeItem); 0079 m_menu->emitUpdated(); 0080 } 0081 0082 void QDBusMenuBar::removeMenu(QPlatformMenu *menu) 0083 { 0084 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu); 0085 m_menu->removeMenuItem(menuItem); 0086 m_menu->emitUpdated(); 0087 } 0088 0089 void QDBusMenuBar::syncMenu(QPlatformMenu *menu) 0090 { 0091 QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu); 0092 updateMenuItem(menuItem, menu); 0093 } 0094 0095 void QDBusMenuBar::handleReparent(QWindow *newParentWindow) 0096 { 0097 // if the parent is set to nullptr on our first time around, 0098 // this is supposed to be an app-wide menu bar 0099 // so we only care if nullptr == nullptr after our first round 0100 if (m_initted && newParentWindow == m_window) { 0101 return; 0102 } 0103 m_initted = true; 0104 0105 QWindow *oldWindow = m_window; 0106 0107 if (this == s_menuBars.value(oldWindow)) 0108 s_menuBars.remove(oldWindow); 0109 0110 unregisterMenuBarX11(m_window); 0111 m_window = newParentWindow; 0112 s_menuBars[newParentWindow] = this; 0113 0114 if (newParentWindow) { 0115 if (s_globalMenuBar == this) { 0116 s_globalMenuBar = nullptr; 0117 m_platformTheme->globalMenuBarNoLongerExists(); 0118 } 0119 if (createDBusMenuBar()) { 0120 registerMenuBarX11(m_window, m_objectPath); 0121 } 0122 } else if (!s_globalMenuBar) { 0123 s_globalMenuBar = this; 0124 createDBusMenuBar(); 0125 m_platformTheme->globalMenuBarExistsNow(); 0126 } else { 0127 qWarning() << "There's already a global menu bar..."; 0128 } 0129 0130 Q_EMIT windowChanged(newParentWindow, oldWindow); 0131 } 0132 0133 QDBusMenuBar *QDBusMenuBar::globalMenuBar() 0134 { 0135 return s_globalMenuBar; 0136 } 0137 0138 QPlatformMenu *QDBusMenuBar::menuForTag(quintptr tag) const 0139 { 0140 QDBusPlatformMenuItem *menuItem = m_menuItems.value(tag); 0141 if (menuItem) 0142 return const_cast<QPlatformMenu *>(menuItem->menu()); 0143 return nullptr; 0144 } 0145 0146 QPlatformMenu *QDBusMenuBar::createMenu() const 0147 { 0148 return new QDBusPlatformMenu; 0149 } 0150 0151 bool QDBusMenuBar::createDBusMenuBar() 0152 { 0153 static uint menuBarId = 0; 0154 0155 QDBusConnection connection = QDBusConnection::sessionBus(); 0156 m_objectPath = QStringLiteral("/MenuBar/%1").arg(++menuBarId); 0157 if (!connection.registerObject(m_objectPath, m_menu)) 0158 return false; 0159 0160 return true; 0161 } 0162 void QDBusMenuBar::uncreateDBusMenuBar() 0163 { 0164 QDBusConnection connection = QDBusConnection::sessionBus(); 0165 0166 if (!m_objectPath.isEmpty()) 0167 connection.unregisterObject(m_objectPath); 0168 } 0169 0170 QDBusMenuBar *QDBusMenuBar::menuBarForWindow(QWindow *window) 0171 { 0172 return s_menuBars.value(window); 0173 } 0174 0175 void QDBusMenuBar::registerMenuBarX11(QWindow *window, const QString &objectPath) 0176 { 0177 if (!window) { 0178 qWarning("Cannot register window menu without window"); 0179 return; 0180 } 0181 0182 QDBusConnection connection = QDBusConnection::sessionBus(); 0183 QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, window); 0184 QDBusPendingReply<> r = registrar.RegisterWindow(static_cast<uint>(window->winId()), QDBusObjectPath(objectPath)); 0185 r.waitForFinished(); 0186 if (r.isError()) { 0187 qWarning("Failed to register window menu, reason: %s (\"%s\")", qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message())); 0188 connection.unregisterObject(objectPath); 0189 } 0190 } 0191 0192 QDBusMenuBar *QDBusMenuBar::s_globalMenuBar = nullptr; 0193 QMap<QWindow *, QDBusMenuBar *> QDBusMenuBar::s_menuBars; 0194 0195 void QDBusMenuBar::unregisterMenuBarX11(QWindow *window) 0196 { 0197 if (!window) { 0198 return; 0199 } 0200 0201 QDBusConnection connection = QDBusConnection::sessionBus(); 0202 QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, window); 0203 QDBusPendingReply<> r = registrar.UnregisterWindow(static_cast<uint>(window->winId())); 0204 r.waitForFinished(); 0205 if (r.isError()) 0206 qWarning("Failed to unregister window menu, reason: %s (\"%s\")", qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message())); 0207 } 0208 0209 QT_END_NAMESPACE