Merge lp:~gerboland/qtubuntu/remove-content-hub-and-ual into lp:qtubuntu

Proposed by Gerry Boland
Status: Approved
Approved by: Gerry Boland
Approved revision: 398
Proposed branch: lp:~gerboland/qtubuntu/remove-content-hub-and-ual
Merge into: lp:qtubuntu
Diff against target: 3616 lines (+244/-2858)
31 files modified
debian/control (+15/-34)
debian/qtubuntu-appmenutheme.install (+0/-1)
debian/rules (+0/-1)
src/src.pro (+1/-1)
src/ubuntuappmenu/com.ubuntu.MenuRegistrar.xml (+0/-83)
src/ubuntuappmenu/gmenumodelexporter.cpp (+0/-475)
src/ubuntuappmenu/gmenumodelexporter.h (+0/-100)
src/ubuntuappmenu/gmenumodelplatformmenu.cpp (+0/-518)
src/ubuntuappmenu/gmenumodelplatformmenu.h (+0/-181)
src/ubuntuappmenu/logging.h (+0/-27)
src/ubuntuappmenu/menuregistrar.cpp (+0/-137)
src/ubuntuappmenu/menuregistrar.h (+0/-59)
src/ubuntuappmenu/qtubuntuextraactionhandler.cpp (+0/-107)
src/ubuntuappmenu/qtubuntuextraactionhandler.h (+0/-40)
src/ubuntuappmenu/registry.cpp (+0/-97)
src/ubuntuappmenu/registry.h (+0/-56)
src/ubuntuappmenu/theme.cpp (+0/-67)
src/ubuntuappmenu/theme.h (+0/-36)
src/ubuntuappmenu/themeplugin.cpp (+0/-36)
src/ubuntuappmenu/themeplugin.h (+0/-34)
src/ubuntuappmenu/ubuntuappmenu.json (+0/-3)
src/ubuntuappmenu/ubuntuappmenu.pro (+0/-44)
src/ubuntumirclient/qmirclientclipboard.cpp (+0/-180)
src/ubuntumirclient/qmirclientclipboard.h (+0/-92)
src/ubuntumirclient/qmirclientcursor.cpp (+68/-25)
src/ubuntumirclient/qmirclientintegration.cpp (+74/-117)
src/ubuntumirclient/qmirclientintegration.h (+3/-18)
src/ubuntumirclient/qmirclientplatformservices.cpp (+0/-75)
src/ubuntumirclient/qmirclientplatformservices.h (+0/-57)
src/ubuntumirclient/qmirclientwindow.cpp (+80/-150)
src/ubuntumirclient/ubuntumirclient.pro (+3/-7)
To merge this branch: bzr merge lp:~gerboland/qtubuntu/remove-content-hub-and-ual
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
Alberto Aguirre (community) Approve
Review via email: mp+328528@code.launchpad.net

Commit message

Completely remove dependency on platform-api and content-hub

Use Qt's built-in platform services for URL launching, which platform-api used to deal with.
Totally remove clipboard support

Based on https://code.launchpad.net/~albaguirre/qtubuntu/papi-cleanup/+merge/324886

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

LGTM.

review: Approve
398. By Gerry Boland

Remove another ref to papi

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:398
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/229/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/4930
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4958
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4764
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4764/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4764
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4764/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4764
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4764/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4764
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4764/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4764
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4764/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4764
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4764/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/229/rebuild

review: Approve (continuous-integration)
399. By Gerry Boland

Merge trunk and fix conflicts

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

CI needs to be reconfigured to build against artful

Unmerged revisions

399. By Gerry Boland

Merge trunk and fix conflicts

398. By Gerry Boland

Remove another ref to papi

397. By Gerry Boland

Reduce delta

396. By Gerry Boland

Restore basic platform services

395. By Gerry Boland

Remove clipboard implementation using content-hub

394. By Gerry Boland

Merge papi-cleanup and fix

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2017-01-10 06:41:48 +0000
+++ debian/control 2017-08-25 11:54:50 +0000
@@ -3,17 +3,14 @@
3Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>3Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
4Build-Depends: debhelper (>= 9),4Build-Depends: debhelper (>= 9),
5 libatspi2.0-dev,5 libatspi2.0-dev,
6 libcontent-hub-dev (>= 0.2),6 libegl1-mesa-dev (>= 17.0.2),
7 libegl1-mesa-dev,
8 libfontconfig1-dev,7 libfontconfig1-dev,
9 libfreetype6-dev,8 libfreetype6-dev,
10 libgles2-mesa-dev,9 libgles2-mesa-dev (>= 17.0.2),
11 libglib2.0-dev,10 libglib2.0-dev,
12 libinput-dev,11 libinput-dev,
13 libmirclient-dev (>= 0.25.0),12 libmirclient-dev (>= 0.26.1),
14 libmirclient-debug-extension-dev,
15 libmtdev-dev,13 libmtdev-dev,
16 libubuntu-application-api-dev (>= 2.9.0),
17 libudev-dev,14 libudev-dev,
18 libxkbcommon-dev,15 libxkbcommon-dev,
19 libxrender-dev,16 libxrender-dev,
@@ -30,20 +27,18 @@
30Architecture: arm64 armhf27Architecture: arm64 armhf
31Multi-Arch: same28Multi-Arch: same
32Conflicts: qtubuntu-desktop,29Conflicts: qtubuntu-desktop,
30 qtubuntu-appmenutheme,
33Replaces: qtubuntu (<< 0.52),31Replaces: qtubuntu (<< 0.52),
34 qtubuntu-desktop,32 qtubuntu-desktop,
33 qtubuntu-appmenutheme,
35Breaks: ubuntu-touch-session (<< 0.107),34Breaks: ubuntu-touch-session (<< 0.107),
36 unity8 (<< 7.85),35 unity8 (<< 7.85),
37Provides: qtubuntu,36Provides: qtubuntu,
38Depends: ubuntu-application-api3-touch,37 qtubuntu-appmenutheme
39 ${misc:Depends},38Depends: ${misc:Depends},
40 ${shlibs:Depends},39 ${shlibs:Depends},
41Description: Qt plugins for Ubuntu Platform API (mobile)40Description: Qt plugins for Mir support on Ubuntu (mobile)
42 QtUbuntu is a set of Qt5 components for the Ubuntu Platform API. It contains a41 QtUbuntu is a QPA plugin for Qt5 adding support for the Mir display server.
43 QPA (Qt Platform Abstraction) plugin based on the Ubuntu Platform API and a
44 legacy QPA plugin based on the compatibility layers. It also provides Qt
45 bindings for Ubuntu Platform API features that are not exposed through the QPA
46 plugins.
47 .42 .
48 This variant of the package is for Android-based phones and tablets.43 This variant of the package is for Android-based phones and tablets.
4944
@@ -51,30 +46,16 @@
51Architecture: any46Architecture: any
52Multi-Arch: same47Multi-Arch: same
53Conflicts: qtubuntu-android,48Conflicts: qtubuntu-android,
49 qtubuntu-appmenutheme,
54Replaces: qtubuntu (<< 0.52),50Replaces: qtubuntu (<< 0.52),
55 qtubuntu-android,51 qtubuntu-android,
52 qtubuntu-appmenutheme,
56Breaks: unity8 (<< 7.85),53Breaks: unity8 (<< 7.85),
57Provides: qtubuntu,54Provides: qtubuntu,
58Depends: ubuntu-application-api3-desktop,55 qtubuntu-appmenutheme,
59 ${misc:Depends},56Depends: ${misc:Depends},
60 ${shlibs:Depends},57 ${shlibs:Depends},
61Description: Qt plugins for Ubuntu Platform API (desktop)58Description: Qt plugins for Mir support on Ubuntu (desktop)
62 QtUbuntu is a set of Qt5 components for the Ubuntu Platform API. It contains a59 QtUbuntu is a QPA plugin for Qt5 adding support for the Mir display server.
63 QPA (Qt Platform Abstraction) plugin based on the Ubuntu Platform API and a
64 legacy QPA plugin based on the compatibility layers. It also provides Qt
65 bindings for Ubuntu Platform API features that are not exposed through the QPA
66 plugins.
67 .60 .
68 This variant of the package is for GNU-based desktops.61 This variant of the package is for GNU-based desktops.
69
70Package: qtubuntu-appmenutheme
71Architecture: any
72Multi-Arch: same
73Depends: ${misc:Depends},
74 ${shlibs:Depends},
75Description: Qt platform theme for exported application menus
76 Appmenutheme enables the export of application menus to a global menu bar.
77 It is implemented in a QPA platform theme plugin.
78 .
79 This package will work for applications designed for Qt5, as well as QML
80 applications
8162
=== removed file 'debian/qtubuntu-appmenutheme.install'
--- debian/qtubuntu-appmenutheme.install 2016-06-17 12:40:26 +0000
+++ debian/qtubuntu-appmenutheme.install 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1usr/lib/*/qt5/plugins/platformthemes/*
20
=== modified file 'debian/rules'
--- debian/rules 2016-06-17 12:40:26 +0000
+++ debian/rules 2017-08-25 11:54:50 +0000
@@ -62,4 +62,3 @@
62 dh_install --sourcedir=$(TMP1_DIR) -pqtubuntu-android62 dh_install --sourcedir=$(TMP1_DIR) -pqtubuntu-android
63endif63endif
64 dh_install --sourcedir=$(TMP2_DIR) -pqtubuntu-desktop64 dh_install --sourcedir=$(TMP2_DIR) -pqtubuntu-desktop
65 dh_install --sourcedir=$(TMP2_DIR) -pqtubuntu-appmenutheme
6665
=== modified file 'src/src.pro'
--- src/src.pro 2016-06-21 16:33:19 +0000
+++ src/src.pro 2017-08-25 11:54:50 +0000
@@ -1,3 +1,3 @@
1TEMPLATE = subdirs1TEMPLATE = subdirs
22
3SUBDIRS += ubuntumirclient ubuntuappmenu3SUBDIRS += ubuntumirclient
44
=== removed directory 'src/ubuntuappmenu'
=== removed file 'src/ubuntuappmenu/com.ubuntu.MenuRegistrar.xml'
--- src/ubuntuappmenu/com.ubuntu.MenuRegistrar.xml 2016-09-29 10:24:29 +0000
+++ src/ubuntuappmenu/com.ubuntu.MenuRegistrar.xml 1970-01-01 00:00:00 +0000
@@ -1,83 +0,0 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
2<node xmlns:dox="http://www.ayatana.org/dbus/dox.dtd">
3 <dox:d><![CDATA[
4 @mainpage
5
6 An interface to register menus that are associated with a window in an application. The
7 main interface is documented here: @ref com::ubuntu::MenuRegistrar.
8
9 The actual menus are transported using the gmenumodel protocol
10 ]]></dox:d>
11 <interface name="com.ubuntu.MenuRegistrar" xmlns:dox="http://www.ayatana.org/dbus/dox.dtd">
12 <dox:d>
13 An interface to register a menu from an application to be displayed in another
14 window. This manages that association between processes and/or Mir surface IDs and the dbus
15 address and object that provides the menus using the org.gtk.Menus interface.
16 </dox:d>
17 <method name="RegisterAppMenu">
18 <dox:d><![CDATA[
19 Associates a gmenumodel with an application
20
21 /note this method assumes that the connection from the caller is the DBus connection
22 to use for the object. Applications that use multiple DBus connections will need to
23 ensure this method is called with the same connection that implements the object.
24 ]]></dox:d>
25 <arg name="pid" type="u" direction="in">
26 <dox:d>The process ID of the application for which the menu is associated</dox:d>
27 </arg>
28 <arg name="menuObjectPath" type="o" direction="in">
29 <dox:d>The dbus path where the gmenumodel interface for the application menu has been exported</dox:d>
30 </arg>
31 <arg name="actionObjectPath" type="o" direction="in">
32 <dox:d>The dbus path where the gactionmenu interface for the application menu actions has been exported</dox:d>
33 </arg>
34 <arg name="service" type="s" direction="in">
35 <dox:d>The dbus conection name of the client application to be registered (e.g. :1.23 or org.example.service)</dox:d>
36 </arg>
37 </method>
38 <method name="UnregisterAppMenu">
39 <dox:d>
40 A method to allow removing an application menu from the database.
41 </dox:d>
42 <arg name="pid" type="u" direction="in">
43 <dox:d>The process id of the application</dox:d>
44 </arg>
45 <arg name="menuObjectPath" type="o" direction="in">
46 <dox:d>The dbus path for the registered application menu to be unregistered</dox:d>
47 </arg>
48 </method>
49
50 <method name="RegisterSurfaceMenu">
51 <dox:d><![CDATA[
52 Associates a gmenumodel with a surface
53
54 /note this method assumes that the connection from the caller is the DBus connection
55 to use for the object. Applications that use multiple DBus connections will need to
56 ensure this method is called with the same connection that implements the object.
57 ]]></dox:d>
58 <arg name="surface" type="s" direction="in">
59 <dox:d>The surface ID of the surface</dox:d>
60 </arg>
61 <arg name="menuObjectPath" type="o" direction="in">
62 <dox:d>The dbus path where the gmenumodel interface for the surface menu has been exported</dox:d>
63 </arg>
64 <arg name="actionObjectPath" type="o" direction="in">
65 <dox:d>The dbus path where the gactionmenu interface for the surface menu actions has been exported</dox:d>
66 </arg>
67 <arg name="service" type="s" direction="in">
68 <dox:d>The dbus conection name of the client application to be registered (e.g. :1.23 or org.example.service)</dox:d>
69 </arg>
70 </method>
71 <method name="UnregisterSurfaceMenu">
72 <dox:d>
73 A method to allow removing a surface menu from the database.
74 </dox:d>
75 <arg name="surfaceId" type="s" direction="in">
76 <dox:d>The surface id of the surface</dox:d>
77 </arg>
78 <arg name="menuObjectPath" type="o" direction="in">
79 <dox:d>The dbus path for the registered surface menu to be unregistered</dox:d>
80 </arg>
81 </method>
82 </interface>
83</node>
840
=== removed file 'src/ubuntuappmenu/gmenumodelexporter.cpp'
--- src/ubuntuappmenu/gmenumodelexporter.cpp 2017-03-27 08:23:00 +0000
+++ src/ubuntuappmenu/gmenumodelexporter.cpp 1970-01-01 00:00:00 +0000
@@ -1,475 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Local
18#include "gmenumodelexporter.h"
19#include "registry.h"
20#include "logging.h"
21#include "qtubuntuextraactionhandler.h"
22
23#include <QDebug>
24#include <QTimerEvent>
25
26#include <functional>
27
28namespace {
29
30// Derive an action name from the label by removing spaces and Capitilizing the words.
31// Also remove mnemonics from the label.
32inline QString getActionString(QString label)
33{
34 QRegExp re("\\W");
35 label = label.replace(QRegExp("(&|_)"), "");
36 QStringList parts = label.split(re, QString::SkipEmptyParts);
37
38 QString result;
39 Q_FOREACH(const QString& part, parts) {
40 result += part[0].toUpper();
41 result += part.right(part.length()-1);
42 }
43 return result;
44}
45
46static void activate_cb(GSimpleAction *action, GVariant *, gpointer user_data)
47{
48 qCDebug(ubuntuappmenu, "Activate menu action '%s'", g_action_get_name(G_ACTION(action)));
49 auto item = static_cast<UbuntuPlatformMenuItem*>(user_data);
50 item->activated();
51}
52
53static uint s_menuId = 0;
54
55#define MENU_OBJECT_PATH "/com/ubuntu/Menu/%1"
56
57} // namespace
58
59
60UbuntuMenuBarExporter::UbuntuMenuBarExporter(UbuntuPlatformMenuBar * bar)
61 : UbuntuGMenuModelExporter(bar)
62{
63 qCDebug(ubuntuappmenu, "UbuntuMenuBarExporter::UbuntuMenuBarExporter");
64
65 connect(bar, &UbuntuPlatformMenuBar::structureChanged, this, [this]() {
66 m_structureTimer.start();
67 });
68 connect(&m_structureTimer, &QTimer::timeout, this, [this, bar]() {
69 clear();
70 Q_FOREACH(QPlatformMenu *platformMenu, bar->menus()) {
71 GMenuItem* item = createSubmenu(platformMenu, nullptr);
72 if (item) {
73 g_menu_append_item(m_gmainMenu, item);
74 g_object_unref(item);
75 }
76
77 UbuntuPlatformMenu* gplatformMenu = static_cast<UbuntuPlatformMenu*>(platformMenu);
78 if (gplatformMenu) {
79 // Sadly we don't have a better way to propagate a enabled change in a top level menu
80 // than reseting the whole menubar
81 connect(gplatformMenu, &UbuntuPlatformMenu::enabledChanged, bar, &UbuntuPlatformMenuBar::structureChanged);
82 }
83 }
84 });
85
86 connect(bar, &UbuntuPlatformMenuBar::ready, this, [this]() {
87 exportModels();
88 });
89}
90
91UbuntuMenuBarExporter::~UbuntuMenuBarExporter()
92{
93 qCDebug(ubuntuappmenu, "UbuntuMenuBarExporter::~UbuntuMenuBarExporter");
94}
95
96UbuntuMenuExporter::UbuntuMenuExporter(UbuntuPlatformMenu *menu)
97 : UbuntuGMenuModelExporter(menu)
98{
99 qCDebug(ubuntuappmenu, "UbuntuMenuExporter::UbuntuMenuExporter");
100
101 connect(menu, &UbuntuPlatformMenu::structureChanged, this, [this]() {
102 m_structureTimer.start();
103 });
104 connect(&m_structureTimer, &QTimer::timeout, this, [this, menu]() {
105 clear();
106 addSubmenuItems(menu, m_gmainMenu);
107 });
108 addSubmenuItems(menu, m_gmainMenu);
109}
110
111UbuntuMenuExporter::~UbuntuMenuExporter()
112{
113 qCDebug(ubuntuappmenu, "UbuntuMenuExporter::~UbuntuMenuExporter");
114}
115
116UbuntuGMenuModelExporter::UbuntuGMenuModelExporter(QObject *parent)
117 : QObject(parent)
118 , m_connection(nullptr)
119 , m_gmainMenu(g_menu_new())
120 , m_gactionGroup(g_simple_action_group_new())
121 , m_exportedModel(0)
122 , m_exportedActions(0)
123 , m_qtubuntuExtraHandler(nullptr)
124 , m_menuPath(QStringLiteral(MENU_OBJECT_PATH).arg(s_menuId++))
125{
126 m_structureTimer.setSingleShot(true);
127 m_structureTimer.setInterval(0);
128}
129
130UbuntuGMenuModelExporter::~UbuntuGMenuModelExporter()
131{
132 unexportModels();
133 clear();
134
135 g_object_unref(m_gmainMenu);
136 g_object_unref(m_gactionGroup);
137}
138
139// Clear the menu and actions that have been created.
140void UbuntuGMenuModelExporter::clear()
141{
142 Q_FOREACH(const QVector<QMetaObject::Connection>& menuPropertyConnections, m_propertyConnections) {
143 Q_FOREACH(const QMetaObject::Connection& connection, menuPropertyConnections) {
144 QObject::disconnect(connection);
145 }
146 }
147 m_propertyConnections.clear();
148
149 g_menu_remove_all(m_gmainMenu);
150
151 Q_FOREACH(const QSet<QByteArray>& menuActions, m_actions) {
152 Q_FOREACH(const QByteArray& action, menuActions) {
153 g_action_map_remove_action(G_ACTION_MAP(m_gactionGroup), action.constData());
154 }
155 }
156 m_actions.clear();
157
158 m_gmenusForMenus.clear();
159}
160
161void UbuntuGMenuModelExporter::timerEvent(QTimerEvent *e)
162{
163 // Find the menu, it's a very short list
164 auto it = m_reloadMenuTimers.begin();
165 for (; it != m_reloadMenuTimers.end(); ++it) {
166 if (e->timerId() == it.value())
167 break;
168 }
169
170 if (it != m_reloadMenuTimers.end()) {
171 UbuntuPlatformMenu* gplatformMenu = it.key();
172 GMenu *menu = m_gmenusForMenus.value(gplatformMenu);
173 if (menu) {
174 Q_FOREACH(const QMetaObject::Connection& connection, m_propertyConnections[menu]) {
175 QObject::disconnect(connection);
176 }
177 m_propertyConnections.remove(menu);
178 Q_FOREACH(const QByteArray& action, m_actions[menu]) {
179 g_action_map_remove_action(G_ACTION_MAP(m_gactionGroup), action.constData());
180 }
181 m_actions.remove(menu);
182 g_menu_remove_all(menu);
183 addSubmenuItems(gplatformMenu, menu);
184 } else {
185 qWarning() << "Got an update timer for a menu that has no GMenu" << gplatformMenu;
186 }
187
188 m_reloadMenuTimers.erase(it);
189 } else {
190 qWarning() << "Got an update timer for a timer that was not running";
191 }
192 killTimer(e->timerId());
193}
194
195// Export the model on dbus
196void UbuntuGMenuModelExporter::exportModels()
197{
198 GError *error = nullptr;
199 m_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr, &error);
200 if (!m_connection) {
201 qCWarning(ubuntuappmenu, "Failed to retreive session bus - %s", error ? error->message : "unknown error");
202 g_error_free (error);
203 return;
204 }
205
206 QByteArray menuPath(m_menuPath.toUtf8());
207
208 if (m_exportedModel == 0) {
209 m_exportedModel = g_dbus_connection_export_menu_model(m_connection, menuPath.constData(), G_MENU_MODEL(m_gmainMenu), &error);
210 if (m_exportedModel == 0) {
211 qCWarning(ubuntuappmenu, "Failed to export menu - %s", error ? error->message : "unknown error");
212 g_error_free (error);
213 error = nullptr;
214 } else {
215 qCDebug(ubuntuappmenu, "Exported menu on %s", g_dbus_connection_get_unique_name(m_connection));
216 }
217 }
218
219 if (m_exportedActions == 0) {
220 m_exportedActions = g_dbus_connection_export_action_group(m_connection, menuPath.constData(), G_ACTION_GROUP(m_gactionGroup), &error);
221 if (m_exportedActions == 0) {
222 qCWarning(ubuntuappmenu, "Failed to export actions - %s", error ? error->message : "unknown error");
223 g_error_free (error);
224 error = nullptr;
225 } else {
226 qCDebug(ubuntuappmenu, "Exported actions on %s", g_dbus_connection_get_unique_name(m_connection));
227 }
228 }
229
230 if (!m_qtubuntuExtraHandler) {
231 m_qtubuntuExtraHandler = new QtUbuntuExtraActionHandler();
232 if (!m_qtubuntuExtraHandler->connect(m_connection, menuPath, this)) {
233 delete m_qtubuntuExtraHandler;
234 m_qtubuntuExtraHandler = nullptr;
235 }
236 }
237}
238
239void UbuntuGMenuModelExporter::aboutToShow(quint64 tag)
240{
241 UbuntuPlatformMenu* gplatformMenu = m_submenusWithTag.value(tag);
242 if (!gplatformMenu) {
243 qWarning() << "Got an aboutToShow call with an unknown tag";
244 return;
245 }
246
247 gplatformMenu->aboutToShow();
248}
249
250// Unexport the model
251void UbuntuGMenuModelExporter::unexportModels()
252{
253 GError *error = nullptr;
254 if (!m_connection) {
255 qCWarning(ubuntuappmenu, "Failed to retreive session bus - %s", error ? error->message : "unknown error");
256 return;
257 }
258
259 if (m_exportedModel != 0) {
260 g_dbus_connection_unexport_menu_model(m_connection, m_exportedModel);
261 m_exportedModel = 0;
262 }
263 if (m_exportedActions != 0) {
264 g_dbus_connection_unexport_action_group(m_connection, m_exportedActions);
265 m_exportedActions = 0;
266 }
267 if (m_qtubuntuExtraHandler) {
268 m_qtubuntuExtraHandler->disconnect(m_connection);
269 delete m_qtubuntuExtraHandler;
270 m_qtubuntuExtraHandler = nullptr;
271 }
272 g_object_unref(m_connection);
273 m_connection = nullptr;
274}
275
276// Create a submenu for the given platform menu.
277// Returns a gmenuitem entry for the menu, which must be cleaned up using g_object_unref.
278// If forItem is suplied, use it's label.
279GMenuItem *UbuntuGMenuModelExporter::createSubmenu(QPlatformMenu *platformMenu, UbuntuPlatformMenuItem *forItem)
280{
281 UbuntuPlatformMenu* gplatformMenu = static_cast<UbuntuPlatformMenu*>(platformMenu);
282 if (!gplatformMenu) return nullptr;
283 GMenu* menu = g_menu_new();
284
285 m_gmenusForMenus.insert(gplatformMenu, menu);
286
287 QByteArray label;
288 bool enabled;
289 if (forItem) {
290 label = UbuntuPlatformMenuItem::get_text(forItem).toUtf8();
291 enabled = UbuntuPlatformMenuItem::get_enabled(forItem);
292 } else {
293 label = UbuntuPlatformMenu::get_text(gplatformMenu).toUtf8();
294 enabled = UbuntuPlatformMenu::get_enabled(gplatformMenu);
295 }
296
297 addSubmenuItems(gplatformMenu, menu);
298
299 Q_FOREACH(QPlatformMenuItem *childItem, gplatformMenu->menuItems()) {
300 UbuntuPlatformMenuItem* gplatformMenuItem = static_cast<UbuntuPlatformMenuItem*>(childItem);
301 if (!gplatformMenuItem) continue;
302
303 // Sadly we don't have a better way to propagate a enabled change in a item-that-is-submenu
304 // than reseting the whole parent menu
305 if (gplatformMenuItem->menu()) {
306 connect(gplatformMenuItem, &UbuntuPlatformMenuItem::enabledChanged, gplatformMenu, &UbuntuPlatformMenu::structureChanged);
307 }
308 connect(gplatformMenuItem, &UbuntuPlatformMenuItem::visibleChanged, gplatformMenu, &UbuntuPlatformMenu::structureChanged);
309 }
310
311 GMenuItem* gmenuItem = g_menu_item_new_submenu(label.constData(), G_MENU_MODEL(menu));
312 const quint64 tag = gplatformMenu->tag();
313 if (tag != 0) {
314 g_menu_item_set_attribute_value(gmenuItem, "qtubuntu-tag", g_variant_new_uint64 (tag));
315 m_submenusWithTag.insert(gplatformMenu->tag(), gplatformMenu);
316 }
317 g_object_unref(menu);
318
319 g_menu_item_set_attribute_value(gmenuItem, "submenu-enabled", g_variant_new_boolean(enabled));
320
321 connect(gplatformMenu, &UbuntuPlatformMenu::structureChanged, this, [this, gplatformMenu]
322 {
323 if (!m_reloadMenuTimers.contains(gplatformMenu)) {
324 const int timerId = startTimer(0);
325 m_reloadMenuTimers.insert(gplatformMenu, timerId);
326 }
327 });
328
329 connect(gplatformMenu, &UbuntuPlatformMenu::destroyed, this, [this, tag, gplatformMenu]
330 {
331 m_submenusWithTag.remove(tag);
332 m_gmenusForMenus.remove(gplatformMenu);
333 auto timerIdIt = m_reloadMenuTimers.find(gplatformMenu);
334 if (timerIdIt != m_reloadMenuTimers.end()) {
335 killTimer(*timerIdIt);
336 m_reloadMenuTimers.erase(timerIdIt);
337 }
338 });
339
340 return gmenuItem;
341}
342
343// Add a platform menu's items to the given gmenu.
344// The items are inserted into menus sections, split by the menu separators.
345void UbuntuGMenuModelExporter::addSubmenuItems(UbuntuPlatformMenu* gplatformMenu, GMenu* menu)
346{
347 auto iter = gplatformMenu->menuItems().begin();
348 auto lastSectionStart = iter;
349 // Iterate through all the menu items adding sections when a separator is found.
350 for (; iter != gplatformMenu->menuItems().end(); ++iter) {
351 UbuntuPlatformMenuItem* gplatformMenuItem = static_cast<UbuntuPlatformMenuItem*>(*iter);
352 if (!gplatformMenuItem) continue;
353
354 // don't add a section until we have separator
355 if (UbuntuPlatformMenuItem::get_separator(gplatformMenuItem)) {
356 if (lastSectionStart != gplatformMenu->menuItems().begin()) {
357 GMenuItem* section = createSection(lastSectionStart, iter);
358 g_menu_append_item(menu, section);
359 g_object_unref(section);
360 }
361 lastSectionStart = iter + 1;
362 } else if (lastSectionStart == gplatformMenu->menuItems().begin()) {
363 processItemForGMenu(gplatformMenuItem, menu);
364 }
365 }
366
367 // Add the last section
368 if (lastSectionStart != gplatformMenu->menuItems().begin() &&
369 lastSectionStart != gplatformMenu->menuItems().end()) {
370 GMenuItem* gsectionItem = createSection(lastSectionStart, gplatformMenu->menuItems().end());
371 g_menu_append_item(menu, gsectionItem);
372 g_object_unref(gsectionItem);
373 }
374}
375
376// Create and return a gmenu item for the given platform menu item.
377// Returned GMenuItem must be cleaned up using g_object_unref
378GMenuItem *UbuntuGMenuModelExporter::createMenuItem(QPlatformMenuItem *platformMenuItem, GMenu *parentMenu)
379{
380 UbuntuPlatformMenuItem* gplatformMenuItem = static_cast<UbuntuPlatformMenuItem*>(platformMenuItem);
381 if (!gplatformMenuItem) return nullptr;
382
383 if (!UbuntuPlatformMenuItem::get_visible(gplatformMenuItem))
384 return nullptr;
385
386 QByteArray label(UbuntuPlatformMenuItem::get_text(gplatformMenuItem).toUtf8());
387 QByteArray actionLabel(getActionString(UbuntuPlatformMenuItem::get_text(gplatformMenuItem)).toUtf8());
388 QByteArray shortcut(UbuntuPlatformMenuItem::get_shortcut(gplatformMenuItem).toString(QKeySequence::NativeText).toUtf8());
389
390 GMenuItem* gmenuItem = g_menu_item_new(label.constData(), nullptr);
391 g_menu_item_set_attribute(gmenuItem, "accel", "s", shortcut.constData());
392 g_menu_item_set_detailed_action(gmenuItem, ("unity." + actionLabel).constData());
393
394 addAction(actionLabel, gplatformMenuItem, parentMenu);
395 return gmenuItem;
396}
397
398// Create a menu section for a section of separated menu items.
399// Returned GMenuItem must be cleaned up using g_object_unref
400GMenuItem *UbuntuGMenuModelExporter::createSection(QList<QPlatformMenuItem *>::const_iterator iter, QList<QPlatformMenuItem *>::const_iterator end)
401{
402 GMenu* gsectionMenu = g_menu_new();
403 for (; iter != end; ++iter) {
404 processItemForGMenu(*iter, gsectionMenu);
405 }
406 GMenuItem* gsectionItem = g_menu_item_new_section("", G_MENU_MODEL(gsectionMenu));
407 g_object_unref(gsectionMenu);
408 return gsectionItem;
409}
410
411// Add the given platform menu item to the menu.
412// If it has an attached submenu, then create and add the submenu.
413void UbuntuGMenuModelExporter::processItemForGMenu(QPlatformMenuItem *platformMenuItem, GMenu *gmenu)
414{
415 UbuntuPlatformMenuItem* gplatformMenuItem = static_cast<UbuntuPlatformMenuItem*>(platformMenuItem);
416 if (!gplatformMenuItem) return;
417
418 GMenuItem* gmenuItem = gplatformMenuItem->menu() ? createSubmenu(gplatformMenuItem->menu(), gplatformMenuItem) :
419 createMenuItem(gplatformMenuItem, gmenu);
420 if (gmenuItem) {
421 g_menu_append_item(gmenu, gmenuItem);
422 g_object_unref(gmenuItem);
423 }
424}
425
426// Create and add an action for a menu item.
427void UbuntuGMenuModelExporter::addAction(const QByteArray &name, UbuntuPlatformMenuItem *gplatformMenuItem, GMenu *parentMenu)
428{
429 disconnect(gplatformMenuItem, &UbuntuPlatformMenuItem::checkedChanged, this, 0);
430 disconnect(gplatformMenuItem, &UbuntuPlatformMenuItem::enabledChanged, this, 0);
431
432 QSet<QByteArray> &actions = m_actions[parentMenu];
433 QVector<QMetaObject::Connection> &propertyConnections = m_propertyConnections[parentMenu];
434
435 if (actions.contains(name)) {
436 g_action_map_remove_action(G_ACTION_MAP(m_gactionGroup), name.constData());
437 actions.remove(name);
438 }
439
440 bool checkable = UbuntuPlatformMenuItem::get_checkable(gplatformMenuItem);
441
442 GSimpleAction* action = nullptr;
443 if (checkable) {
444 bool checked = UbuntuPlatformMenuItem::get_checked(gplatformMenuItem);
445 action = g_simple_action_new_stateful(name.constData(), nullptr, g_variant_new_boolean(checked));
446
447 std::function<void(bool)> updateChecked = [gplatformMenuItem, action](bool checked) {
448 auto type = g_action_get_state_type(G_ACTION(action));
449 if (type && g_variant_type_equal(type, G_VARIANT_TYPE_BOOLEAN)) {
450 g_simple_action_set_state(action, g_variant_new_boolean(checked ? TRUE : FALSE));
451 }
452 };
453 // save the connection to disconnect in UbuntuGMenuModelExporter::clear()
454 propertyConnections << connect(gplatformMenuItem, &UbuntuPlatformMenuItem::checkedChanged, this, updateChecked);
455 } else {
456 action = g_simple_action_new(name.constData(), nullptr);
457 }
458
459 // Enabled update
460 std::function<void(bool)> updateEnabled = [gplatformMenuItem, action](bool enabled) {
461 GValue value = G_VALUE_INIT;
462 g_value_init (&value, G_TYPE_BOOLEAN);
463 g_value_set_boolean(&value, enabled ? TRUE : FALSE);
464 g_object_set_property(G_OBJECT(action), "enabled", &value);
465 };
466 updateEnabled(UbuntuPlatformMenuItem::get_enabled(gplatformMenuItem));
467 // save the connection to disconnect in UbuntuGMenuModelExporter::clear()
468 propertyConnections << connect(gplatformMenuItem, &UbuntuPlatformMenuItem::enabledChanged, this, updateEnabled);
469
470 g_signal_connect(action, "activate", G_CALLBACK(activate_cb), gplatformMenuItem);
471
472 actions.insert(name);
473 g_action_map_add_action(G_ACTION_MAP(m_gactionGroup), G_ACTION(action));
474 g_object_unref(action);
475}
4760
=== removed file 'src/ubuntuappmenu/gmenumodelexporter.h'
--- src/ubuntuappmenu/gmenumodelexporter.h 2017-03-15 08:47:51 +0000
+++ src/ubuntuappmenu/gmenumodelexporter.h 1970-01-01 00:00:00 +0000
@@ -1,100 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef GMENUMODELEXPORTER_H
18#define GMENUMODELEXPORTER_H
19
20#include "gmenumodelplatformmenu.h"
21
22#include <gio/gio.h>
23
24#include <QTimer>
25#include <QMap>
26#include <QSet>
27#include <QMetaObject>
28
29class QtUbuntuExtraActionHandler;
30
31// Base class for a gmenumodel exporter
32class UbuntuGMenuModelExporter : public QObject
33{
34 Q_OBJECT
35public:
36 virtual ~UbuntuGMenuModelExporter();
37
38 void exportModels();
39 void unexportModels();
40
41 QString menuPath() const { return m_menuPath;}
42
43 void aboutToShow(quint64 tag);
44
45protected:
46 UbuntuGMenuModelExporter(QObject *parent);
47
48 GMenuItem *createSubmenu(QPlatformMenu* platformMenu, UbuntuPlatformMenuItem* forItem);
49 GMenuItem *createMenuItem(QPlatformMenuItem* platformMenuItem, GMenu *parentMenu);
50 GMenuItem *createSection(QList<QPlatformMenuItem*>::const_iterator iter, QList<QPlatformMenuItem*>::const_iterator end);
51 void addAction(const QByteArray& name, UbuntuPlatformMenuItem* gplatformItem, GMenu *parentMenu);
52
53 void addSubmenuItems(UbuntuPlatformMenu* gplatformMenu, GMenu* menu);
54 void processItemForGMenu(QPlatformMenuItem* item, GMenu* gmenu);
55
56 void clear();
57
58 void timerEvent(QTimerEvent *e) override;
59
60protected:
61 GDBusConnection *m_connection;
62 GMenu *m_gmainMenu;
63 GSimpleActionGroup *m_gactionGroup;
64 guint m_exportedModel;
65 guint m_exportedActions;
66 QtUbuntuExtraActionHandler *m_qtubuntuExtraHandler;
67 QTimer m_structureTimer;
68 QString m_menuPath;
69
70 // UbuntuPlatformMenu::tag -> UbuntuPlatformMenu
71 QMap<quint64, UbuntuPlatformMenu*> m_submenusWithTag;
72
73 // UbuntuPlatformMenu -> reload TimerId (startTimer)
74 QHash<UbuntuPlatformMenu*, int> m_reloadMenuTimers;
75
76 QHash<UbuntuPlatformMenu*, GMenu*> m_gmenusForMenus;
77
78 QHash<GMenu*, QSet<QByteArray>> m_actions;
79 QHash<GMenu*, QVector<QMetaObject::Connection>> m_propertyConnections;
80
81};
82
83// Class which exports a qt platform menu bar.
84class UbuntuMenuBarExporter : public UbuntuGMenuModelExporter
85{
86public:
87 UbuntuMenuBarExporter(UbuntuPlatformMenuBar *parent);
88 ~UbuntuMenuBarExporter();
89};
90
91// Class which exports a qt platform menu.
92// This will allow exporting of context menus.
93class UbuntuMenuExporter : public UbuntuGMenuModelExporter
94{
95public:
96 UbuntuMenuExporter(UbuntuPlatformMenu *parent);
97 ~UbuntuMenuExporter();
98};
99
100#endif // GMENUMODELEXPORTER_H
1010
=== removed file 'src/ubuntuappmenu/gmenumodelplatformmenu.cpp'
--- src/ubuntuappmenu/gmenumodelplatformmenu.cpp 2017-03-27 08:23:00 +0000
+++ src/ubuntuappmenu/gmenumodelplatformmenu.cpp 1970-01-01 00:00:00 +0000
@@ -1,518 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Local
18#include "gmenumodelplatformmenu.h"
19#include "gmenumodelexporter.h"
20#include "registry.h"
21#include "menuregistrar.h"
22#include "logging.h"
23
24// Qt
25#include <QDebug>
26#include <QWindow>
27#include <QCoreApplication>
28
29#define BAR_DEBUG_MSG qCDebug(ubuntuappmenu).nospace() << "UbuntuPlatformMenuBar[" << (void*)this <<"]::" << __func__
30#define MENU_DEBUG_MSG qCDebug(ubuntuappmenu).nospace() << "UbuntuPlatformMenu[" << (void*)this <<"]::" << __func__
31#define ITEM_DEBUG_MSG qCDebug(ubuntuappmenu).nospace() << "UbuntuPlatformMenuItem[" << (void*)this <<"]::" << __func__
32
33namespace {
34
35int logRecusion = 0;
36
37}
38
39QDebug operator<<(QDebug stream, UbuntuPlatformMenuBar* bar) {
40 if (bar) return bar->operator<<(stream);
41 return stream;
42}
43QDebug operator<<(QDebug stream, UbuntuPlatformMenu* menu) {
44 if (menu) return menu->operator<<(stream);
45 return stream;
46}
47QDebug operator<<(QDebug stream, UbuntuPlatformMenuItem* menuItem) {
48 if (menuItem) return menuItem->operator<<(stream);
49 return stream;
50}
51
52UbuntuPlatformMenuBar::UbuntuPlatformMenuBar()
53 : m_exporter(new UbuntuMenuBarExporter(this))
54 , m_registrar(new UbuntuMenuRegistrar())
55 , m_ready(false)
56{
57 BAR_DEBUG_MSG << "()";
58
59 connect(this, &UbuntuPlatformMenuBar::menuInserted, this, &UbuntuPlatformMenuBar::structureChanged);
60 connect(this,&UbuntuPlatformMenuBar::menuRemoved, this, &UbuntuPlatformMenuBar::structureChanged);
61}
62
63UbuntuPlatformMenuBar::~UbuntuPlatformMenuBar()
64{
65 BAR_DEBUG_MSG << "()";
66}
67
68void UbuntuPlatformMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before)
69{
70 BAR_DEBUG_MSG << "(menu=" << menu << ", before=" << before << ")";
71
72 if (m_menus.contains(menu)) return;
73
74 if (!before) {
75 m_menus.push_back(menu);
76 } else {
77 for (auto iter = m_menus.begin(); iter != m_menus.end(); ++iter) {
78 if (*iter == before) {
79 m_menus.insert(iter, menu);
80 break;
81 }
82 }
83 }
84 Q_EMIT menuInserted(menu);
85}
86
87void UbuntuPlatformMenuBar::removeMenu(QPlatformMenu *menu)
88{
89 BAR_DEBUG_MSG << "(menu=" << menu << ")";
90
91 QMutableListIterator<QPlatformMenu*> iterator(m_menus);
92 while(iterator.hasNext()) {
93 if (iterator.next() == menu) {
94 iterator.remove();
95 break;
96 }
97 }
98 Q_EMIT menuRemoved(menu);
99}
100
101void UbuntuPlatformMenuBar::syncMenu(QPlatformMenu *menu)
102{
103 BAR_DEBUG_MSG << "(menu=" << menu << ")";
104
105 Q_UNUSED(menu)
106}
107
108void UbuntuPlatformMenuBar::handleReparent(QWindow *parentWindow)
109{
110 BAR_DEBUG_MSG << "(parentWindow=" << parentWindow << ")";
111
112 setReady(true);
113 m_registrar->registerMenuForWindow(parentWindow, QDBusObjectPath(m_exporter->menuPath()));
114}
115
116QPlatformMenu *UbuntuPlatformMenuBar::menuForTag(quintptr tag) const
117{
118 Q_FOREACH(QPlatformMenu* menu, m_menus) {
119 if (menu->tag() == tag) {
120 return menu;
121 }
122 }
123 return nullptr;
124}
125
126const QList<QPlatformMenu *> UbuntuPlatformMenuBar::menus() const
127{
128 return m_menus;
129}
130
131QDebug UbuntuPlatformMenuBar::operator<<(QDebug stream)
132{
133 stream.nospace().noquote() << QString("%1").arg("", logRecusion, QLatin1Char('\t'))
134 << "UbuntuPlatformMenuBar(this=" << (void*)this << ")" << endl;
135 Q_FOREACH(QPlatformMenu* menu, m_menus) {
136 auto myMenu = static_cast<UbuntuPlatformMenu*>(menu);
137 if (myMenu) {
138 logRecusion++;
139 stream << myMenu;
140 logRecusion--;
141 }
142 }
143
144 return stream;
145}
146
147#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
148QPlatformMenu *UbuntuPlatformMenuBar::createMenu() const
149{
150 return new UbuntuPlatformMenu();
151}
152#endif
153
154void UbuntuPlatformMenuBar::setReady(bool isReady)
155{
156 if (m_ready != isReady) {
157 m_ready = isReady;
158 Q_EMIT ready();
159 }
160}
161
162//////////////////////////////////////////////////////////////
163
164UbuntuPlatformMenu::UbuntuPlatformMenu()
165 : m_tag(reinterpret_cast<quintptr>(this))
166 , m_parentWindow(nullptr)
167 , m_exporter(nullptr)
168 , m_registrar(nullptr)
169{
170 MENU_DEBUG_MSG << "()";
171
172 connect(this, &UbuntuPlatformMenu::menuItemInserted, this, &UbuntuPlatformMenu::structureChanged);
173 connect(this, &UbuntuPlatformMenu::menuItemRemoved, this, &UbuntuPlatformMenu::structureChanged);
174}
175
176UbuntuPlatformMenu::~UbuntuPlatformMenu()
177{
178 MENU_DEBUG_MSG << "()";
179}
180
181void UbuntuPlatformMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
182{
183 MENU_DEBUG_MSG << "(menuItem=" << menuItem << ", before=" << before << ")";
184
185 if (m_menuItems.contains(menuItem)) return;
186
187 if (!before) {
188 m_menuItems.push_back(menuItem);
189 } else {
190 for (auto iter = m_menuItems.begin(); iter != m_menuItems.end(); ++iter) {
191 if (*iter == before) {
192 m_menuItems.insert(iter, menuItem);
193 break;
194 }
195 }
196 }
197
198 Q_EMIT menuItemInserted(menuItem);
199}
200
201void UbuntuPlatformMenu::removeMenuItem(QPlatformMenuItem *menuItem)
202{
203 MENU_DEBUG_MSG << "(menuItem=" << menuItem << ")";
204
205 QMutableListIterator<QPlatformMenuItem*> iterator(m_menuItems);
206 while(iterator.hasNext()) {
207 if (iterator.next() == menuItem) {
208 iterator.remove();
209 break;
210 }
211 }
212 Q_EMIT menuItemRemoved(menuItem);
213}
214
215void UbuntuPlatformMenu::syncMenuItem(QPlatformMenuItem *menuItem)
216{
217 MENU_DEBUG_MSG << "(menuItem=" << menuItem << ")";
218
219 Q_UNUSED(menuItem)
220}
221
222void UbuntuPlatformMenu::syncSeparatorsCollapsible(bool enable)
223{
224 MENU_DEBUG_MSG << "(enable=" << enable << ")";
225 Q_UNUSED(enable)
226}
227
228void UbuntuPlatformMenu::setTag(quintptr tag)
229{
230 MENU_DEBUG_MSG << "(tag=" << tag << ")";
231 m_tag = tag;
232}
233
234quintptr UbuntuPlatformMenu::tag() const
235{
236 return m_tag;
237}
238
239void UbuntuPlatformMenu::setText(const QString &text)
240{
241 MENU_DEBUG_MSG << "(text=" << text << ")";
242 if (m_text != text) {
243 m_text = text;
244 }
245}
246
247void UbuntuPlatformMenu::setIcon(const QIcon &icon)
248{
249 MENU_DEBUG_MSG << "(icon=" << icon.name() << ")";
250
251 if (!icon.isNull() || (!m_icon.isNull() && icon.isNull())) {
252 m_icon = icon;
253 }
254}
255
256void UbuntuPlatformMenu::setEnabled(bool enabled)
257{
258 MENU_DEBUG_MSG << "(enabled=" << enabled << ")";
259
260 if (m_enabled != enabled) {
261 m_enabled = enabled;
262 Q_EMIT enabledChanged(enabled);
263 }
264}
265
266void UbuntuPlatformMenu::setVisible(bool isVisible)
267{
268 MENU_DEBUG_MSG << "(visible=" << isVisible << ")";
269
270 if (m_visible != isVisible) {
271 m_visible = isVisible;
272 }
273}
274
275void UbuntuPlatformMenu::setMinimumWidth(int width)
276{
277 MENU_DEBUG_MSG << "(width=" << width << ")";
278
279 Q_UNUSED(width)
280}
281
282void UbuntuPlatformMenu::setFont(const QFont &font)
283{
284 MENU_DEBUG_MSG << "(font=" << font << ")";
285
286 Q_UNUSED(font)
287}
288
289void UbuntuPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item)
290{
291 MENU_DEBUG_MSG << "(parentWindow=" << parentWindow << ", targetRect=" << targetRect << ", item=" << item << ")";
292
293 if (!m_exporter) {
294 m_exporter.reset(new UbuntuMenuExporter(this));
295 m_exporter->exportModels();
296 }
297
298 if (parentWindow != m_parentWindow) {
299 if (m_parentWindow) {
300 m_registrar->unregisterMenu();
301 }
302
303 m_parentWindow = parentWindow;
304
305 if (m_parentWindow) {
306 if (!m_registrar) m_registrar.reset(new UbuntuMenuRegistrar);
307 m_registrar->registerMenuForWindow(const_cast<QWindow*>(m_parentWindow),
308 QDBusObjectPath(m_exporter->menuPath()));
309 }
310 }
311
312 Q_UNUSED(targetRect);
313 Q_UNUSED(item);
314 setVisible(true);
315}
316
317void UbuntuPlatformMenu::dismiss()
318{
319 MENU_DEBUG_MSG << "()";
320
321 if (m_registrar) { m_registrar->unregisterMenu(); }
322 if (m_exporter) { m_exporter->unexportModels(); }
323}
324
325QPlatformMenuItem *UbuntuPlatformMenu::menuItemAt(int position) const
326{
327 if (position < 0 || position >= m_menuItems.count()) return nullptr;
328 return m_menuItems.at(position);
329}
330
331QPlatformMenuItem *UbuntuPlatformMenu::menuItemForTag(quintptr tag) const
332{
333 Q_FOREACH(QPlatformMenuItem* menuItem, m_menuItems) {
334 if (menuItem->tag() == tag) {
335 return menuItem;
336 }
337 }
338 return nullptr;
339}
340
341QPlatformMenuItem *UbuntuPlatformMenu::createMenuItem() const
342{
343 return new UbuntuPlatformMenuItem();
344}
345
346#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
347QPlatformMenu *UbuntuPlatformMenu::createSubMenu() const
348{
349 return new UbuntuPlatformMenu();
350}
351#endif
352
353const QList<QPlatformMenuItem *> UbuntuPlatformMenu::menuItems() const
354{
355 return m_menuItems;
356}
357
358QDebug UbuntuPlatformMenu::operator<<(QDebug stream)
359{
360 stream.nospace().noquote() << QString("%1").arg("", logRecusion, QLatin1Char('\t'))
361 << "UbuntuPlatformMenu(this=" << (void*)this << ", text=\"" << m_text << "\")" << endl;
362 Q_FOREACH(QPlatformMenuItem* item, m_menuItems) {
363 logRecusion++;
364 auto myItem = static_cast<UbuntuPlatformMenuItem*>(item);
365 if (myItem) {
366 stream << myItem;
367 }
368 logRecusion--;
369 }
370 return stream;
371}
372
373//////////////////////////////////////////////////////////////
374
375UbuntuPlatformMenuItem::UbuntuPlatformMenuItem()
376 : m_menu(nullptr)
377 , m_tag(reinterpret_cast<quintptr>(this))
378{
379 ITEM_DEBUG_MSG << "()";
380}
381
382UbuntuPlatformMenuItem::~UbuntuPlatformMenuItem()
383{
384 ITEM_DEBUG_MSG << "()";
385}
386
387void UbuntuPlatformMenuItem::setTag(quintptr tag)
388{
389 ITEM_DEBUG_MSG << "(tag=" << tag << ")";
390 m_tag = tag;
391}
392
393quintptr UbuntuPlatformMenuItem::tag() const
394{
395 return m_tag;
396}
397
398void UbuntuPlatformMenuItem::setText(const QString &text)
399{
400 ITEM_DEBUG_MSG << "(text=" << text << ")";
401 if (m_text != text) {
402 m_text = text;
403 }
404}
405
406void UbuntuPlatformMenuItem::setIcon(const QIcon &icon)
407{
408 ITEM_DEBUG_MSG << "(icon=" << icon.name() << ")";
409
410 if (!icon.isNull() || (!m_icon.isNull() && icon.isNull())) {
411 m_icon = icon;
412 }
413}
414
415void UbuntuPlatformMenuItem::setVisible(bool isVisible)
416{
417 ITEM_DEBUG_MSG << "(visible=" << isVisible << ")";
418 if (m_visible != isVisible) {
419 m_visible = isVisible;
420 Q_EMIT visibleChanged(m_visible);
421 }
422}
423
424void UbuntuPlatformMenuItem::setIsSeparator(bool isSeparator)
425{
426 ITEM_DEBUG_MSG << "(separator=" << isSeparator << ")";
427 if (m_separator != isSeparator) {
428 m_separator = isSeparator;
429 }
430}
431
432void UbuntuPlatformMenuItem::setFont(const QFont &font)
433{
434 ITEM_DEBUG_MSG << "(font=" << font << ")";
435 Q_UNUSED(font);
436}
437
438void UbuntuPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role)
439{
440 ITEM_DEBUG_MSG << "(role=" << role << ")";
441 Q_UNUSED(role);
442}
443
444void UbuntuPlatformMenuItem::setCheckable(bool checkable)
445{
446 ITEM_DEBUG_MSG << "(checkable=" << checkable << ")";
447 if (m_checkable != checkable) {
448 m_checkable = checkable;
449 }
450}
451
452void UbuntuPlatformMenuItem::setChecked(bool isChecked)
453{
454 ITEM_DEBUG_MSG << "(checked=" << isChecked << ")";
455 if (m_checked != isChecked) {
456 m_checked = isChecked;
457 Q_EMIT checkedChanged(isChecked);
458 }
459}
460
461void UbuntuPlatformMenuItem::setShortcut(const QKeySequence &shortcut)
462{
463 ITEM_DEBUG_MSG << "(shortcut=" << shortcut << ")";
464 if (m_shortcut != shortcut) {
465 m_shortcut = shortcut;
466 }
467}
468
469void UbuntuPlatformMenuItem::setEnabled(bool enabled)
470{
471 ITEM_DEBUG_MSG << "(enabled=" << enabled << ")";
472 if (m_enabled != enabled) {
473 m_enabled = enabled;
474 Q_EMIT enabledChanged(enabled);
475 }
476}
477
478void UbuntuPlatformMenuItem::setIconSize(int size)
479{
480 ITEM_DEBUG_MSG << "(size=" << size << ")";
481 Q_UNUSED(size);
482}
483
484void UbuntuPlatformMenuItem::setMenu(QPlatformMenu *menu)
485{
486 ITEM_DEBUG_MSG << "(menu=" << menu << ")";
487 if (m_menu != menu) {
488 m_menu = menu;
489
490 if (menu) {
491 connect(menu, &QObject::destroyed,
492 this, [this] { setMenu(nullptr); });
493 }
494 }
495}
496
497QPlatformMenu *UbuntuPlatformMenuItem::menu() const
498{
499 return m_menu;
500}
501
502QDebug UbuntuPlatformMenuItem::operator<<(QDebug stream)
503{
504 QString properties = "text=\"" + m_text + "\"";
505
506 stream.nospace().noquote() << QString("%1").arg("", logRecusion, QLatin1Char('\t'))
507 << "UbuntuPlatformMenuItem(this=" << (void*)this << ", "
508 << (m_separator ? "Separator" : properties) << ")" << endl;
509 if (m_menu) {
510 auto myMenu = static_cast<UbuntuPlatformMenu*>(m_menu);
511 if (myMenu) {
512 logRecusion++;
513 stream << myMenu;
514 logRecusion--;
515 }
516 }
517 return stream;
518}
5190
=== removed file 'src/ubuntuappmenu/gmenumodelplatformmenu.h'
--- src/ubuntuappmenu/gmenumodelplatformmenu.h 2017-03-27 08:23:00 +0000
+++ src/ubuntuappmenu/gmenumodelplatformmenu.h 1970-01-01 00:00:00 +0000
@@ -1,181 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef EXPORTEDPLATFORMMENUBAR_H
18#define EXPORTEDPLATFORMMENUBAR_H
19
20#include <qpa/qplatformmenu.h>
21
22// Local
23class UbuntuGMenuModelExporter;
24class UbuntuMenuRegistrar;
25class QWindow;
26
27class UbuntuPlatformMenuBar : public QPlatformMenuBar
28{
29 Q_OBJECT
30public:
31 UbuntuPlatformMenuBar();
32 ~UbuntuPlatformMenuBar();
33
34 QString exportedPath() const;
35
36 virtual void insertMenu(QPlatformMenu *menu, QPlatformMenu* before) override;
37 virtual void removeMenu(QPlatformMenu *menu) override;
38 virtual void syncMenu(QPlatformMenu *menu) override;
39 virtual void handleReparent(QWindow *newParentWindow) override;
40 virtual QPlatformMenu *menuForTag(quintptr tag) const override;
41
42 const QList<QPlatformMenu*> menus() const;
43
44 QDebug operator<<(QDebug stream);
45
46#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
47 virtual QPlatformMenu *createMenu() const override;
48#endif
49
50Q_SIGNALS:
51 void menuInserted(QPlatformMenu *menu);
52 void menuRemoved(QPlatformMenu *menu);
53
54 void structureChanged();
55 void ready();
56
57private:
58 void setReady(bool);
59
60 QList<QPlatformMenu*> m_menus;
61 QScopedPointer<UbuntuGMenuModelExporter> m_exporter;
62 QScopedPointer<UbuntuMenuRegistrar> m_registrar;
63 bool m_ready;
64};
65
66#define MENU_PROPERTY(class, name, type, defaultValue) \
67 static type get_##name(const class *menuItem) { return menuItem->m_##name; } \
68 type m_##name = defaultValue;
69
70class Q_DECL_EXPORT UbuntuPlatformMenu : public QPlatformMenu
71{
72 Q_OBJECT
73public:
74 UbuntuPlatformMenu();
75 ~UbuntuPlatformMenu();
76
77 virtual void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) override;
78 virtual void removeMenuItem(QPlatformMenuItem *menuItem) override;
79 virtual void syncMenuItem(QPlatformMenuItem *menuItem) override;
80 virtual void syncSeparatorsCollapsible(bool enable) override;
81
82 virtual void setTag(quintptr tag) override;
83 virtual quintptr tag() const override;
84
85 virtual void setText(const QString &text) override;
86 virtual void setIcon(const QIcon &icon) override;
87 virtual void setEnabled(bool isEnabled) override;
88 virtual void setVisible(bool isVisible) override;
89 virtual void setMinimumWidth(int width) override;
90 virtual void setFont(const QFont &font) override;
91
92 virtual void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) override;
93
94 virtual void dismiss() override; // Closes this and all its related menu popups
95
96 virtual QPlatformMenuItem *menuItemAt(int position) const override;
97 virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const override;
98
99 virtual QPlatformMenuItem *createMenuItem() const override;
100#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
101 virtual QPlatformMenu *createSubMenu() const override;
102#endif
103
104 int id() const;
105
106 const QList<QPlatformMenuItem*> menuItems() const;
107
108 QDebug operator<<(QDebug stream);
109
110Q_SIGNALS:
111 void menuItemInserted(QPlatformMenuItem *menuItem);
112 void menuItemRemoved(QPlatformMenuItem *menuItem);
113 void structureChanged();
114 void enabledChanged(bool);
115
116private:
117 MENU_PROPERTY(UbuntuPlatformMenu, visible, bool, true)
118 MENU_PROPERTY(UbuntuPlatformMenu, text, QString, QString())
119 MENU_PROPERTY(UbuntuPlatformMenu, enabled, bool, true)
120 MENU_PROPERTY(UbuntuPlatformMenu, icon, QIcon, QIcon())
121
122 quintptr m_tag;
123 QList<QPlatformMenuItem*> m_menuItems;
124 const QWindow* m_parentWindow;
125 QScopedPointer<UbuntuGMenuModelExporter> m_exporter;
126 QScopedPointer<UbuntuMenuRegistrar> m_registrar;
127
128 friend class UbuntuGMenuModelExporter;
129};
130
131
132class Q_DECL_EXPORT UbuntuPlatformMenuItem : public QPlatformMenuItem
133{
134 Q_OBJECT
135public:
136 UbuntuPlatformMenuItem();
137 ~UbuntuPlatformMenuItem();
138
139 virtual void setTag(quintptr tag) override;
140 virtual quintptr tag() const override;
141
142 virtual void setText(const QString &text) override;
143 virtual void setIcon(const QIcon &icon) override;
144 virtual void setMenu(QPlatformMenu *menu) override;
145 virtual void setVisible(bool isVisible) override;
146 virtual void setIsSeparator(bool isSeparator) override;
147 virtual void setFont(const QFont &font) override;
148 virtual void setRole(MenuRole role) override;
149 virtual void setCheckable(bool checkable) override;
150 virtual void setChecked(bool isChecked) override;
151 virtual void setShortcut(const QKeySequence& shortcut) override;
152 virtual void setEnabled(bool enabled) override;
153 virtual void setIconSize(int size) override;
154
155 QPlatformMenu* menu() const;
156
157 QDebug operator<<(QDebug stream);
158
159Q_SIGNALS:
160 void checkedChanged(bool);
161 void enabledChanged(bool);
162 void visibleChanged(bool);
163
164private:
165 MENU_PROPERTY(UbuntuPlatformMenuItem, separator, bool, false)
166 MENU_PROPERTY(UbuntuPlatformMenuItem, visible, bool, true)
167 MENU_PROPERTY(UbuntuPlatformMenuItem, text, QString, QString())
168 MENU_PROPERTY(UbuntuPlatformMenuItem, enabled, bool, true)
169 MENU_PROPERTY(UbuntuPlatformMenuItem, checkable, bool, false)
170 MENU_PROPERTY(UbuntuPlatformMenuItem, checked, bool, false)
171 MENU_PROPERTY(UbuntuPlatformMenuItem, shortcut, QKeySequence, QKeySequence())
172 MENU_PROPERTY(UbuntuPlatformMenuItem, icon, QIcon, QIcon())
173 MENU_PROPERTY(UbuntuPlatformMenuItem, iconSize, int, 16)
174 MENU_PROPERTY(UbuntuPlatformMenuItem, menu, QPlatformMenu*, nullptr)
175
176
177 quintptr m_tag;
178 friend class UbuntuGMenuModelExporter;
179};
180
181#endif // EXPORTEDPLATFORMMENUBAR_H
1820
=== removed file 'src/ubuntuappmenu/logging.h'
--- src/ubuntuappmenu/logging.h 2016-08-24 10:08:05 +0000
+++ src/ubuntuappmenu/logging.h 1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef QUBUNTUTHEMELOGGING_H
18#define QUBUNTUTHEMELOGGING_H
19
20#include <QLoggingCategory>
21
22#define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
23
24Q_DECLARE_LOGGING_CATEGORY(ubuntuappmenu)
25Q_DECLARE_LOGGING_CATEGORY(ubuntuappmenuRegistrar)
26
27#endif // QUBUNTUTHEMELOGGING_H
280
=== removed file 'src/ubuntuappmenu/menuregistrar.cpp'
--- src/ubuntuappmenu/menuregistrar.cpp 2016-09-30 16:10:35 +0000
+++ src/ubuntuappmenu/menuregistrar.cpp 1970-01-01 00:00:00 +0000
@@ -1,137 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "menuregistrar.h"
18#include "registry.h"
19#include "logging.h"
20
21#include <QDebug>
22#include <QDBusObjectPath>
23#include <QGuiApplication>
24#include <qpa/qplatformnativeinterface.h>
25#include <qpa/qplatformwindow.h>
26
27namespace {
28
29bool isMirClient() {
30 return qGuiApp->platformName() == "ubuntumirclient";
31}
32
33}
34
35UbuntuMenuRegistrar::UbuntuMenuRegistrar()
36 : m_connection(nullptr)
37 , m_registeredProcessId(~0)
38{
39 GError *error = NULL;
40 m_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
41 if (!m_connection) {
42 qCWarning(ubuntuappmenuRegistrar, "Failed to retreive session bus - %s", error ? error->message : "unknown error");
43 g_error_free (error);
44 return;
45 }
46 m_service = g_dbus_connection_get_unique_name(m_connection);
47 connect(UbuntuMenuRegistry::instance(), &UbuntuMenuRegistry::serviceChanged, this, &UbuntuMenuRegistrar::onRegistrarServiceChanged);
48
49 if (isMirClient()) {
50 auto nativeInterface = qGuiApp->platformNativeInterface();
51 connect(nativeInterface, &QPlatformNativeInterface::windowPropertyChanged, this, [this](QPlatformWindow* window, const QString &property) {
52 if (property != QStringLiteral("persistentSurfaceId")) {
53 return;
54 }
55 if (window->window() == m_window) {
56 registerMenuForWindow(m_window, m_path);
57 }
58 });
59 }
60}
61
62UbuntuMenuRegistrar::~UbuntuMenuRegistrar()
63{
64 if (m_connection) {
65 g_object_unref(m_connection);
66 }
67 unregisterMenu();
68}
69
70void UbuntuMenuRegistrar::registerMenuForWindow(QWindow* window, const QDBusObjectPath& path)
71{
72 unregisterMenu();
73
74 m_window = window;
75 m_path = path;
76
77 registerMenu();
78}
79
80void UbuntuMenuRegistrar::registerMenu()
81{
82 if (UbuntuMenuRegistry::instance()->isConnected() && m_window) {
83 if (isMirClient()) {
84 registerSurfaceMenu();
85 } else {
86 registerApplicationMenu();
87 }
88 }
89}
90
91void UbuntuMenuRegistrar::unregisterMenu()
92{
93 if (!m_registeredSurfaceId.isEmpty()) {
94 unregisterSurfaceMenu();
95 } else if (m_registeredProcessId != ~0) {
96 unregisterApplicationMenu();
97 }
98}
99
100void UbuntuMenuRegistrar::registerSurfaceMenu()
101{
102 auto nativeInterface = qGuiApp->platformNativeInterface();
103 QByteArray persistentSurfaceId = nativeInterface->windowProperty(m_window->handle(), "persistentSurfaceId", QByteArray()).toByteArray();
104 if (persistentSurfaceId.isEmpty()) return;
105
106 UbuntuMenuRegistry::instance()->registerSurfaceMenu(persistentSurfaceId, m_path, m_service);
107 m_registeredSurfaceId = persistentSurfaceId;
108}
109
110void UbuntuMenuRegistrar::unregisterSurfaceMenu()
111{
112 if (UbuntuMenuRegistry::instance()->isConnected()) {
113 UbuntuMenuRegistry::instance()->unregisterSurfaceMenu(m_registeredSurfaceId, m_path);
114 }
115 m_registeredSurfaceId.clear();
116}
117
118void UbuntuMenuRegistrar::registerApplicationMenu()
119{
120 pid_t pid = getpid();
121 UbuntuMenuRegistry::instance()->registerApplicationMenu(pid, m_path, m_service);
122 m_registeredProcessId = pid;
123}
124
125void UbuntuMenuRegistrar::unregisterApplicationMenu()
126{
127 if (UbuntuMenuRegistry::instance()->isConnected()) {
128 UbuntuMenuRegistry::instance()->unregisterApplicationMenu(m_registeredProcessId, m_path);
129 }
130 m_registeredProcessId = ~0;
131}
132
133void UbuntuMenuRegistrar::onRegistrarServiceChanged()
134{
135 unregisterMenu();
136 registerMenu();
137}
1380
=== removed file 'src/ubuntuappmenu/menuregistrar.h'
--- src/ubuntuappmenu/menuregistrar.h 2016-09-30 08:35:16 +0000
+++ src/ubuntuappmenu/menuregistrar.h 1970-01-01 00:00:00 +0000
@@ -1,59 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MENUREGISTRAR_H
18#define MENUREGISTRAR_H
19
20#include <QObject>
21#include <QWindow>
22#include <QPointer>
23#include <QDBusObjectPath>
24
25#include <gio/gio.h>
26
27class UbuntuMenuRegistrar : public QObject
28{
29 Q_OBJECT
30public:
31 UbuntuMenuRegistrar();
32 ~UbuntuMenuRegistrar();
33
34 void registerMenuForWindow(QWindow* window, const QDBusObjectPath& path);
35 void unregisterMenu();
36
37private Q_SLOTS:
38 void registerSurfaceMenu();
39 void onRegistrarServiceChanged();
40
41private:
42 void registerMenu();
43
44 void registerApplicationMenu();
45 void unregisterApplicationMenu();
46
47 void unregisterSurfaceMenu();
48
49 GDBusConnection *m_connection;
50 QString m_service;
51 QDBusObjectPath m_path;
52 QPointer<QWindow> m_window;
53 QString m_registeredSurfaceId;
54 pid_t m_registeredProcessId;
55};
56
57
58#endif // MENUREGISTRAR_H
59
600
=== removed file 'src/ubuntuappmenu/qtubuntuextraactionhandler.cpp'
--- src/ubuntuappmenu/qtubuntuextraactionhandler.cpp 2017-03-16 09:42:27 +0000
+++ src/ubuntuappmenu/qtubuntuextraactionhandler.cpp 1970-01-01 00:00:00 +0000
@@ -1,107 +0,0 @@
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "qtubuntuextraactionhandler.h"
18
19#include "gmenumodelexporter.h"
20#include "logging.h"
21
22static const gchar introspection_xml[] =
23 "<node>"
24 " <interface name='qtubuntu.actions.extra'>"
25 " <method name='aboutToShow'>"
26 " <arg type='t' name='tag' direction='in'/>"
27 " </method>"
28 " </interface>"
29 "</node>";
30
31static void handle_method_call (GDBusConnection *,
32 const gchar *,
33 const gchar *,
34 const gchar *,
35 const gchar *method_name,
36 GVariant *parameters,
37 GDBusMethodInvocation *invocation,
38 gpointer user_data)
39{
40
41 if (g_strcmp0 (method_name, "aboutToShow") == 0)
42 {
43 if (g_variant_check_format_string(parameters, "(t)", false)) {
44 auto obj = static_cast<UbuntuGMenuModelExporter*>(user_data);
45 guint64 tag;
46
47 g_variant_get (parameters, "(t)", &tag);
48 obj->aboutToShow(tag);
49 }
50
51 g_dbus_method_invocation_return_value (invocation, NULL);
52 } else {
53 g_dbus_method_invocation_return_error(invocation,
54 G_DBUS_ERROR,
55 G_DBUS_ERROR_UNKNOWN_METHOD,
56 "Unknown method");
57 }
58}
59
60
61static const GDBusInterfaceVTable interface_vtable =
62{
63 handle_method_call,
64 NULL,
65 NULL,
66 NULL
67};
68
69QtUbuntuExtraActionHandler::QtUbuntuExtraActionHandler()
70 : m_registration_id(0)
71{
72 m_introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
73}
74
75QtUbuntuExtraActionHandler::~QtUbuntuExtraActionHandler()
76{
77 g_clear_pointer(&m_introspection_data, g_dbus_node_info_unref);
78}
79
80bool QtUbuntuExtraActionHandler::connect(GDBusConnection *connection, const QByteArray &menuPath, UbuntuGMenuModelExporter *gmenuexporter)
81{
82 if (m_registration_id != 0) {
83 qCWarning(ubuntuappmenu, "Called connect in an already connected QtUbuntuExtraActionHandler");
84 return false;
85 }
86
87 GError *error = nullptr;
88 m_registration_id = g_dbus_connection_register_object (connection, menuPath.constData(),
89 m_introspection_data->interfaces[0],
90 &interface_vtable,
91 gmenuexporter,
92 nullptr,
93 &error);
94
95 if (!m_registration_id) {
96 qCWarning(ubuntuappmenu, "Failed to extra actions - %s", error ? error->message : "unknown error");
97 g_clear_error(&error);
98 }
99
100 return m_registration_id != 0;
101}
102
103void QtUbuntuExtraActionHandler::disconnect(GDBusConnection *connection) {
104 if (m_registration_id) {
105 g_dbus_connection_unregister_object (connection, m_registration_id);
106 }
107}
1080
=== removed file 'src/ubuntuappmenu/qtubuntuextraactionhandler.h'
--- src/ubuntuappmenu/qtubuntuextraactionhandler.h 2017-03-06 16:19:29 +0000
+++ src/ubuntuappmenu/qtubuntuextraactionhandler.h 1970-01-01 00:00:00 +0000
@@ -1,40 +0,0 @@
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef QTUBUNTUEXTRAACTIONHANDLER_H
18#define QTUBUNTUEXTRAACTIONHANDLER_H
19
20#include <gio/gio.h>
21
22class QByteArray;
23
24class UbuntuGMenuModelExporter;
25
26class QtUbuntuExtraActionHandler
27{
28public:
29 QtUbuntuExtraActionHandler();
30 ~QtUbuntuExtraActionHandler();
31
32 bool connect(GDBusConnection *connection, const QByteArray &menuPath, UbuntuGMenuModelExporter *gmenuexporter);
33 void disconnect(GDBusConnection *connection);
34
35private:
36 GDBusNodeInfo *m_introspection_data;
37 guint m_registration_id;
38};
39
40#endif
410
=== removed file 'src/ubuntuappmenu/registry.cpp'
--- src/ubuntuappmenu/registry.cpp 2016-09-29 15:12:29 +0000
+++ src/ubuntuappmenu/registry.cpp 1970-01-01 00:00:00 +0000
@@ -1,97 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "registry.h"
18#include "logging.h"
19#include "menuregistrar_interface.h"
20
21#include <QDBusObjectPath>
22#include <QDBusServiceWatcher>
23
24Q_LOGGING_CATEGORY(ubuntuappmenuRegistrar, "ubuntuappmenu.registrar", QtWarningMsg)
25
26#define REGISTRAR_SERVICE "com.ubuntu.MenuRegistrar"
27#define REGISTRY_OBJECT_PATH "/com/ubuntu/MenuRegistrar"
28
29UbuntuMenuRegistry *UbuntuMenuRegistry::instance()
30{
31 static UbuntuMenuRegistry* registry(new UbuntuMenuRegistry());
32 return registry;
33}
34
35UbuntuMenuRegistry::UbuntuMenuRegistry(QObject* parent)
36 : QObject(parent)
37 , m_serviceWatcher(new QDBusServiceWatcher(REGISTRAR_SERVICE, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this))
38 , m_interface(new ComUbuntuMenuRegistrarInterface(REGISTRAR_SERVICE, REGISTRY_OBJECT_PATH, QDBusConnection::sessionBus(), this))
39 , m_connected(m_interface->isValid())
40{
41 connect(m_serviceWatcher.data(), &QDBusServiceWatcher::serviceOwnerChanged, this, &UbuntuMenuRegistry::serviceOwnerChanged);
42}
43
44UbuntuMenuRegistry::~UbuntuMenuRegistry()
45{
46}
47
48void UbuntuMenuRegistry::registerApplicationMenu(pid_t pid, QDBusObjectPath menuObjectPath, const QString &service)
49{
50 qCDebug(ubuntuappmenuRegistrar, "UbuntuMenuRegistry::registerMenu(pid=%d, menuObjectPath=%s, service=%s)",
51 pid,
52 qPrintable(menuObjectPath.path()),
53 qPrintable(service));
54
55 m_interface->RegisterAppMenu(pid, menuObjectPath, menuObjectPath, service);
56}
57
58void UbuntuMenuRegistry::unregisterApplicationMenu(pid_t pid, QDBusObjectPath menuObjectPath)
59{
60 qCDebug(ubuntuappmenuRegistrar, "UbuntuMenuRegistry::unregisterSurfaceMenu(pid=%d, menuObjectPath=%s)",
61 pid,
62 qPrintable(menuObjectPath.path()));
63
64 m_interface->UnregisterAppMenu(pid, menuObjectPath);
65}
66
67void UbuntuMenuRegistry::registerSurfaceMenu(const QString &surfaceId, QDBusObjectPath menuObjectPath, const QString &service)
68{
69 qCDebug(ubuntuappmenuRegistrar, "UbuntuMenuRegistry::registerMenu(surfaceId=%s, menuObjectPath=%s, service=%s)",
70 qPrintable(surfaceId),
71 qPrintable(menuObjectPath.path()),
72 qPrintable(service));
73
74 m_interface->RegisterSurfaceMenu(surfaceId, menuObjectPath, menuObjectPath, service);
75}
76
77void UbuntuMenuRegistry::unregisterSurfaceMenu(const QString &surfaceId, QDBusObjectPath menuObjectPath)
78{
79 qCDebug(ubuntuappmenuRegistrar, "UbuntuMenuRegistry::unregisterSurfaceMenu(surfaceId=%s, menuObjectPath=%s)",
80 qPrintable(surfaceId),
81 qPrintable(menuObjectPath.path()));
82
83 m_interface->UnregisterSurfaceMenu(surfaceId, menuObjectPath);
84}
85
86
87void UbuntuMenuRegistry::serviceOwnerChanged(const QString &serviceName, const QString& oldOwner, const QString &newOwner)
88{
89 qCDebug(ubuntuappmenuRegistrar, "UbuntuMenuRegistry::serviceOwnerChanged(newOwner=%s)", qPrintable(newOwner));
90
91 if (serviceName != REGISTRAR_SERVICE) return;
92
93 if (oldOwner != newOwner) {
94 m_connected = !newOwner.isEmpty();
95 Q_EMIT serviceChanged();
96 }
97}
980
=== removed file 'src/ubuntuappmenu/registry.h'
--- src/ubuntuappmenu/registry.h 2016-09-29 15:03:17 +0000
+++ src/ubuntuappmenu/registry.h 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTU_MENU_REGISTRY_H
18#define UBUNTU_MENU_REGISTRY_H
19
20#include <QObject>
21#include <QScopedPointer>
22
23class ComUbuntuMenuRegistrarInterface;
24class QDBusObjectPath;
25class QDBusServiceWatcher;
26
27class UbuntuMenuRegistry : public QObject
28{
29 Q_OBJECT
30public:
31 UbuntuMenuRegistry(QObject* parent = nullptr);
32 virtual ~UbuntuMenuRegistry();
33
34 static UbuntuMenuRegistry *instance();
35
36 void registerApplicationMenu(pid_t pid, QDBusObjectPath menuObjectPath, const QString &service);
37 void unregisterApplicationMenu(pid_t pid, QDBusObjectPath menuObjectPath);
38
39 void registerSurfaceMenu(const QString &surfaceId, QDBusObjectPath menuObjectPath, const QString &service);
40 void unregisterSurfaceMenu(const QString &surfaceId, QDBusObjectPath menuObjectPath);
41
42 bool isConnected() const { return m_connected; }
43
44Q_SIGNALS:
45 void serviceChanged();
46
47private Q_SLOTS:
48 void serviceOwnerChanged(const QString &serviceName, const QString& oldOwner, const QString &newOwner);
49
50private:
51 QScopedPointer<QDBusServiceWatcher> m_serviceWatcher;
52 QScopedPointer<ComUbuntuMenuRegistrarInterface> m_interface;
53 bool m_connected;
54};
55
56#endif // UBUNTU_MENU_REGISTRY_H
570
=== removed file 'src/ubuntuappmenu/theme.cpp'
--- src/ubuntuappmenu/theme.cpp 2017-03-29 14:16:47 +0000
+++ src/ubuntuappmenu/theme.cpp 1970-01-01 00:00:00 +0000
@@ -1,67 +0,0 @@
1/*
2 * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "theme.h"
18#include "gmenumodelplatformmenu.h"
19#include "logging.h"
20
21#include <QtCore/QVariant>
22#include <QDebug>
23
24Q_LOGGING_CATEGORY(ubuntuappmenu, "ubuntuappmenu", QtWarningMsg)
25const char *UbuntuAppMenuTheme::name = "ubuntuappmenu";
26
27namespace {
28
29bool useLocalMenu() {
30 QByteArray menuProxy = qgetenv("UBUNTU_MENUPROXY");
31 bool menuProxyIsZero = !menuProxy.isEmpty() && menuProxy.at(0) == '0';
32 return menuProxyIsZero;
33}
34
35}
36
37UbuntuAppMenuTheme::UbuntuAppMenuTheme():
38 UbuntuTheme()
39{
40 qCDebug(ubuntuappmenu, "UbuntuAppMenuTheme::UbuntuAppMenuTheme() - useLocalMenu=%s", useLocalMenu() ? "true" : "false");
41}
42
43QPlatformMenuItem *UbuntuAppMenuTheme::createPlatformMenuItem() const
44{
45 if (useLocalMenu()) return QGenericUnixTheme::createPlatformMenuItem();
46 return new UbuntuPlatformMenuItem();
47}
48
49QPlatformMenu *UbuntuAppMenuTheme::createPlatformMenu() const
50{
51 if (useLocalMenu()) return QGenericUnixTheme::createPlatformMenu();
52 return new UbuntuPlatformMenu();
53}
54
55QPlatformMenuBar *UbuntuAppMenuTheme::createPlatformMenuBar() const
56{
57 if (useLocalMenu()) return QGenericUnixTheme::createPlatformMenuBar();
58 return new UbuntuPlatformMenuBar();
59}
60
61QPlatformSystemTrayIcon *UbuntuAppMenuTheme::createPlatformSystemTrayIcon() const
62{
63 // We can't use QGenericUnixTheme implementation since it needs the platformMenu to
64 // be a subclass of QDBusPlatformMenu and ours isn't
65 // TODO Investigate if we're fine with not supporting system trays or we should fix it
66 return nullptr;
67}
680
=== removed file 'src/ubuntuappmenu/theme.h'
--- src/ubuntuappmenu/theme.h 2017-03-29 14:16:47 +0000
+++ src/ubuntuappmenu/theme.h 1970-01-01 00:00:00 +0000
@@ -1,36 +0,0 @@
1/*
2 * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTU_THEME_H
18#define UBUNTU_THEME_H
19
20#include "../shared/ubuntutheme.h"
21
22class UbuntuAppMenuTheme : public UbuntuTheme
23{
24public:
25 static const char* name;
26 UbuntuAppMenuTheme();
27 ~UbuntuAppMenuTheme() = default;
28
29 // For the menus
30 QPlatformMenuItem* createPlatformMenuItem() const override;
31 QPlatformMenu* createPlatformMenu() const override;
32 QPlatformMenuBar* createPlatformMenuBar() const override;
33 QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override;
34};
35
36#endif // UBUNTU_THEME_H
370
=== removed file 'src/ubuntuappmenu/themeplugin.cpp'
--- src/ubuntuappmenu/themeplugin.cpp 2016-09-29 15:03:17 +0000
+++ src/ubuntuappmenu/themeplugin.cpp 1970-01-01 00:00:00 +0000
@@ -1,36 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "themeplugin.h"
18#include "theme.h"
19
20#include <QDebug>
21
22///////////////////////////////////////////////////////////
23
24UbuntuAppMenuThemePlugin::UbuntuAppMenuThemePlugin(QObject *parent)
25 : QPlatformThemePlugin(parent)
26{
27}
28
29QPlatformTheme *
30UbuntuAppMenuThemePlugin::create(const QString &key, const QStringList&)
31{
32 if (key.compare(QLatin1String(UbuntuAppMenuTheme::name), Qt::CaseInsensitive))
33 return 0;
34
35 return new UbuntuAppMenuTheme();
36}
370
=== removed file 'src/ubuntuappmenu/themeplugin.h'
--- src/ubuntuappmenu/themeplugin.h 2016-06-21 16:33:19 +0000
+++ src/ubuntuappmenu/themeplugin.h 1970-01-01 00:00:00 +0000
@@ -1,34 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTUTHEMEPLUGIN_H
18#define UBUNTUTHEMEPLUGIN_H
19
20#include <qpa/qplatformthemeplugin.h>
21
22class UbuntuAppMenuThemePlugin : public QPlatformThemePlugin
23{
24 Q_OBJECT
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformThemeFactoryInterface.5.1" FILE "ubuntuappmenu.json")
26public:
27 UbuntuAppMenuThemePlugin(QObject *parent = 0);
28
29 virtual QPlatformTheme *create(const QString &key, const QStringList &paramList);
30
31 static const char *name;
32};
33
34#endif
350
=== removed file 'src/ubuntuappmenu/ubuntuappmenu.json'
--- src/ubuntuappmenu/ubuntuappmenu.json 2016-06-21 16:33:19 +0000
+++ src/ubuntuappmenu/ubuntuappmenu.json 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
1{
2 "Keys": [ "ubuntuappmenu" ]
3}
40
=== removed file 'src/ubuntuappmenu/ubuntuappmenu.pro'
--- src/ubuntuappmenu/ubuntuappmenu.pro 2017-07-07 08:17:58 +0000
+++ src/ubuntuappmenu/ubuntuappmenu.pro 1970-01-01 00:00:00 +0000
@@ -1,44 +0,0 @@
1TARGET = ubuntuappmenu
2TEMPLATE = lib
3
4QT -= gui
5QT += core-private theme_support-private dbus
6
7CONFIG += plugin no_keywords
8
9# CONFIG += c++11 # only enables C++0x
10QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall
11QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined
12
13CONFIG += link_pkgconfig
14PKGCONFIG += gio-2.0
15
16DBUS_INTERFACES += com.ubuntu.MenuRegistrar.xml
17
18HEADERS += \
19 theme.h \
20 gmenumodelexporter.h \
21 gmenumodelplatformmenu.h \
22 logging.h \
23 menuregistrar.h \
24 registry.h \
25 themeplugin.h \
26 qtubuntuextraactionhandler.h \
27 ../shared/ubuntutheme.h
28
29SOURCES += \
30 theme.cpp \
31 gmenumodelexporter.cpp \
32 gmenumodelplatformmenu.cpp \
33 menuregistrar.cpp \
34 registry.cpp \
35 themeplugin.cpp \
36 qtubuntuextraactionhandler.cpp
37
38OTHER_FILES += \
39 ubuntuappmenu.json
40
41# Installation path
42target.path += $$[QT_INSTALL_PLUGINS]/platformthemes
43
44INSTALLS += target
450
=== removed file 'src/ubuntumirclient/qmirclientclipboard.cpp'
--- src/ubuntumirclient/qmirclientclipboard.cpp 2017-03-02 10:49:22 +0000
+++ src/ubuntumirclient/qmirclientclipboard.cpp 1970-01-01 00:00:00 +0000
@@ -1,180 +0,0 @@
1/****************************************************************************
2**
3** Copyright (C) 2016 Canonical, Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins 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
41#include "qmirclientclipboard.h"
42#include "qmirclientlogging.h"
43#include "qmirclientwindow.h"
44
45#include <QDBusPendingCallWatcher>
46#include <QGuiApplication>
47#include <QSignalBlocker>
48#include <QtCore/QMimeData>
49#include <QtCore/QStringList>
50
51// content-hub
52#include <com/ubuntu/content/hub.h>
53
54// get this cumbersome nested namespace out of the way
55using namespace com::ubuntu::content;
56
57QMirClientClipboard::QMirClientClipboard()
58 : mMimeData(new QMimeData)
59 , mContentHub(Hub::Client::instance())
60{
61 connect(mContentHub, &Hub::pasteboardChanged, this, [this]() {
62 if (mClipboardState == QMirClientClipboard::SyncedClipboard) {
63 mClipboardState = QMirClientClipboard::OutdatedClipboard;
64 emitChanged(QClipboard::Clipboard);
65 }
66 });
67
68 connect(qGuiApp, &QGuiApplication::applicationStateChanged,
69 this, &QMirClientClipboard::onApplicationStateChanged);
70
71 requestMimeData();
72}
73
74QMirClientClipboard::~QMirClientClipboard()
75{
76 delete mMimeData;
77}
78
79QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode)
80{
81 if (mode != QClipboard::Clipboard)
82 return nullptr;
83
84 // Blocks dataChanged() signal from being emitted. Makes no sense to emit it from
85 // inside the data getter.
86 const QSignalBlocker blocker(this);
87
88 if (mClipboardState == OutdatedClipboard) {
89 updateMimeData();
90 } else if (mClipboardState == SyncingClipboard) {
91 mPasteReply->waitForFinished();
92 }
93
94 return mMimeData;
95}
96
97void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode)
98{
99 QWindow *focusWindow = QGuiApplication::focusWindow();
100 if (focusWindow && mode == QClipboard::Clipboard && mimeData != nullptr) {
101 QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
102
103 QDBusPendingCall reply = mContentHub->createPaste(surfaceId, *mimeData);
104
105 // Don't care whether it succeeded
106 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
107 connect(watcher, &QDBusPendingCallWatcher::finished,
108 watcher, &QObject::deleteLater);
109
110 mMimeData = mimeData;
111 mClipboardState = SyncedClipboard;
112 emitChanged(QClipboard::Clipboard);
113 }
114}
115
116bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const
117{
118 return mode == QClipboard::Clipboard;
119}
120
121bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const
122{
123 Q_UNUSED(mode);
124 return false;
125}
126
127void QMirClientClipboard::onApplicationStateChanged(Qt::ApplicationState state)
128{
129 if (state == Qt::ApplicationActive) {
130 // Only focused or active applications might be allowed to paste, so we probably
131 // missed changes in the clipboard while we were hidden, inactive or, more importantly,
132 // suspended.
133 requestMimeData();
134 }
135}
136
137void QMirClientClipboard::updateMimeData()
138{
139 if (qGuiApp->applicationState() != Qt::ApplicationActive) {
140 // Don't even bother asking as content-hub would probably ignore our request (and should).
141 return;
142 }
143
144 QWindow *focusWindow = QGuiApplication::focusWindow();
145 if (focusWindow) {
146 delete mMimeData;
147 QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
148 mMimeData = mContentHub->latestPaste(surfaceId);
149 mClipboardState = SyncedClipboard;
150 emitChanged(QClipboard::Clipboard);
151 }
152}
153
154void QMirClientClipboard::requestMimeData()
155{
156 if (qGuiApp->applicationState() != Qt::ApplicationActive) {
157 // Don't even bother asking as content-hub would probably ignore our request (and should).
158 return;
159 }
160
161 QWindow *focusWindow = QGuiApplication::focusWindow();
162 if (!focusWindow) {
163 return;
164 }
165
166 QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
167 QDBusPendingCall reply = mContentHub->requestLatestPaste(surfaceId);
168 mClipboardState = SyncingClipboard;
169
170 mPasteReply = new QDBusPendingCallWatcher(reply, this);
171 connect(mPasteReply, &QDBusPendingCallWatcher::finished,
172 this, [this]() {
173 delete mMimeData;
174 mMimeData = mContentHub->paste(*mPasteReply);
175 mClipboardState = SyncedClipboard;
176 mPasteReply->deleteLater();
177 mPasteReply = nullptr;
178 emitChanged(QClipboard::Clipboard);
179 });
180}
1810
=== removed file 'src/ubuntumirclient/qmirclientclipboard.h'
--- src/ubuntumirclient/qmirclientclipboard.h 2017-02-07 15:37:20 +0000
+++ src/ubuntumirclient/qmirclientclipboard.h 1970-01-01 00:00:00 +0000
@@ -1,92 +0,0 @@
1/****************************************************************************
2**
3** Copyright (C) 2016 Canonical, Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins 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
41#ifndef QMIRCLIENTCLIPBOARD_H
42#define QMIRCLIENTCLIPBOARD_H
43
44#include <qpa/qplatformclipboard.h>
45
46#include <QMimeData>
47#include <QPointer>
48
49namespace com {
50 namespace ubuntu {
51 namespace content {
52 class Hub;
53 }
54 }
55}
56
57class QDBusPendingCallWatcher;
58
59class QMirClientClipboard : public QObject, public QPlatformClipboard
60{
61 Q_OBJECT
62public:
63 QMirClientClipboard();
64 virtual ~QMirClientClipboard();
65
66 // QPlatformClipboard methods.
67 QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
68 void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override;
69 bool supportsMode(QClipboard::Mode mode) const override;
70 bool ownsMode(QClipboard::Mode mode) const override;
71
72private Q_SLOTS:
73 void onApplicationStateChanged(Qt::ApplicationState state);
74
75private:
76 void updateMimeData();
77 void requestMimeData();
78
79 QMimeData *mMimeData;
80
81 enum {
82 OutdatedClipboard, // Our mimeData is outdated, need to fetch latest from ContentHub
83 SyncingClipboard, // Our mimeData is outdated and we are waiting for ContentHub to reply with the latest paste
84 SyncedClipboard // Our mimeData is in sync with what ContentHub has
85 } mClipboardState{OutdatedClipboard};
86
87 com::ubuntu::content::Hub *mContentHub;
88
89 QDBusPendingCallWatcher *mPasteReply{nullptr};
90};
91
92#endif // QMIRCLIENTCLIPBOARD_H
930
=== modified file 'src/ubuntumirclient/qmirclientcursor.cpp'
--- src/ubuntumirclient/qmirclientcursor.cpp 2017-03-28 17:12:13 +0000
+++ src/ubuntumirclient/qmirclientcursor.cpp 2017-08-25 11:54:50 +0000
@@ -138,11 +138,17 @@
138{138{
139public:139public:
140 CursorWindowSpec(MirConnection *connection, const char *name)140 CursorWindowSpec(MirConnection *connection, const char *name)
141 : spec(mir_create_window_spec(connection))141 : CursorWindowSpec(connection)
142 {142 {
143 mir_window_spec_set_cursor_name(spec, name);143 mir_window_spec_set_cursor_name(spec, name);
144 }144 }
145145
146 CursorWindowSpec(MirConnection *connection, MirRenderSurface *surface, int hotspotX, int hotspotY)
147 : CursorWindowSpec(connection)
148 {
149 mir_window_spec_set_cursor_render_surface(spec, surface, hotspotX, hotspotY);
150 }
151
146 ~CursorWindowSpec()152 ~CursorWindowSpec()
147 {153 {
148 mir_window_spec_release(spec);154 mir_window_spec_release(spec);
@@ -153,8 +159,60 @@
153 mir_window_apply_spec(window, spec);159 mir_window_apply_spec(window, spec);
154 }160 }
155private:161private:
162 CursorWindowSpec(MirConnection *connection) : spec(mir_create_window_spec(connection)) {}
156 MirWindowSpec * const spec;163 MirWindowSpec * const spec;
157};164};
165
166class BufferStream
167{
168public:
169 BufferStream(MirRenderSurface *surface, int width, int height)
170 : stream(mir_render_surface_get_buffer_stream(surface, width, height, mir_pixel_format_argb_8888))
171 {
172 }
173
174 void draw(QImage const& image)
175 {
176 MirGraphicsRegion region;
177 const bool validRegion = mir_buffer_stream_get_graphics_region(stream, &region);
178 if (!validRegion)
179 throw std::runtime_error("Could not get graphics region to draw into");
180
181 auto regionLine = region.vaddr;
182 Q_ASSERT(image.bytesPerLine() <= region.stride);
183
184 for (int i = 0; i < image.height(); ++i) {
185 memcpy(regionLine, image.scanLine(i), image.bytesPerLine());
186 regionLine += region.stride;
187 }
188 mir_buffer_stream_swap_buffers_sync(stream);
189 }
190
191private:
192 MirBufferStream * const stream;
193};
194
195class RenderSurface
196{
197public:
198 RenderSurface(MirConnection *connection, int width, int height)
199 : surface(mir_connection_create_render_surface_sync(connection, width, height)),
200 stream(surface, width, height)
201 {
202 if (!mir_render_surface_is_valid(surface)) {
203 throw std::runtime_error(mir_render_surface_get_error_message(surface));
204 }
205 }
206
207 ~RenderSurface() { mir_render_surface_release(surface); }
208 operator MirRenderSurface *() const { return surface; }
209 void draw(QImage const& image) { stream.draw(image); }
210
211private:
212 MirRenderSurface * const surface;
213 BufferStream stream;
214};
215
158} // anonymous namespace216} // anonymous namespace
159217
160void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)218void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)
@@ -196,30 +254,15 @@
196 image = image.convertToFormat(QImage::Format_ARGB32);254 image = image.convertToFormat(QImage::Format_ARGB32);
197 }255 }
198256
199 MirBufferStream *bufferStream = mir_connection_create_buffer_stream_sync(mConnection,257 try {
200 image.width(), image.height(), mir_pixel_format_argb_8888, mir_buffer_usage_software);258 RenderSurface surface(mConnection, image.width(), image.height());
201259 surface.draw(image);
202 {260
203 MirGraphicsRegion region;261 CursorWindowSpec spec(mConnection, surface, cursor.hotSpot().x(), cursor.hotSpot().y());
204 mir_buffer_stream_get_graphics_region(bufferStream, &region);262 spec.apply(window);
205263 } catch(std::exception const& e) {
206 char *regionLine = region.vaddr;264 qWarning("Error applying pixmap cursor: %s", e.what());
207 Q_ASSERT(image.bytesPerLine() <= region.stride);265 }
208 for (int i = 0; i < image.height(); ++i) {
209 memcpy(regionLine, image.scanLine(i), image.bytesPerLine());
210 regionLine += region.stride;
211 }
212 }
213
214 mir_buffer_stream_swap_buffers_sync(bufferStream);
215
216 {
217 auto configuration = mir_cursor_configuration_from_buffer_stream(bufferStream, cursor.hotSpot().x(), cursor.hotSpot().y());
218 mir_window_configure_cursor(window, configuration);
219 mir_cursor_configuration_destroy(configuration);
220 }
221
222 mir_buffer_stream_release_sync(bufferStream);
223}266}
224267
225void QMirClientCursor::applyDefaultCursorConfiguration(MirWindow *window)268void QMirClientCursor::applyDefaultCursorConfiguration(MirWindow *window)
226269
=== modified file 'src/ubuntumirclient/qmirclientintegration.cpp'
--- src/ubuntumirclient/qmirclientintegration.cpp 2017-07-07 08:17:58 +0000
+++ src/ubuntumirclient/qmirclientintegration.cpp 2017-08-25 11:54:50 +0000
@@ -41,7 +41,6 @@
41// Local41// Local
42#include "qmirclientintegration.h"42#include "qmirclientintegration.h"
43#include "qmirclientbackingstore.h"43#include "qmirclientbackingstore.h"
44#include "qmirclientclipboard.h"
45#include "qmirclientdebugextension.h"44#include "qmirclientdebugextension.h"
46#include "qmirclientdesktopwindow.h"45#include "qmirclientdesktopwindow.h"
47#include "qmirclientglcontext.h"46#include "qmirclientglcontext.h"
@@ -61,67 +60,93 @@
61#include <QtEglSupport/private/qeglconvenience_p.h>60#include <QtEglSupport/private/qeglconvenience_p.h>
62#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>61#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
63#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>62#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
63#include <QtServiceSupport/private/qgenericunixservices_p.h>
64#include <QtEglSupport/private/qeglpbuffer_p.h>64#include <QtEglSupport/private/qeglpbuffer_p.h>
65#include <QtLinuxAccessibilitySupport/private/bridge_p.h>65#include <QtLinuxAccessibilitySupport/private/bridge_p.h>
66#include <QOpenGLContext>66#include <QOpenGLContext>
67#include <QOffscreenSurface>67#include <QOffscreenSurface>
6868
69// platform-api69namespace
70#include <ubuntu/application/lifecycle_delegate.h>70{
71#include <ubuntu/application/id.h>71class UbuntuIconTheme : public QGenericUnixTheme
72#include <ubuntu/application/options.h>72{
7373public:
74static void resumedCallback(const UApplicationOptions */*options*/, void *context)74 UbuntuIconTheme()
75{75 {}
76 auto integration = static_cast<QMirClientClientIntegration*>(context);76
77 integration->appStateController()->setResumed();77 // From QPlatformTheme
78 QVariant themeHint(ThemeHint hint) const override
79 {
80 if (hint == QPlatformTheme::SystemIconThemeName)
81 {
82 QByteArray iconTheme = qgetenv("QTUBUNTU_ICON_THEME");
83 if (iconTheme.isEmpty())
84 {
85 return QVariant(QStringLiteral("ubuntu-mobile"));
86 }
87 else
88 {
89 return QVariant(QString(iconTheme));
90 }
91 }
92 else
93 {
94 return QGenericUnixTheme::themeHint(hint);
95 }
96 }
97};
98
99QByteArray generateSessionNameFromQmlFile(QStringList &args)
100{
101 Q_FOREACH (QString arg, args) {
102 if (arg.endsWith(".qml")) {
103 QFileInfo fileInfo(arg);
104 return fileInfo.fileName().toLocal8Bit();
105 }
106 }
107
108 // give up
109 return "qmlscene";
78}110}
79111
80static void aboutToStopCallback(UApplicationArchive */*archive*/, void *context)112QByteArray generateSessionName(QStringList args)
81{113{
82 auto integration = static_cast<QMirClientClientIntegration*>(context);114 // Try to come up with some meaningful session name to uniquely identify this session,
83 auto inputContext = integration->inputContext();115 // helping with shell debugging
84 if (inputContext) {116 if (args.count() == 0) {
85 inputContext->hideInputPanel();117 return QByteArray("QtUbuntu");
118 } if (args[0].contains("qmlscene")) {
119 return generateSessionNameFromQmlFile(args);
86 } else {120 } else {
87 qCWarning(mirclient) << "aboutToStopCallback(): no input context";121 // use the executable name
122 QFileInfo fileInfo(args[0]);
123 return fileInfo.fileName().toLocal8Bit();
88 }124 }
89 integration->appStateController()->setSuspended();
90}125}
91126
127MirConnection *make_mir_connection()
128{
129 auto sessionName = generateSessionName(QCoreApplication::arguments());
130 auto mirConnection = mir_connect_sync(nullptr, sessionName.data());
131 if (!mir_connection_is_valid(mirConnection))
132 {
133 qCritical("Mir returned: \"%s\"", mir_connection_get_error_message(mirConnection));
134 mir_connection_release(mirConnection);
135 exit(EXIT_FAILURE);
136 }
137 return mirConnection;
138}
139}
92140
93QMirClientClientIntegration::QMirClientClientIntegration(int argc, char **argv)141QMirClientClientIntegration::QMirClientClientIntegration(int argc, char **argv)
94 : QPlatformIntegration()142 : QPlatformIntegration()
95 , mNativeInterface(new QMirClientNativeInterface(this))143 , mNativeInterface(new QMirClientNativeInterface(this))
96 , mFontDb(new QGenericUnixFontDatabase)144 , mFontDb(new QGenericUnixFontDatabase)
97 , mServices(new QMirClientPlatformServices)145 , mPlatformServices(new QGenericUnixServices)
98 , mAppStateController(new QMirClientAppStateController)146 , mAppStateController(new QMirClientAppStateController)
99 , mScaleFactor(1.0)147 , mScaleFactor(1.0)
148 , mMirConnection(make_mir_connection())
100{149{
101 QByteArray sessionName;
102 {
103 QStringList args = QCoreApplication::arguments();
104 setupOptions(args);
105 sessionName = generateSessionName(args);
106 setupDescription(sessionName);
107 }
108
109 // Create new application instance
110 mInstance = u_application_instance_new_from_description_with_options(mDesc, mOptions);
111
112 if (mInstance == nullptr) {
113 qCritical("[QPA] QMirClientClientIntegration: connection to Mir server failed.\n");
114
115 // TODO: add API to platform-api to fetch Mir's error message (bug:1655970).
116 // Workaround by retrying the connection here in order to get the message.
117 auto mirConnection = mir_connect_sync(nullptr, sessionName.data());
118 qCritical("Mir returned: \"%s\"", mir_connection_get_error_message(mirConnection));
119 mir_connection_release(mirConnection);
120 exit(EXIT_FAILURE);
121 }
122
123 mMirConnection = u_application_instance_get_mir_connection(mInstance);
124
125 // Choose the default surface format suited to the Mir platform150 // Choose the default surface format suited to the Mir platform
126 QSurfaceFormat defaultFormat;151 QSurfaceFormat defaultFormat;
127 defaultFormat.setRedBufferSize(8);152 defaultFormat.setRedBufferSize(8);
@@ -130,8 +155,7 @@
130 QSurfaceFormat::setDefaultFormat(defaultFormat);155 QSurfaceFormat::setDefaultFormat(defaultFormat);
131156
132 // Initialize EGL.157 // Initialize EGL.
133 mEglNativeDisplay = mir_connection_get_egl_native_display(mMirConnection);158 ASSERT((mEglDisplay = eglGetDisplay(mMirConnection)) != EGL_NO_DISPLAY);
134 ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY);
135 ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);159 ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);
136160
137 // Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var161 // Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var
@@ -185,70 +209,7 @@
185 eglTerminate(mEglDisplay);209 eglTerminate(mEglDisplay);
186 delete mInput;210 delete mInput;
187 delete mInputContext;211 delete mInputContext;
188 delete mServices;212 mir_connection_release(mMirConnection);
189}
190
191QPlatformServices *QMirClientClientIntegration::services() const
192{
193 return mServices;
194}
195
196void QMirClientClientIntegration::setupOptions(QStringList &args)
197{
198 int argc = args.size() + 1;
199 char **argv = new char*[argc];
200 for (int i = 0; i < argc - 1; i++)
201 argv[i] = qstrdup(args.at(i).toLocal8Bit());
202 argv[argc - 1] = nullptr;
203
204 mOptions = u_application_options_new_from_cmd_line(argc - 1, argv);
205
206 for (int i = 0; i < argc; i++)
207 delete [] argv[i];
208 delete [] argv;
209}
210
211void QMirClientClientIntegration::setupDescription(QByteArray &sessionName)
212{
213 mDesc = u_application_description_new();
214
215 UApplicationId* id = u_application_id_new_from_stringn(sessionName.data(), sessionName.count());
216 u_application_description_set_application_id(mDesc, id);
217
218 UApplicationLifecycleDelegate* delegate = u_application_lifecycle_delegate_new();
219 u_application_lifecycle_delegate_set_application_resumed_cb(delegate, &resumedCallback);
220 u_application_lifecycle_delegate_set_application_about_to_stop_cb(delegate, &aboutToStopCallback);
221 u_application_lifecycle_delegate_set_context(delegate, this);
222 u_application_description_set_application_lifecycle_delegate(mDesc, delegate);
223}
224
225QByteArray QMirClientClientIntegration::generateSessionName(QStringList &args)
226{
227 // Try to come up with some meaningful session name to uniquely identify this session,
228 // helping with shell debugging
229
230 if (args.count() == 0) {
231 return QByteArray("QtUbuntu");
232 } if (args[0].contains("qmlscene")) {
233 return generateSessionNameFromQmlFile(args);
234 } else {
235 // use the executable name
236 QFileInfo fileInfo(args[0]);
237 return fileInfo.fileName().toLocal8Bit();
238 }
239}
240
241QByteArray QMirClientClientIntegration::generateSessionNameFromQmlFile(QStringList &args)
242{
243 Q_FOREACH (QString arg, args) {
244 if (arg.endsWith(".qml")) {
245 QFileInfo fileInfo(arg);
246 return fileInfo.fileName().toLocal8Bit();
247 }
248 }
249
250 // give up
251 return "qmlscene";
252}213}
253214
254QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const215QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const
@@ -262,6 +223,11 @@
262 }223 }
263}224}
264225
226QPlatformServices *QMirClientClientIntegration::services() const
227{
228 return mPlatformServices.data();
229}
230
265bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const231bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const
266{232{
267 switch (cap) {233 switch (cap) {
@@ -350,15 +316,6 @@
350 return QPlatformIntegration::styleHint(hint);316 return QPlatformIntegration::styleHint(hint);
351}317}
352318
353QPlatformClipboard* QMirClientClientIntegration::clipboard() const
354{
355 static QPlatformClipboard *clipboard = nullptr;
356 if (!clipboard) {
357 clipboard = new QMirClientClipboard;
358 }
359 return clipboard;
360}
361
362QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const319QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const
363{320{
364 return mNativeInterface;321 return mNativeInterface;
365322
=== modified file 'src/ubuntumirclient/qmirclientintegration.h'
--- src/ubuntumirclient/qmirclientintegration.h 2017-03-15 09:21:47 +0000
+++ src/ubuntumirclient/qmirclientintegration.h 2017-08-25 11:54:50 +0000
@@ -45,13 +45,8 @@
45#include <QSharedPointer>45#include <QSharedPointer>
4646
47#include "qmirclientappstatecontroller.h"47#include "qmirclientappstatecontroller.h"
48#include "qmirclientplatformservices.h"
49#include "qmirclientscreenobserver.h"48#include "qmirclientscreenobserver.h"
5049
51// platform-api
52#include <ubuntu/application/description.h>
53#include <ubuntu/application/instance.h>
54
55#include <EGL/egl.h>50#include <EGL/egl.h>
5651
57class QMirClientDebugExtension;52class QMirClientDebugExtension;
@@ -81,7 +76,6 @@
81 QPlatformServices *services() const override;76 QPlatformServices *services() const override;
82 QPlatformWindow* createPlatformWindow(QWindow* window) const override;77 QPlatformWindow* createPlatformWindow(QWindow* window) const override;
83 QPlatformInputContext* inputContext() const override { return mInputContext; }78 QPlatformInputContext* inputContext() const override { return mInputContext; }
84 QPlatformClipboard* clipboard() const override;
85 void initialize() override;79 void initialize() override;
86 QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;80 QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
87 QPlatformAccessibility *accessibility() const override;81 QPlatformAccessibility *accessibility() const override;
@@ -89,7 +83,7 @@
89 // New methods.83 // New methods.
90 MirConnection *mirConnection() const { return mMirConnection; }84 MirConnection *mirConnection() const { return mMirConnection; }
91 EGLDisplay eglDisplay() const { return mEglDisplay; }85 EGLDisplay eglDisplay() const { return mEglDisplay; }
92 EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }86 EGLNativeDisplayType eglNativeDisplay() const { return mMirConnection; }
93 QMirClientAppStateController *appStateController() const { return mAppStateController.data(); }87 QMirClientAppStateController *appStateController() const { return mAppStateController.data(); }
94 QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); }88 QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); }
95 QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); }89 QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); }
@@ -100,32 +94,23 @@
100private:94private:
101 void setupOptions(QStringList &args);95 void setupOptions(QStringList &args);
102 void setupDescription(QByteArray &sessionName);96 void setupDescription(QByteArray &sessionName);
103 static QByteArray generateSessionName(QStringList &args);
104 static QByteArray generateSessionNameFromQmlFile(QStringList &args);
10597
106 QMirClientNativeInterface* mNativeInterface;98 QMirClientNativeInterface* mNativeInterface;
107 QPlatformFontDatabase* mFontDb;99 QPlatformFontDatabase* mFontDb;
108100
109 QMirClientPlatformServices* mServices;
110
111 QMirClientInput* mInput;101 QMirClientInput* mInput;
112 QPlatformInputContext* mInputContext;102 QPlatformInputContext* mInputContext;
113 mutable QScopedPointer<QPlatformAccessibility> mAccessibility;103 mutable QScopedPointer<QPlatformAccessibility> mAccessibility;
104 const QScopedPointer<QPlatformServices> mPlatformServices;
105 const QScopedPointer<QMirClientAppStateController> mAppStateController;
114 QScopedPointer<QMirClientDebugExtension> mDebugExtension;106 QScopedPointer<QMirClientDebugExtension> mDebugExtension;
115 QScopedPointer<QMirClientScreenObserver> mScreenObserver;107 QScopedPointer<QMirClientScreenObserver> mScreenObserver;
116 QScopedPointer<QMirClientAppStateController> mAppStateController;
117 qreal mScaleFactor;108 qreal mScaleFactor;
118109
119 MirConnection *mMirConnection;110 MirConnection *mMirConnection;
120111
121 // Platform API stuff
122 UApplicationOptions* mOptions;
123 UApplicationDescription* mDesc;
124 UApplicationInstance* mInstance;
125
126 // EGL related112 // EGL related
127 EGLDisplay mEglDisplay{EGL_NO_DISPLAY};113 EGLDisplay mEglDisplay{EGL_NO_DISPLAY};
128 EGLNativeDisplayType mEglNativeDisplay;
129};114};
130115
131#endif // QMIRCLIENTINTEGRATION_H116#endif // QMIRCLIENTINTEGRATION_H
132117
=== removed file 'src/ubuntumirclient/qmirclientplatformservices.cpp'
--- src/ubuntumirclient/qmirclientplatformservices.cpp 2017-02-07 15:37:20 +0000
+++ src/ubuntumirclient/qmirclientplatformservices.cpp 1970-01-01 00:00:00 +0000
@@ -1,75 +0,0 @@
1/****************************************************************************
2**
3** Copyright (C) 2016 Canonical, Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins 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
41#include "qmirclientplatformservices.h"
42
43#include <QUrl>
44
45#include <ubuntu/application/url_dispatcher/service.h>
46#include <ubuntu/application/url_dispatcher/session.h>
47
48bool QMirClientPlatformServices::openUrl(const QUrl &url)
49{
50 return callDispatcher(url);
51}
52
53bool QMirClientPlatformServices::openDocument(const QUrl &url)
54{
55 return callDispatcher(url);
56}
57
58bool QMirClientPlatformServices::callDispatcher(const QUrl &url)
59{
60 UAUrlDispatcherSession* session = ua_url_dispatcher_session();
61 if (!session)
62 return false;
63
64 ua_url_dispatcher_session_open(session, url.toEncoded().constData(), NULL, NULL);
65
66 free(session);
67
68 // We are returning true here because the other option
69 // is spawning a nested event loop and wait for the
70 // callback. But there is no guarantee on how fast
71 // the callback is going to be so we prefer to avoid the
72 // nested event loop. Long term plan is improve Qt API
73 // to support an async openUrl
74 return true;
75}
760
=== removed file 'src/ubuntumirclient/qmirclientplatformservices.h'
--- src/ubuntumirclient/qmirclientplatformservices.h 2017-07-07 08:17:58 +0000
+++ src/ubuntumirclient/qmirclientplatformservices.h 1970-01-01 00:00:00 +0000
@@ -1,57 +0,0 @@
1/****************************************************************************
2**
3** Copyright (C) 2016 Canonical, Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins 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
41#ifndef QMIRCLIENTPLATFORMSERVICES_H
42#define QMIRCLIENTPLATFORMSERVICES_H
43
44#include <qpa/qplatformservices.h>
45#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
46#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
47
48class QMirClientPlatformServices : public QPlatformServices {
49public:
50 bool openUrl(const QUrl &url) override;
51 bool openDocument(const QUrl &url) override;
52
53private:
54 bool callDispatcher(const QUrl &url);
55};
56
57#endif // QMIRCLIENTPLATFORMSERVICES_H
580
=== modified file 'src/ubuntumirclient/qmirclientwindow.cpp'
--- src/ubuntumirclient/qmirclientwindow.cpp 2017-07-07 08:17:58 +0000
+++ src/ubuntumirclient/qmirclientwindow.cpp 2017-08-25 11:54:50 +0000
@@ -75,12 +75,6 @@
7575
76using Spec = std::unique_ptr<MirWindowSpec, MirSpecDeleter>;76using Spec = std::unique_ptr<MirWindowSpec, MirSpecDeleter>;
7777
78EGLNativeWindowType nativeWindowFor(MirWindow *surf)
79{
80 auto stream = mir_window_get_buffer_stream(surf);
81 return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream));
82}
83
84const char *qtWindowStateToStr(Qt::WindowState state)78const char *qtWindowStateToStr(Qt::WindowState state)
85{79{
86 switch (state) {80 switch (state) {
@@ -114,24 +108,6 @@
114 Q_UNREACHABLE();108 Q_UNREACHABLE();
115}109}
116110
117const char *mirPixelFormatToStr(MirPixelFormat pixelFormat)
118{
119 switch (pixelFormat) {
120 case mir_pixel_format_invalid: return "invalid";
121 case mir_pixel_format_abgr_8888: return "ABGR8888";
122 case mir_pixel_format_xbgr_8888: return "XBGR8888";
123 case mir_pixel_format_argb_8888: return "ARGB8888";
124 case mir_pixel_format_xrgb_8888: return "XRGB8888";
125 case mir_pixel_format_bgr_888: return "BGR888";
126 case mir_pixel_format_rgb_888: return "RGB888";
127 case mir_pixel_format_rgb_565: return "RGB565";
128 case mir_pixel_format_rgba_5551: return "RGBA5551";
129 case mir_pixel_format_rgba_4444: return "RGBA4444";
130 case mir_pixel_formats: Q_UNREACHABLE();
131 }
132 Q_UNREACHABLE();
133}
134
135const char *mirWindowTypeToStr(MirWindowType type)111const char *mirWindowTypeToStr(MirWindowType type)
136{112{
137 switch (type) {113 switch (type) {
@@ -221,12 +197,23 @@
221 return requiresParent(qtWindowTypeToMirWindowType(type));197 return requiresParent(qtWindowTypeToMirWindowType(type));
222}198}
223199
224Spec makeSurfaceSpec(QWindow *window, MirPixelFormat pixelFormat, QMirClientWindow *parentWindowHandle,200QRect geometryFor(QWindow *window)
225 MirConnection *connection)201{
226{202 auto geometry = window->geometry();
227 const auto geometry = window->geometry();203 if (geometry.width() < 1)
228 const int width = geometry.width() > 0 ? geometry.width() : 1;204 geometry.setWidth(1);
229 const int height = geometry.height() > 0 ? geometry.height() : 1;205 if (geometry.height() < 1)
206 geometry.setHeight(1);
207
208 return geometry;
209}
210
211Spec makeWindowSpec(QWindow *window, QMirClientWindow *parentWindowHandle,
212 MirRenderSurface *surface, MirConnection *connection)
213{
214 const auto geometry = geometryFor(window);
215 const int width = geometry.width();
216 const int height = geometry.height();
230 auto type = qtWindowTypeToMirWindowType(window->type());217 auto type = qtWindowTypeToMirWindowType(window->type());
231218
232 MirRectangle location{geometry.x(), geometry.y(), 0, 0};219 MirRectangle location{geometry.x(), geometry.y(), 0, 0};
@@ -272,7 +259,6 @@
272 // There's no helper function for satellite windows. Guess they're not very popular259 // There's no helper function for satellite windows. Guess they're not very popular
273 spec = Spec{mir_create_window_spec(connection)};260 spec = Spec{mir_create_window_spec(connection)};
274 mir_window_spec_set_type(spec.get(), mir_window_type_satellite);261 mir_window_spec_set_type(spec.get(), mir_window_type_satellite);
275 mir_window_spec_set_buffer_usage(spec.get(), mir_buffer_usage_hardware);
276 mir_window_spec_set_parent(spec.get(), parent);262 mir_window_spec_set_parent(spec.get(), parent);
277 mir_window_spec_set_width(spec.get(), width);263 mir_window_spec_set_width(spec.get(), width);
278 mir_window_spec_set_height(spec.get(), height);264 mir_window_spec_set_height(spec.get(), height);
@@ -282,9 +268,9 @@
282 break;268 break;
283 }269 }
284270
285 mir_window_spec_set_pixel_format(spec.get(), pixelFormat);271 mir_window_spec_add_render_surface(spec.get(), surface, width, height, 0, 0);
286272
287 qCDebug(mirclient, "makeSurfaceSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)",273 qCDebug(mirclient, "makeWindowSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)",
288 window, mirWindowTypeToStr(type), window->type(), location.left, location.top, width, height);274 window, mirWindowTypeToStr(type), window->type(), location.left, location.top, width, height);
289275
290 return spec;276 return spec;
@@ -331,14 +317,29 @@
331 mir_window_spec_set_input_shape(spec, rects, count);317 mir_window_spec_set_input_shape(spec, rects, count);
332}318}
333319
320MirRenderSurface *createMirSurface(QWindow *window, MirConnection *connection)
321{
322 const auto geometry = geometryFor(window);
323 const int width = geometry.width();
324 const int height = geometry.height();
325
326 auto surface = mir_connection_create_render_surface_sync(connection, width, height);
327 if (!mir_render_surface_is_valid(surface))
328 {
329 auto errorMsg = mir_render_surface_get_error_message(surface);
330 qFatal("Failed to create mir surface: %s", errorMsg);
331 }
332 return surface;
333}
334
334MirWindow *createMirWindow(QWindow *window, int mirOutputId, QMirClientWindow *parentWindowHandle,335MirWindow *createMirWindow(QWindow *window, int mirOutputId, QMirClientWindow *parentWindowHandle,
335 MirPixelFormat pixelFormat, MirConnection *connection,336 MirRenderSurface *surface, MirConnection *connection,
336 MirWindowEventCallback inputCallback, void *inputContext)337 MirWindowEventCallback eventCallback, void *context)
337{338{
338 auto spec = makeSurfaceSpec(window, pixelFormat, parentWindowHandle, connection);339 auto spec = makeWindowSpec(window, parentWindowHandle, surface, connection);
339340
340 // Install event handler as early as possible341 // Install event handler as early as possible
341 mir_window_spec_set_event_handler(spec.get(), inputCallback, inputContext);342 mir_window_spec_set_event_handler(spec.get(), eventCallback, context);
342343
343 const auto title = window->title().toUtf8();344 const auto title = window->title().toUtf8();
344 mir_window_spec_set_name(spec.get(), title.constData());345 mir_window_spec_set_name(spec.get(), title.constData());
@@ -358,9 +359,14 @@
358 mir_window_spec_set_state(spec.get(), mir_window_state_hidden);359 mir_window_spec_set_state(spec.get(), mir_window_state_hidden);
359 }360 }
360361
361 auto surface = mir_create_window_sync(spec.get());362 auto mirWindow = mir_create_window_sync(spec.get());
362 Q_ASSERT(mir_window_is_valid(surface));363 if (!mir_window_is_valid(mirWindow))
363 return surface;364 {
365 auto errorMsg = mir_window_get_error_message(mirWindow);
366 qFatal("Failed to create mir window: %s", errorMsg);
367 }
368
369 return mirWindow;
364}370}
365371
366QMirClientWindow *getParentIfNecessary(QWindow *window, QMirClientInput *input)372QMirClientWindow *getParentIfNecessary(QWindow *window, QMirClientInput *input)
@@ -377,18 +383,6 @@
377 return parentWindowHandle;383 return parentWindowHandle;
378}384}
379385
380MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat)
381{
382 switch (pixelFormat) {
383 case mir_pixel_format_abgr_8888:
384 return mir_pixel_format_xbgr_8888;
385 case mir_pixel_format_argb_8888:
386 return mir_pixel_format_xrgb_8888;
387 default: // can do nothing, leave it alone
388 return pixelFormat;
389 }
390}
391
392// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633386// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
393// we need to guess the panel height (3GU)387// we need to guess the panel height (3GU)
394int panelHeight()388int panelHeight()
@@ -426,7 +420,6 @@
426420
427 void onSwapBuffersDone();421 void onSwapBuffersDone();
428 void handleSurfaceResized(int width, int height);422 void handleSurfaceResized(int width, int height);
429 int needsRepaint() const;
430423
431 MirWindowState state() const { return mir_window_get_state(mMirWindow); }424 MirWindowState state() const { return mir_window_get_state(mMirWindow); }
432 void setState(MirWindowState state);425 void setState(MirWindowState state);
@@ -448,7 +441,7 @@
448 QString persistentSurfaceId();441 QString persistentSurfaceId();
449442
450private:443private:
451 static void surfaceEventCallback(MirWindow* surface, const MirEvent *event, void* context);444 static void windowEventCallback(MirWindow* surface, const MirEvent *event, void* context);
452 void postEvent(const MirEvent *event);445 void postEvent(const MirEvent *event);
453446
454 QWindow * const mWindow;447 QWindow * const mWindow;
@@ -458,14 +451,12 @@
458 QMirClientWindow * mParentWindowHandle{nullptr};451 QMirClientWindow * mParentWindowHandle{nullptr};
459452
460 MirWindow* mMirWindow;453 MirWindow* mMirWindow;
454 MirRenderSurface* mMirSurface;
461 const EGLDisplay mEglDisplay;455 const EGLDisplay mEglDisplay;
462 EGLSurface mEglSurface;456 EGLSurface mEglSurface;
463457
464 bool mNeedsRepaint;
465 bool mParented;458 bool mParented;
466 QSize mBufferSize;
467 QSurfaceFormat mFormat;459 QSurfaceFormat mFormat;
468 MirPixelFormat mPixelFormat;
469460
470 QMutex mTargetSizeMutex;461 QMutex mTargetSizeMutex;
471 QSize mTargetSize;462 QSize mTargetSize;
@@ -479,7 +470,6 @@
479 , mInput(input)470 , mInput(input)
480 , mConnection(connection)471 , mConnection(connection)
481 , mEglDisplay(display)472 , mEglDisplay(display)
482 , mNeedsRepaint(false)
483 , mParented(mWindow->transientParent() || mWindow->parent())473 , mParented(mWindow->transientParent() || mWindow->parent())
484 , mFormat(mWindow->requestedFormat())474 , mFormat(mWindow->requestedFormat())
485 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)475 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
@@ -506,50 +496,33 @@
506496
507 mFormat = q_glFormatFromConfig(display, config, mFormat);497 mFormat = q_glFormatFromConfig(display, config, mFormat);
508498
509 // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way
510 // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers.
511 mPixelFormat = mir_connection_get_egl_pixel_format(connection, display, config);
512 // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client.
513 // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer.
514 // This is an optimization for the compositor, as it can avoid blending this surface.
515 if (mWindow->requestedFormat().alphaBufferSize() < 0) {
516 mPixelFormat = disableAlphaBufferIfPossible(mPixelFormat);
517 }
518
519 const auto outputId = static_cast<QMirClientScreen *>(mWindow->screen()->handle())->mirOutputId();499 const auto outputId = static_cast<QMirClientScreen *>(mWindow->screen()->handle())->mirOutputId();
520500
521 mParentWindowHandle = getParentIfNecessary(mWindow, input);501 mParentWindowHandle = getParentIfNecessary(mWindow, input);
522502
523 mMirWindow = createMirWindow(mWindow, outputId, mParentWindowHandle, mPixelFormat, connection, surfaceEventCallback, this);503 mMirSurface = createMirSurface(mWindow, connection);
524 mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirWindow), nullptr);504 mMirWindow = createMirWindow(mWindow, outputId, mParentWindowHandle, mMirSurface, connection, windowEventCallback, this);
505 mEglSurface = eglCreateWindowSurface(mEglDisplay, config, reinterpret_cast<EGLNativeWindowType>(mMirSurface), nullptr);
525506
526 mNeedsExposeCatchup = mir_window_get_visibility(mMirWindow) == mir_window_visibility_occluded;507 mNeedsExposeCatchup = mir_window_get_visibility(mMirWindow) == mir_window_visibility_occluded;
527508
528 // Window manager can give us a final size different from what we asked for509 // Assume that the buffer size matches the surface size at creation time
529 // so let's check what we ended up getting
530 MirWindowParameters parameters;
531 mir_window_get_parameters(mMirWindow, &parameters);
532
533 auto geom = mWindow->geometry();510 auto geom = mWindow->geometry();
534 geom.setWidth(parameters.width);
535 geom.setHeight(parameters.height);
536
537 // Assume that the buffer size matches the surface size at creation time
538 mBufferSize = geom.size();
539 platformWindow->QPlatformWindow::setGeometry(geom);
540 QWindowSystemInterface::handleGeometryChange(mWindow, geom);
541511
542 qCDebug(mirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title();512 qCDebug(mirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title();
543 qCDebug(mirclientGraphics)513 qCDebug(mirclientGraphics)
544 << "Requested format:" << mWindow->requestedFormat()514 << "Requested format:" << mWindow->requestedFormat()
545 << "\nActual format:" << mFormat515 << "\nActual format:" << mFormat;
546 << "with associated Mir pixel format:" << mirPixelFormatToStr(mPixelFormat);
547}516}
548517
549UbuntuSurface::~UbuntuSurface()518UbuntuSurface::~UbuntuSurface()
550{519{
551 if (mEglSurface != EGL_NO_SURFACE)520 if (mEglSurface != EGL_NO_SURFACE) {
552 eglDestroySurface(mEglDisplay, mEglSurface);521 eglDestroySurface(mEglDisplay, mEglSurface);
522 }
523 if (mMirSurface) {
524 mir_render_surface_release(mMirSurface);
525 }
553 if (mMirWindow) {526 if (mMirWindow) {
554 mir_window_release_sync(mMirWindow);527 mir_window_release_sync(mMirWindow);
555 }528 }
@@ -606,30 +579,23 @@
606{579{
607 QMutexLocker lock(&mTargetSizeMutex);580 QMutexLocker lock(&mTargetSizeMutex);
608581
609 // mir's resize event is mainly a signal that we need to redraw our content. We use the582 // There could have been a flurry of resize events, only process the latest event
610 // width/height as identifiers to figure out if this is the latest surface resize event583 const bool needsResize = mTargetSize.width() == width && mTargetSize.height() == height;
611 // that has posted, discarding any old ones. This avoids issuing too many redraw events.584 if (needsResize) {
612 // see TODO in postEvent as the ideal way we should handle this.585 // Resize the buffers
613 // The actual buffer size may or may have not changed at this point, so let the rendering586 mir_render_surface_set_size(mMirSurface, width, height);
614 // thread drive the window geometry updates.587
615 mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height;588 //Resize the window
616}589 Spec spec{mir_create_window_spec(mConnection)};
617590 mir_window_spec_add_render_surface(spec.get(), mMirSurface, width, height, 0, 0);
618int UbuntuSurface::needsRepaint() const591 mir_window_apply_spec(mMirWindow, spec.get());
619{592
620 if (mNeedsRepaint) {593 QRect newGeometry = mPlatformWindow->geometry();
621 if (mTargetSize != mBufferSize) {594 newGeometry.setSize(mTargetSize);
622 //If the buffer hasn't changed yet, we need at least two redraws,595
623 //once to get the new buffer size and propagate the geometry changes596 mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
624 //and the second to redraw the content at the new size597 QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
625 return 2;
626 } else {
627 // The buffer size has already been updated so we only need one redraw
628 // to render at the new size
629 return 1;
630 }
631 }598 }
632 return 0;
633}599}
634600
635void UbuntuSurface::setState(MirWindowState state)601void UbuntuSurface::setState(MirWindowState state)
@@ -653,35 +619,13 @@
653 static int sFrameNumber = 0;619 static int sFrameNumber = 0;
654 ++sFrameNumber;620 ++sFrameNumber;
655621
656 EGLint eglSurfaceWidth = -1;622 qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d]",
657 EGLint eglSurfaceHeight = -1;623 mWindow, sFrameNumber);
658 eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth);
659 eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight);
660
661 const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0;
662
663 if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {
664
665 qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
666 mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);
667
668 mBufferSize.rwidth() = eglSurfaceWidth;
669 mBufferSize.rheight() = eglSurfaceHeight;
670
671 QRect newGeometry = mPlatformWindow->geometry();
672 newGeometry.setSize(mBufferSize);
673
674 mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
675 QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
676 } else {
677 qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
678 mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());
679 }
680}624}
681625
682void UbuntuSurface::surfaceEventCallback(MirWindow *surface, const MirEvent *event, void* context)626void UbuntuSurface::windowEventCallback(MirWindow *window, const MirEvent *event, void* context)
683{627{
684 Q_UNUSED(surface);628 Q_UNUSED(window);
685 Q_ASSERT(context != nullptr);629 Q_ASSERT(context != nullptr);
686630
687 auto s = static_cast<UbuntuSurface *>(context);631 auto s = static_cast<UbuntuSurface *>(context);
@@ -692,9 +636,8 @@
692{636{
693 const auto eventType = mir_event_get_type(event);637 const auto eventType = mir_event_get_type(event);
694 if (mir_event_type_resize == eventType) {638 if (mir_event_type_resize == eventType) {
695 // TODO: The current event queue just accumulates all resize events;639 // The event queue just accumulates all resize events;
696 // It would be nicer if we could update just one event if that event has not been dispatched.640 // Use the width and height as an identifier of this latest event
697 // As a workaround, we use the width/height as an identifier of this latest event
698 // so the event handler (handleSurfaceResized) can discard/ignore old ones.641 // so the event handler (handleSurfaceResized) can discard/ignore old ones.
699 const auto resizeEvent = mir_event_get_resize_event(event);642 const auto resizeEvent = mir_event_get_resize_event(event);
700 const auto width = mir_resize_event_get_width(resizeEvent);643 const auto width = mir_resize_event_get_width(resizeEvent);
@@ -786,19 +729,6 @@
786 qCDebug(mirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), width, height);729 qCDebug(mirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), width, height);
787730
788 mSurface->handleSurfaceResized(width, height);731 mSurface->handleSurfaceResized(width, height);
789
790 // This resize event could have occurred just after the last buffer swap for this window.
791 // This means the client may still be holding a buffer with the older size. The first redraw call
792 // will then render at the old size. After swapping the client now will get a new buffer with the
793 // updated size but it still needs re-rendering so another redraw may be needed.
794 // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice
795 auto const numRepaints = mSurface->needsRepaint();
796 lock.unlock();
797 qCDebug(mirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
798 for (int i = 0; i < numRepaints; i++) {
799 qCDebug(mirclient, "handleSurfaceResize(window=%p) repainting size=(%dx%d)dp", window(), geometry().size().width(), geometry().size().height());
800 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
801 }
802}732}
803733
804void QMirClientWindow::handleSurfaceExposeChange(bool exposed)734void QMirClientWindow::handleSurfaceExposeChange(bool exposed)
805735
=== modified file 'src/ubuntumirclient/ubuntumirclient.pro'
--- src/ubuntumirclient/ubuntumirclient.pro 2017-07-07 08:17:58 +0000
+++ src/ubuntumirclient/ubuntumirclient.pro 2017-08-25 11:54:50 +0000
@@ -4,22 +4,21 @@
4QT += \4QT += \
5 core-private dbus linuxaccessibility_support-private \5 core-private dbus linuxaccessibility_support-private \
6 theme_support-private eventdispatcher_support-private \6 theme_support-private eventdispatcher_support-private \
7 fontdatabase_support-private egl_support-private7 fontdatabase_support-private egl_support-private service_support-private
88
9CONFIG += plugin no_keywords qpa/genericunixfontdatabase9CONFIG += plugin no_keywords qpa/genericunixfontdatabase
1010
11DEFINES += MESA_EGL_NO_X11_HEADERS11DEFINES += MESA_EGL_NO_X11_HEADERS MIR_DEPRECATE_RENDERSURFACES=0 MIR_ENABLE_DEPRECATIONS=0
12# CONFIG += c++11 # only enables C++0x12# CONFIG += c++11 # only enables C++0x
13QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall13QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall
14QMAKE_CXXFLAGS += -Wno-error=deprecated-declarations14QMAKE_CXXFLAGS += -Wno-error=deprecated-declarations
15QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined15QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined
1616
17CONFIG += link_pkgconfig17CONFIG += link_pkgconfig
18PKGCONFIG += egl mirclient ubuntu-platform-api xkbcommon libcontent-hub18PKGCONFIG += egl mirclient xkbcommon
1919
20SOURCES = \20SOURCES = \
21 qmirclientbackingstore.cpp \21 qmirclientbackingstore.cpp \
22 qmirclientclipboard.cpp \
23 qmirclientcursor.cpp \22 qmirclientcursor.cpp \
24 qmirclientdebugextension.cpp \23 qmirclientdebugextension.cpp \
25 qmirclientdesktopwindow.cpp \24 qmirclientdesktopwindow.cpp \
@@ -27,7 +26,6 @@
27 qmirclientinput.cpp \26 qmirclientinput.cpp \
28 qmirclientintegration.cpp \27 qmirclientintegration.cpp \
29 qmirclientnativeinterface.cpp \28 qmirclientnativeinterface.cpp \
30 qmirclientplatformservices.cpp \
31 qmirclientplugin.cpp \29 qmirclientplugin.cpp \
32 qmirclientscreen.cpp \30 qmirclientscreen.cpp \
33 qmirclientscreenobserver.cpp \31 qmirclientscreenobserver.cpp \
@@ -36,7 +34,6 @@
3634
37HEADERS = \35HEADERS = \
38 qmirclientbackingstore.h \36 qmirclientbackingstore.h \
39 qmirclientclipboard.h \
40 qmirclientcursor.h \37 qmirclientcursor.h \
41 qmirclientdebugextension.h \38 qmirclientdebugextension.h \
42 qmirclientdesktopwindow.h \39 qmirclientdesktopwindow.h \
@@ -45,7 +42,6 @@
45 qmirclientintegration.h \42 qmirclientintegration.h \
46 qmirclientnativeinterface.h \43 qmirclientnativeinterface.h \
47 qmirclientorientationchangeevent_p.h \44 qmirclientorientationchangeevent_p.h \
48 qmirclientplatformservices.h \
49 qmirclientplugin.h \45 qmirclientplugin.h \
50 qmirclientscreenobserver.h \46 qmirclientscreenobserver.h \
51 qmirclientscreen.h \47 qmirclientscreen.h \

Subscribers

People subscribed via source and target branches