Merge lp:~gerboland/qtmir/qmirserver-hides-mirserver into lp:qtmir

Proposed by Gerry Boland
Status: Merged
Approved by: Daniel d'Andrada
Approved revision: 340
Merged at revision: 344
Proposed branch: lp:~gerboland/qtmir/qmirserver-hides-mirserver
Merge into: lp:qtmir
Diff against target: 750 lines (+279/-192)
14 files modified
demos/qml-demo-shell/qml-demo-shell.qml (+15/-0)
src/platforms/mirserver/CMakeLists.txt (+1/-0)
src/platforms/mirserver/display.cpp (+1/-6)
src/platforms/mirserver/display.h (+7/-9)
src/platforms/mirserver/miropenglcontext.cpp (+2/-3)
src/platforms/mirserver/miropenglcontext.h (+0/-1)
src/platforms/mirserver/mirserverintegration.cpp (+24/-35)
src/platforms/mirserver/mirserverintegration.h (+3/-4)
src/platforms/mirserver/nativeinterface.cpp (+13/-10)
src/platforms/mirserver/nativeinterface.h (+3/-3)
src/platforms/mirserver/qmirserver.cpp (+69/-72)
src/platforms/mirserver/qmirserver.h (+21/-49)
src/platforms/mirserver/qmirserver_p.cpp (+53/-0)
src/platforms/mirserver/qmirserver_p.h (+67/-0)
To merge this branch: bzr merge lp:~gerboland/qtmir/qmirserver-hides-mirserver
Reviewer Review Type Date Requested Status
Daniel d'Andrada (community) Approve
PS Jenkins bot (community) continuous-integration Needs Fixing
Review via email: mp+258038@code.launchpad.net

Commit message

[qpa] refactor QMirServer to clean up its API, and fix strange thread design.

This does the following:
- QMirServer has a much cleaner API - using d-pointer to encourage ABI stability
- move quit decision point to MirServerIntegration
- the Mir server is run from a class inheriting a QThread, simplifies thread control significantly

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

If you're thinking about making QMirServer public API, could you please add some documentation to src/platforms/mirserver/qmirserver.h. Explain what it does, what's its main purpose.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

So MirServer::stop() is thread safe or is it a hack?

"""
void MirServerWorker::stop()
{
    server->stop();
}
"""

review: Needs Information
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> So MirServer::stop() is thread safe or is it a hack?
>
>
> """
> void MirServerWorker::stop()
> {
> server->stop();
> }
> """

Please ignore me. Now I see that MirServerWorker::run() and stop() are never called directly from the main thread but only from the within worker thread's event loop.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

In src/platforms/mirserver/qmirserver.h:

"""
    Q_SLOT void serverStopped();
"""

Are you sure you want this slot in the public API?

And, by the way, it's named like a signal. It should be onServerStopped() or, even better, quit().

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

in src/platforms/mirserver/qmirserver.cpp:

"""
    connect(d->serverWorker, &MirServerWorker::stopped, this, &QMirServer::serverStopped, Qt::DirectConnection);
"""

I think this line deserves a comment explaining why this has to be a direct connection, which will cause QMirServer::serverStopped to be called from within MirServerWorker's thread.

trunk has a terse comment about it.

Which makes me think maybe you should say from which thread QMirServer::serverStopped() will be called in the documentation of QMirServer::serverStopped() itself. Helps keeping tabs on this tricky cross-thread communication.

review: Needs Information
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

In src/platforms/mirserver/qmirserver.h

"""
    bool run();
    Q_SLOT bool stop();
"""

Again, thinking about having it as public API: you should probably document these methods, answering questions like: Is it a blocking call or does it return immediately?

What's the user expected to do with those return values? I don't see you using them for anything.

"""
    connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
            d->serverWorker, &MirServerWorker::stop, Qt::DirectConnection); // see FIXME in MirServerWorker
"""

"""
    if (!d->serverWorker->waitForMirStartup())
    {
        qCritical() << "ERROR: QMirServer - Mir failed to start";
        QCoreApplication::quit();
"""

Isn't QMirServer going out of its territory when it modifies QCoreApplication directly like that?
I would expect the user of QMirServer to do this instead, like:

"""
if (!qmirServer->run()) {
    QCoreApplication::quit();
}
"""

review: Needs Information
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

In src/platforms/mirserver/display.cpp:

"""
-Display::Display(const QSharedPointer<MirServer> &server, QObject *parent)
- : QObject(parent)
- , m_mirServer(server)
+Display::Display(const QSharedPointer<MirServer> &server)
 {
- std::shared_ptr<mir::graphics::DisplayConfiguration> displayConfig = m_mirServer->the_display()->configuration();
+ std::shared_ptr<mir::graphics::DisplayConfiguration> displayConfig = server->the_display()->configuration();
"""

I think you could go further and pass the display config already in the constructor instead of the whole server since that's the only thing Display is interested in after all.

-------------------------

In src/platforms/mirserver/miropenglcontext.cpp:

"""
 MirOpenGLContext::MirOpenGLContext(const QSharedPointer<MirServer> &server, const QSurfaceFormat &format)
- : m_mirServer(server)
 #if GL_DEBUG
- , m_logger(new QOpenGLDebugLogger(this))
+ : m_logger(new QOpenGLDebugLogger(this))
 #endif
 {
- std::shared_ptr<mir::graphics::Display> display = m_mirServer->the_display();
+ std::shared_ptr<mir::graphics::Display> display = server->the_display();
"""

Likewise here.

Revision history for this message
Gerry Boland (gerboland) wrote :

> If you're thinking about making QMirServer public API, could you please add
> some documentation to src/platforms/mirserver/qmirserver.h. Explain what it
> does, what's its main purpose.

It's far from ready yet, but that is the plan. I'll start writing documentation when we've the API in a good condition, which will be another while yet.

Revision history for this message
Gerry Boland (gerboland) wrote :

> in src/platforms/mirserver/qmirserver.cpp:
>
> """
> connect(d->serverWorker, &MirServerWorker::stopped, this,
> &QMirServer::serverStopped, Qt::DirectConnection);
> """
>
> I think this line deserves a comment explaining why this has to be a direct
> connection, which will cause QMirServer::serverStopped to be called from
> within MirServerWorker's thread.
>
> trunk has a terse comment about it.

Fair point. The line above it also creates a direct connection, and that line has a comment pointing to the explanation. But yeah, that connection is easily missed, will fix

Revision history for this message
Gerry Boland (gerboland) wrote :

> In src/platforms/mirserver/qmirserver.h
>
> """
> bool run();
> Q_SLOT bool stop();
> """
>
> Again, thinking about having it as public API: you should probably document
> these methods, answering questions like: Is it a blocking call or does it
> return immediately?
>
> What's the user expected to do with those return values? I don't see you using
> them for anything.

I was planning to document things later. But I can start now if you'd prefer.

> """
> connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
> d->serverWorker, &MirServerWorker::stop, Qt::DirectConnection); //
> see FIXME in MirServerWorker
> """
>
> """
> if (!d->serverWorker->waitForMirStartup())
> {
> qCritical() << "ERROR: QMirServer - Mir failed to start";
> QCoreApplication::quit();
> """
>
> Isn't QMirServer going out of its territory when it modifies QCoreApplication
> directly like that?
> I would expect the user of QMirServer to do this instead, like:
>
> """
> if (!qmirServer->run()) {
> QCoreApplication::quit();
> }
> """

You're totally right, this is also the direction I wanted to go. I was hesitant to do so, as I feared it along with all the other changes would make quite a large MR. So your suggestion is to be the next step: have the QMirServer user listen for mir or qt shutdown, and react accordingly. Should I just do that now?

Revision history for this message
Gerry Boland (gerboland) wrote :

> In src/platforms/mirserver/display.cpp:
>
> """
> -Display::Display(const QSharedPointer<MirServer> &server, QObject *parent)
> - : QObject(parent)
> - , m_mirServer(server)
> +Display::Display(const QSharedPointer<MirServer> &server)
> {
> - std::shared_ptr<mir::graphics::DisplayConfiguration> displayConfig =
> m_mirServer->the_display()->configuration();
> + std::shared_ptr<mir::graphics::DisplayConfiguration> displayConfig =
> server->the_display()->configuration();
> """
>
> I think you could go further and pass the display config already in the
> constructor instead of the whole server since that's the only thing Display is
> interested in after all.
>
> -------------------------
>
> In src/platforms/mirserver/miropenglcontext.cpp:
>
> """
> MirOpenGLContext::MirOpenGLContext(const QSharedPointer<MirServer> &server,
> const QSurfaceFormat &format)
> - : m_mirServer(server)
> #if GL_DEBUG
> - , m_logger(new QOpenGLDebugLogger(this))
> + : m_logger(new QOpenGLDebugLogger(this))
> #endif
> {
> - std::shared_ptr<mir::graphics::Display> display =
> m_mirServer->the_display();
> + std::shared_ptr<mir::graphics::Display> display = server->the_display();
> """
>
> Likewise here.

I had a reason for not doing that at the time, but I can't recall it now. Will do

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> > In src/platforms/mirserver/qmirserver.h
> >
> > """
> > bool run();
> > Q_SLOT bool stop();
> > """
> >
> > Again, thinking about having it as public API: you should probably document
> > these methods, answering questions like: Is it a blocking call or does it
> > return immediately?
> >
> > What's the user expected to do with those return values? I don't see you
> using
> > them for anything.
>
> I was planning to document things later. But I can start now if you'd prefer.
>
>
>
> > """
> > connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
> > d->serverWorker, &MirServerWorker::stop, Qt::DirectConnection);
> //
> > see FIXME in MirServerWorker
> > """
> >
> > """
> > if (!d->serverWorker->waitForMirStartup())
> > {
> > qCritical() << "ERROR: QMirServer - Mir failed to start";
> > QCoreApplication::quit();
> > """
> >
> > Isn't QMirServer going out of its territory when it modifies
> QCoreApplication
> > directly like that?
> > I would expect the user of QMirServer to do this instead, like:
> >
> > """
> > if (!qmirServer->run()) {
> > QCoreApplication::quit();
> > }
> > """
>
>
> You're totally right, this is also the direction I wanted to go. I was
> hesitant to do so, as I feared it along with all the other changes would make
> quite a large MR. So your suggestion is to be the next step: have the
> QMirServer user listen for mir or qt shutdown, and react accordingly. Should I
> just do that now?

I can live with this being an intermediate step but it should leave the code in a consistent state. Eg: If you don't use the return values for anything then don't return them in the first place (have a void return type). Also it would be good to add TODOs for the next step, like over those QCoreApplication calls inside QMirServer.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

The commit message line is a bit too long. That first line should shorter, followed by a longer description below if needed

332. By Gerry Boland

Trying to fix shutdown, incomplete

333. By Gerry Boland

Fix shutdown issues by inheriting QThread directly - also get to avoid having qt event loop for mir

334. By Gerry Boland

Clean up shutdown codepath further. run/stop return void

335. By Gerry Boland

Unneeded return statements

336. By Gerry Boland

Remove old comment, it not the case any more

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
337. By Gerry Boland

Merge qtmir trunk

Revision history for this message
Gerry Boland (gerboland) wrote :

> > In src/platforms/mirserver/display.cpp:
> >
> > """
> > -Display::Display(const QSharedPointer<MirServer> &server, QObject *parent)
> > - : QObject(parent)
> > - , m_mirServer(server)
> > +Display::Display(const QSharedPointer<MirServer> &server)
> > {
> > - std::shared_ptr<mir::graphics::DisplayConfiguration> displayConfig =
> > m_mirServer->the_display()->configuration();
> > + std::shared_ptr<mir::graphics::DisplayConfiguration> displayConfig =
> > server->the_display()->configuration();
> > """
> >
> > I think you could go further and pass the display config already in the
> > constructor instead of the whole server since that's the only thing Display
> is
> > interested in after all.
> >
> > -------------------------
> >
> > In src/platforms/mirserver/miropenglcontext.cpp:
> >
> > """
> > MirOpenGLContext::MirOpenGLContext(const QSharedPointer<MirServer> &server,
> > const QSurfaceFormat &format)
> > - : m_mirServer(server)
> > #if GL_DEBUG
> > - , m_logger(new QOpenGLDebugLogger(this))
> > + : m_logger(new QOpenGLDebugLogger(this))
> > #endif
> > {
> > - std::shared_ptr<mir::graphics::Display> display =
> > m_mirServer->the_display();
> > + std::shared_ptr<mir::graphics::Display> display =
> server->the_display();
> > """
> >
> > Likewise here.
>
>
> I had a reason for not doing that at the time, but I can't recall it now. Will
> do

I thought of the reason. It would require me to include loads of Mir internal headers in MirServerIntegration. Since qtmir::Display wants mir::graphics::DisplayConfiguration, I would need to include headers for mg::Display & mg::DisplayConfiguration.

As the multimonitor work will refactor those classes quite a bit, I decided to just keep this approach knowing that I'll improve it later.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
338. By Gerry Boland

Merge trunk

339. By Gerry Boland

Remove unneeded header

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
340. By Gerry Boland

Only pass mg::DisplayConfiguration to qtmir::Display, as that is all it needs

Revision history for this message
Gerry Boland (gerboland) wrote :

Ready for a second review pass. Main change is in the thread design which simplifies event passing greatly. API improved too, QMirServer no longer quits the process, owner does instead

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

"""
bool QMirServer::start()
{
    [...]
    Q_EMIT started();
    [...]
}
"""

Is this signal being used for anything?

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

> """
> bool QMirServer::start()
> {
> [...]
> Q_EMIT started();
> [...]
> }
> """
>
> Is this signal being used for anything?

Nope, added to API for symmetry (the "stopped" signal is necessary)

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Code looks ok, but didn't test on the device to see if broke anything.

review: Approve (code)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

* Did you perform an exploratory manual test run of the code change and any related functionality?
Yes.

* Did CI run pass? If not, please explain why.
No, because Jenkins runs on wily and wily doesn't have mir 0.13 yet.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'demos/qml-demo-shell/qml-demo-shell.qml'
--- demos/qml-demo-shell/qml-demo-shell.qml 2015-01-23 10:23:07 +0000
+++ demos/qml-demo-shell/qml-demo-shell.qml 2015-05-27 12:12:52 +0000
@@ -110,6 +110,21 @@
110 y: point.y110 y: point.y
111 }111 }
112112
113 Rectangle {
114 width: 60
115 height: 40
116 color: "red"
117 anchors { right: parent.right; bottom: parent.bottom }
118 Text {
119 anchors.centerIn: parent
120 text: "Quit"
121 }
122 MouseArea {
123 anchors.fill: parent
124 onClicked: Qt.quit()
125 }
126 }
127
113 Connections {128 Connections {
114 target: SurfaceManager129 target: SurfaceManager
115 onSurfaceCreated: {130 onSurfaceCreated: {
116131
=== modified file 'src/platforms/mirserver/CMakeLists.txt'
--- src/platforms/mirserver/CMakeLists.txt 2015-05-13 09:40:03 +0000
+++ src/platforms/mirserver/CMakeLists.txt 2015-05-27 12:12:52 +0000
@@ -44,6 +44,7 @@
44 qteventfeeder.cpp44 qteventfeeder.cpp
45 plugin.cpp45 plugin.cpp
46 qmirserver.cpp46 qmirserver.cpp
47 qmirserver_p.cpp
47 sessionauthorizer.cpp48 sessionauthorizer.cpp
48 sessionlistener.cpp49 sessionlistener.cpp
49 surfaceobserver.cpp50 surfaceobserver.cpp
5051
=== modified file 'src/platforms/mirserver/display.cpp'
--- src/platforms/mirserver/display.cpp 2014-12-01 11:10:54 +0000
+++ src/platforms/mirserver/display.cpp 2015-05-27 12:12:52 +0000
@@ -23,18 +23,13 @@
2323
24#include <mir/graphics/display.h>24#include <mir/graphics/display.h>
25#include <mir/graphics/display_configuration.h>25#include <mir/graphics/display_configuration.h>
26#include <QDebug>
2726
28namespace mg = mir::graphics;27namespace mg = mir::graphics;
2928
30// TODO: Listen for display changes and update the list accordingly29// TODO: Listen for display changes and update the list accordingly
3130
32Display::Display(const QSharedPointer<MirServer> &server, QObject *parent)31Display::Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig)
33 : QObject(parent)
34 , m_mirServer(server)
35{32{
36 std::shared_ptr<mir::graphics::DisplayConfiguration> displayConfig = m_mirServer->the_display()->configuration();
37
38 displayConfig->for_each_output([this](mg::DisplayConfigurationOutput const& output) {33 displayConfig->for_each_output([this](mg::DisplayConfigurationOutput const& output) {
39 if (output.used) {34 if (output.used) {
40 auto screen = new Screen(output);35 auto screen = new Screen(output);
4136
=== modified file 'src/platforms/mirserver/display.h'
--- src/platforms/mirserver/display.h 2014-12-01 11:10:54 +0000
+++ src/platforms/mirserver/display.h 2015-05-27 12:12:52 +0000
@@ -19,23 +19,21 @@
19#ifndef DISPLAY_H19#ifndef DISPLAY_H
20#define DISPLAY_H20#define DISPLAY_H
2121
22#include <QObject>
23#include <qpa/qplatformscreen.h>22#include <qpa/qplatformscreen.h>
2423#include <memory>
25class MirServer;24
2625namespace mir { namespace graphics { class DisplayConfiguration; }}
27class Display : public QObject26
27class Display
28{28{
29 Q_OBJECT
30public:29public:
31 Display(const QSharedPointer<MirServer> &server, QObject *parent = 0);30 Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig);
32 ~Display();31 virtual ~Display();
3332
34 QList<QPlatformScreen *> screens() const { return m_screens; }33 QList<QPlatformScreen *> screens() const { return m_screens; }
3534
36private:35private:
37 QList<QPlatformScreen *> m_screens;36 QList<QPlatformScreen *> m_screens;
38 const QSharedPointer<MirServer> m_mirServer;
39};37};
4038
41#endif // DISPLAY_H39#endif // DISPLAY_H
4240
=== modified file 'src/platforms/mirserver/miropenglcontext.cpp'
--- src/platforms/mirserver/miropenglcontext.cpp 2015-01-12 17:54:55 +0000
+++ src/platforms/mirserver/miropenglcontext.cpp 2015-05-27 12:12:52 +0000
@@ -36,12 +36,11 @@
36// (i.e. individual display output buffers) to use as a common base context.36// (i.e. individual display output buffers) to use as a common base context.
3737
38MirOpenGLContext::MirOpenGLContext(const QSharedPointer<MirServer> &server, const QSurfaceFormat &format)38MirOpenGLContext::MirOpenGLContext(const QSharedPointer<MirServer> &server, const QSurfaceFormat &format)
39 : m_mirServer(server)
40#if GL_DEBUG39#if GL_DEBUG
41 , m_logger(new QOpenGLDebugLogger(this))40 : m_logger(new QOpenGLDebugLogger(this))
42#endif41#endif
43{42{
44 std::shared_ptr<mir::graphics::Display> display = m_mirServer->the_display();43 std::shared_ptr<mir::graphics::Display> display = server->the_display();
4544
46 // create a temporary GL context to fetch the EGL display and config, so Qt can determine the surface format45 // create a temporary GL context to fetch the EGL display and config, so Qt can determine the surface format
47 std::unique_ptr<mir::graphics::GLContext> mirContext = display->create_gl_context();46 std::unique_ptr<mir::graphics::GLContext> mirContext = display->create_gl_context();
4847
=== modified file 'src/platforms/mirserver/miropenglcontext.h'
--- src/platforms/mirserver/miropenglcontext.h 2014-12-01 11:10:54 +0000
+++ src/platforms/mirserver/miropenglcontext.h 2015-05-27 12:12:52 +0000
@@ -52,7 +52,6 @@
52#endif52#endif
5353
54private:54private:
55 const QSharedPointer<MirServer> m_mirServer;
56 QSurfaceFormat m_format;55 QSurfaceFormat m_format;
57#if GL_DEBUG56#if GL_DEBUG
58 QOpenGLDebugLogger *m_logger;57 QOpenGLDebugLogger *m_logger;
5958
=== modified file 'src/platforms/mirserver/mirserverintegration.cpp'
--- src/platforms/mirserver/mirserverintegration.cpp 2015-04-01 10:48:28 +0000
+++ src/platforms/mirserver/mirserverintegration.cpp 2015-05-27 12:12:52 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013-2014 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * 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 by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -30,7 +30,6 @@
30#include <qpa/qwindowsysteminterface.h>30#include <qpa/qwindowsysteminterface.h>
3131
32#include <QCoreApplication>32#include <QCoreApplication>
33#include <QStringList>
34#include <QOpenGLContext>33#include <QOpenGLContext>
3534
36#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)35#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
@@ -41,10 +40,7 @@
4140
42// Mir41// Mir
43#include <mir/graphics/display.h>42#include <mir/graphics/display.h>
44#include <mir/graphics/display_buffer.h>43#include <mir/graphics/display_configuration.h>
45
46// std
47#include <csignal>
4844
49// local45// local
50#include "clipboard.h"46#include "clipboard.h"
@@ -66,36 +62,25 @@
66#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)62#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
67 , m_eventDispatcher(createUnixEventDispatcher())63 , m_eventDispatcher(createUnixEventDispatcher())
68#endif64#endif
65 , m_mirServer(new QMirServer(QCoreApplication::arguments()))
69 , m_display(nullptr)66 , m_display(nullptr)
70 , m_qmirServer(nullptr)
71 , m_nativeInterface(nullptr)67 , m_nativeInterface(nullptr)
72 , m_clipboard(new Clipboard)68 , m_clipboard(new Clipboard)
73{69{
74 // Start Mir server only once Qt has initialized its event dispatcher, see initialize()
75
76 QStringList args = QCoreApplication::arguments();
77 // convert arguments back into argc-argv form that Mir wants
78 char **argv;
79 argv = new char*[args.size() + 1];
80 for (int i = 0; i < args.size(); i++) {
81 argv[i] = new char[strlen(args.at(i).toStdString().c_str())+1];
82 memcpy(argv[i], args.at(i).toStdString().c_str(), strlen(args.at(i).toStdString().c_str())+1);
83 }
84 argv[args.size()] = '\0';
85
86 // For access to sensors, qtmir uses qtubuntu-sensors. qtubuntu-sensors reads the70 // For access to sensors, qtmir uses qtubuntu-sensors. qtubuntu-sensors reads the
87 // UBUNTU_PLATFORM_API_BACKEND variable to decide if to load a valid sensor backend or not.71 // UBUNTU_PLATFORM_API_BACKEND variable to decide if to load a valid sensor backend or not.
88 // For it to function we need to ensure a valid backend has been specified72 // For it to function we need to ensure a valid backend has been specified
89 if (qEnvironmentVariableIsEmpty("UBUNTU_PLATFORM_API_BACKEND")) {73 if (qEnvironmentVariableIsEmpty("UBUNTU_PLATFORM_API_BACKEND")) {
90 if (qgetenv("DESKTOP_SESSION").contains("mir")) {74 if (qgetenv("DESKTOP_SESSION").contains("mir") || !qEnvironmentVariableIsSet("ANDROID_DATA")) {
91 qputenv("UBUNTU_PLATFORM_API_BACKEND", "desktop_mirclient");75 qputenv("UBUNTU_PLATFORM_API_BACKEND", "desktop_mirclient");
92 } else {76 } else {
93 qputenv("UBUNTU_PLATFORM_API_BACKEND", "touch_mirclient");77 qputenv("UBUNTU_PLATFORM_API_BACKEND", "touch_mirclient");
94 }78 }
95 }79 }
9680
97 m_mirServer = QSharedPointer<MirServer>(81 // If Mir shuts down, quit.
98 new MirServer(args.length(), const_cast<const char**>(argv)));82 QObject::connect(m_mirServer.data(), &QMirServer::stopped,
83 QCoreApplication::instance(), &QCoreApplication::quit);
9984
100#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)85#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
101 QGuiApplicationPrivate::instance()->setEventDispatcher(eventDispatcher_);86 QGuiApplicationPrivate::instance()->setEventDispatcher(eventDispatcher_);
@@ -109,7 +94,6 @@
109{94{
110 delete m_nativeInterface;95 delete m_nativeInterface;
111 delete m_display;96 delete m_display;
112 delete m_qmirServer;
113}97}
11498
115bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const99bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -135,18 +119,21 @@
135119
136 DisplayWindow* displayWindow = nullptr;120 DisplayWindow* displayWindow = nullptr;
137121
122 auto const mirServer = m_mirServer->mirServer().lock();
138 mg::DisplayBuffer* first_buffer{nullptr};123 mg::DisplayBuffer* first_buffer{nullptr};
139 mg::DisplaySyncGroup* first_group{nullptr};124 mg::DisplaySyncGroup* first_group{nullptr};
140 m_mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) {125 if (mirServer) {
141 if (!first_group) {126 mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) {
142 first_group = &group;127 if (!first_group) {
143 }128 first_group = &group;
144 group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) {
145 if (!first_buffer) {
146 first_buffer = &buffer;
147 }129 }
130 group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) {
131 if (!first_buffer) {
132 first_buffer = &buffer;
133 }
134 });
148 });135 });
149 });136 }
150137
151 // FIXME(gerry) this will go very bad for >1 display buffer138 // FIXME(gerry) this will go very bad for >1 display buffer
152 if (first_group && first_buffer)139 if (first_group && first_buffer)
@@ -168,7 +155,7 @@
168QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const155QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
169{156{
170 qDebug() << "createPlatformOpenGLContext" << context;157 qDebug() << "createPlatformOpenGLContext" << context;
171 return new MirOpenGLContext(m_mirServer, context->format());158 return new MirOpenGLContext(m_mirServer->mirServer(), context->format());
172}159}
173160
174#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)161#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
@@ -181,10 +168,12 @@
181void MirServerIntegration::initialize()168void MirServerIntegration::initialize()
182{169{
183 // Creates instance of and start the Mir server in a separate thread170 // Creates instance of and start the Mir server in a separate thread
184 m_qmirServer = new QMirServer(m_mirServer);171 if (!m_mirServer->start()) {
172 exit(2);
173 }
185174
186 m_display = new Display(m_mirServer);175 m_display = new Display(m_mirServer->mirServer().data()->the_display()->configuration());
187 m_nativeInterface = new NativeInterface(m_mirServer);176 m_nativeInterface = new NativeInterface(m_mirServer->mirServer());
188177
189 for (QPlatformScreen *screen : m_display->screens())178 for (QPlatformScreen *screen : m_display->screens())
190 screenAdded(screen);179 screenAdded(screen);
191180
=== modified file 'src/platforms/mirserver/mirserverintegration.h'
--- src/platforms/mirserver/mirserverintegration.h 2014-12-11 15:27:02 +0000
+++ src/platforms/mirserver/mirserverintegration.h 2015-05-27 12:12:52 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013-2014 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * 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 by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -69,8 +69,6 @@
69 QPlatformNativeInterface *nativeInterface() const override;69 QPlatformNativeInterface *nativeInterface() const override;
7070
71private:71private:
72 QSharedPointer<MirServer> m_mirServer;
73
74 QScopedPointer<QPlatformAccessibility> m_accessibility;72 QScopedPointer<QPlatformAccessibility> m_accessibility;
75 QScopedPointer<QPlatformFontDatabase> m_fontDb;73 QScopedPointer<QPlatformFontDatabase> m_fontDb;
76 QScopedPointer<QPlatformServices> m_services;74 QScopedPointer<QPlatformServices> m_services;
@@ -78,8 +76,9 @@
78 QScopedPointer<QAbstractEventDispatcher> m_eventDispatcher;76 QScopedPointer<QAbstractEventDispatcher> m_eventDispatcher;
79#endif77#endif
8078
79 QScopedPointer<QMirServer> m_mirServer;
80
81 Display *m_display;81 Display *m_display;
82 QMirServer *m_qmirServer;
83 NativeInterface *m_nativeInterface;82 NativeInterface *m_nativeInterface;
84 QPlatformInputContext* m_inputContext;83 QPlatformInputContext* m_inputContext;
85 QScopedPointer<qtmir::Clipboard> m_clipboard;84 QScopedPointer<qtmir::Clipboard> m_clipboard;
8685
=== modified file 'src/platforms/mirserver/nativeinterface.cpp'
--- src/platforms/mirserver/nativeinterface.cpp 2015-01-28 14:25:36 +0000
+++ src/platforms/mirserver/nativeinterface.cpp 2015-05-27 12:12:52 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * 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 by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -18,7 +18,7 @@
1818
19#include "nativeinterface.h"19#include "nativeinterface.h"
2020
21NativeInterface::NativeInterface(const QSharedPointer<MirServer> &server)21NativeInterface::NativeInterface(const QWeakPointer<MirServer> &server)
22 : m_mirServer(server)22 : m_mirServer(server)
23{23{
24}24}
@@ -27,14 +27,17 @@
27{27{
28 void *result = nullptr;28 void *result = nullptr;
2929
30 if (resource == "SessionAuthorizer")30 auto const server = m_mirServer.lock();
31 result = m_mirServer->sessionAuthorizer();
32 else if (resource == "Shell")
33 result = m_mirServer->shell();
34 else if (resource == "SessionListener")
35 result = m_mirServer->sessionListener();
36 else if (resource == "PromptSessionListener")
37 result = m_mirServer->promptSessionListener();
3831
32 if (server) {
33 if (resource == "SessionAuthorizer")
34 result = server->sessionAuthorizer();
35 else if (resource == "Shell")
36 result = server->shell();
37 else if (resource == "SessionListener")
38 result = server->sessionListener();
39 else if (resource == "PromptSessionListener")
40 result = server->promptSessionListener();
41 }
39 return result;42 return result;
40}43}
4144
=== modified file 'src/platforms/mirserver/nativeinterface.h'
--- src/platforms/mirserver/nativeinterface.h 2014-12-01 11:05:01 +0000
+++ src/platforms/mirserver/nativeinterface.h 2015-05-27 12:12:52 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * 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 by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -29,11 +29,11 @@
29class NativeInterface : public QPlatformNativeInterface29class NativeInterface : public QPlatformNativeInterface
30{30{
31public:31public:
32 NativeInterface(const QSharedPointer<MirServer> &);32 NativeInterface(const QWeakPointer<MirServer> &);
3333
34 virtual void *nativeResourceForIntegration(const QByteArray &resource);34 virtual void *nativeResourceForIntegration(const QByteArray &resource);
3535
36 QSharedPointer<MirServer> m_mirServer;36 QWeakPointer<MirServer> m_mirServer;
37};37};
3838
39#endif // NATIVEINTEGRATION_H39#endif // NATIVEINTEGRATION_H
4040
=== modified file 'src/platforms/mirserver/qmirserver.cpp'
--- src/platforms/mirserver/qmirserver.cpp 2015-04-27 15:59:42 +0000
+++ src/platforms/mirserver/qmirserver.cpp 2015-05-27 12:12:52 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * 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 by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -19,80 +19,77 @@
19#include <QCoreApplication>19#include <QCoreApplication>
20#include <QDebug>20#include <QDebug>
2121
22#include <mir/main_loop.h>
23
24// local22// local
23#include "mirserver.h"
25#include "qmirserver.h"24#include "qmirserver.h"
2625#include "qmirserver_p.h"
2726
28void MirServerWorker::run()27
29{28QMirServer::QMirServer(const QStringList &arguments, QObject *parent)
30 auto const main_loop = server->the_main_loop();
31 // By enqueuing the notification code in the main loop, we are
32 // ensuring that the server has really and fully started before
33 // leaving wait_for_startup().
34 main_loop->enqueue(
35 this,
36 [&]
37 {
38 std::lock_guard<std::mutex> lock(mutex);
39 mir_running = true;
40 started_cv.notify_one();
41 });
42
43 server->run();
44 Q_EMIT stopped();
45}
46
47bool MirServerWorker::wait_for_mir_startup()
48{
49 std::unique_lock<decltype(mutex)> lock(mutex);
50 started_cv.wait_for(lock, std::chrono::seconds{10}, [&]{ return mir_running; });
51 return mir_running;
52}
53
54QMirServer::QMirServer(const QSharedPointer<MirServer> &server, QObject *parent)
55 : QObject(parent)29 : QObject(parent)
56 , m_mirServer(new MirServerWorker(server))30 , d_ptr(new QMirServerPrivate())
57{31{
58 m_mirServer->moveToThread(&m_mirThread);32 Q_D(QMirServer);
5933
60 connect(this, &QMirServer::run, m_mirServer, &MirServerWorker::run);34 // convert arguments back into argc-argv form that Mir wants
61 connect(this, &QMirServer::stop, m_mirServer, &MirServerWorker::stop);35 int argc = arguments.size();
6236 char **argv = new char*[argc + 1];
63 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QMirServer::shutDownMirServer);37 for (int i = 0; i < argc; i++) {
64 connect(m_mirServer, &MirServerWorker::stopped, this, &QMirServer::shutDownQApplication, Qt::DirectConnection); // since no event loop38 argv[i] = new char[strlen(arguments.at(i).toStdString().c_str())+1];
6539 memcpy(argv[i], arguments.at(i).toStdString().c_str(), strlen(arguments.at(i).toStdString().c_str())+1);
66 m_mirThread.start(QThread::TimeCriticalPriority);40 }
67 Q_EMIT run();41 argv[argc] = '\0';
6842
69 if (!m_mirServer->wait_for_mir_startup())43 d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv)));
44
45 d->serverThread = new MirServerThread(d->server);
46
47 connect(d->serverThread, &MirServerThread::stopped, this, &QMirServer::stopped);
48}
49
50QMirServer::~QMirServer()
51{
52 stop();
53}
54
55bool QMirServer::start()
56{
57 Q_D(QMirServer);
58
59 d->serverThread->start(QThread::TimeCriticalPriority);
60
61 if (!d->serverThread->waitForMirStartup())
70 {62 {
71 qCritical() << "ERROR: QMirServer - Mir failed to start";63 qCritical() << "ERROR: QMirServer - Mir failed to start";
72 exit(2);64 return false;
73 }65 }
74}66
7567 Q_EMIT started();
76QMirServer::~QMirServer()68 return true;
77{69}
78 shutDownMirServer();70
79}71void QMirServer::stop()
8072{
81void QMirServer::shutDownMirServer()73 Q_D(QMirServer);
82{74
83 if (m_mirThread.isRunning()) {75 if (d->serverThread->isRunning()) {
84 m_mirServer->stop();76 d->serverThread->stop();
85 m_mirThread.wait();77 if (!d->serverThread->wait(10000)) {
86 }78 // do something to indicate fail during shutdown
87}79 qCritical() << "ERROR: QMirServer - Mir failed to shut down correctly, terminating it";
8880 d->serverThread->terminate();
89void QMirServer::shutDownQApplication()81 }
90{82 }
91 if (m_mirThread.isRunning())83}
92 m_mirThread.quit();84
9385bool QMirServer::isRunning() const
94 // if unexpected mir server stop, better quit the QApplication86{
95 if (!QCoreApplication::closingDown()) {87 Q_D(const QMirServer);
96 QCoreApplication::quit();88 return d->serverThread->isRunning();
97 }89}
90
91QWeakPointer<MirServer> QMirServer::mirServer() const
92{
93 Q_D(const QMirServer);
94 return d->server.toWeakRef();
98}95}
9996
=== modified file 'src/platforms/mirserver/qmirserver.h'
--- src/platforms/mirserver/qmirserver.h 2014-12-02 14:55:17 +0000
+++ src/platforms/mirserver/qmirserver.h 2015-05-27 12:12:52 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * 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 by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -19,63 +19,35 @@
1919
20// Qt20// Qt
21#include <QObject>21#include <QObject>
22#include <QThread>22#include <QWeakPointer>
23#include <QSharedPointer>23
2424class QMirServerPrivate;
25// local25class MirServer;
26#include "mirserver.h"26
2727class QMirServer: public QObject
28#include <condition_variable>
29#include <mutex>
30
31// Wrap mir::Server with QObject, so it can be controlled via QThread
32class MirServerWorker : public QObject
33{28{
34 Q_OBJECT29 Q_OBJECT
3530
36public:31public:
37 MirServerWorker(const QSharedPointer<MirServer> &server)32 QMirServer(const QStringList &arguments, QObject* parent=0);
38 : server(server)33 virtual ~QMirServer();
39 {}34
4035 bool start();
41 bool wait_for_mir_startup();36 Q_SLOT void stop();
37 bool isRunning() const;
38
39 QWeakPointer<MirServer> mirServer() const;
4240
43Q_SIGNALS:41Q_SIGNALS:
42 void started();
44 void stopped();43 void stopped();
4544
46public Q_SLOTS:45protected:
47 void run();46 QMirServerPrivate * const d_ptr;
48 void stop() { server->stop(); }47
4948private:
50private:
51 std::mutex mutex;
52 std::condition_variable started_cv;
53 bool mir_running{false};
54
55 const QSharedPointer<MirServer> server;
56};
57
58
59class QMirServer: public QObject
60{
61 Q_OBJECT
62
63public:
64 QMirServer(const QSharedPointer<MirServer> &config, QObject* parent=0);
65 ~QMirServer();
66
67Q_SIGNALS:
68 void run();
69 void stop();
70
71protected Q_SLOTS:
72 void shutDownMirServer();
73 void shutDownQApplication();
74
75private:
76 QThread m_mirThread;
77 MirServerWorker *m_mirServer;
78 Q_DISABLE_COPY(QMirServer)49 Q_DISABLE_COPY(QMirServer)
50 Q_DECLARE_PRIVATE(QMirServer)
79};51};
8052
81#endif // QMIRSERVER_H53#endif // QMIRSERVER_H
8254
=== added file 'src/platforms/mirserver/qmirserver_p.cpp'
--- src/platforms/mirserver/qmirserver_p.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/qmirserver_p.cpp 2015-05-27 12:12:52 +0000
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2015 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// Mir
18#include <mir/main_loop.h>
19
20// local
21#include "qmirserver_p.h"
22
23
24void MirServerThread::run()
25{
26 auto const main_loop = server->the_main_loop();
27 // By enqueuing the notification code in the main loop, we are
28 // ensuring that the server has really and fully started before
29 // leaving wait_for_startup().
30 main_loop->enqueue(
31 this,
32 [&]
33 {
34 std::lock_guard<std::mutex> lock(mutex);
35 mir_running = true;
36 started_cv.notify_one();
37 });
38
39 server->run(); // blocks until Mir server stopped
40 Q_EMIT stopped();
41}
42
43void MirServerThread::stop()
44{
45 server->stop();
46}
47
48bool MirServerThread::waitForMirStartup()
49{
50 std::unique_lock<decltype(mutex)> lock(mutex);
51 started_cv.wait_for(lock, std::chrono::seconds{10}, [&]{ return mir_running; });
52 return mir_running;
53}
054
=== added file 'src/platforms/mirserver/qmirserver_p.h'
--- src/platforms/mirserver/qmirserver_p.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/qmirserver_p.h 2015-05-27 12:12:52 +0000
@@ -0,0 +1,67 @@
1/*
2 * Copyright (C) 2015 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 QMIRSERVER_P_H
18#define QMIRSERVER_P_H
19
20// Qt
21#include <QThread>
22#include <QSharedPointer>
23
24// std
25#include <condition_variable>
26#include <mutex>
27
28// local
29#include "mirserver.h"
30
31class QMirServer;
32class MirServerThread;
33
34struct QMirServerPrivate
35{
36 QSharedPointer<MirServer> server;
37 MirServerThread *serverThread;
38};
39
40
41class MirServerThread : public QThread
42{
43 Q_OBJECT
44
45public:
46 MirServerThread(const QSharedPointer<MirServer> &server)
47 : server(server)
48 {}
49
50 bool waitForMirStartup();
51
52Q_SIGNALS:
53 void stopped();
54
55public Q_SLOTS:
56 void run() override;
57 void stop();
58
59private:
60 std::mutex mutex;
61 std::condition_variable started_cv;
62 bool mir_running{false};
63
64 const QSharedPointer<MirServer> server;
65};
66
67#endif // QMIRSERVER_P_H

Subscribers

People subscribed via source and target branches