diff options
author | Andreas Pokorny <andreas.pokorny@canonical.com> | 2015-06-24 19:17:08 +0200 |
---|---|---|
committer | Andreas Pokorny <andreas.pokorny@canonical.com> | 2015-06-24 19:17:08 +0200 |
commit | aee914d643adf4994c655cce06998d1dd06d98d6 (patch) | |
tree | a32b2891baabc5b60f689341c7520485a9696550 /src | |
parent | a36d99e78c2407aa540a04abb07352dec8e90a04 (diff) | |
parent | ec03118336af538ce0af198adb9cdc571150ae16 (diff) |
merge trunk
Diffstat (limited to 'src')
21 files changed, 390 insertions, 252 deletions
diff --git a/src/modules/Unity/Application/CMakeLists.txt b/src/modules/Unity/Application/CMakeLists.txt index 7a0154a..8c437e6 100644 --- a/src/modules/Unity/Application/CMakeLists.txt +++ b/src/modules/Unity/Application/CMakeLists.txt @@ -1,5 +1,4 @@ include_directories( - ${APPLICATION_API_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIO_UNIX_INCLUDE_DIRS} diff --git a/src/modules/Unity/Application/application.cpp b/src/modules/Unity/Application/application.cpp index 4714c22..cf37c92 100644 --- a/src/modules/Unity/Application/application.cpp +++ b/src/modules/Unity/Application/application.cpp @@ -60,12 +60,9 @@ Application::Application(const QSharedPointer<TaskController>& taskController, // FIXME(greyback) need to save long appId internally until ubuntu-app-launch can hide it from us m_longAppId = desktopFileReader->file().remove(QRegExp(".desktop$")).split('/').last(); - // FIXME: This is a hack. Remove once we have a real implementation for knowing the supported - // orientations of an app - m_supportedOrientations = PortraitOrientation - | LandscapeOrientation - | InvertedPortraitOrientation - | InvertedLandscapeOrientation; + m_supportedOrientations = m_desktopData->supportedOrientations(); + + m_rotatesWindowContents = m_desktopData->rotatesWindowContents(); } Application::~Application() @@ -355,11 +352,16 @@ QString Application::longAppId() const return m_longAppId; } -Application::SupportedOrientations Application::supportedOrientations() const +Qt::ScreenOrientations Application::supportedOrientations() const { return m_supportedOrientations; } +bool Application::rotatesWindowContents() const +{ + return m_rotatesWindowContents; +} + Session* Application::session() const { return m_session; diff --git a/src/modules/Unity/Application/application.h b/src/modules/Unity/Application/application.h index a80f852..dff36cd 100644 --- a/src/modules/Unity/Application/application.h +++ b/src/modules/Unity/Application/application.h @@ -47,27 +47,15 @@ class Application : public unity::shell::application::ApplicationInfoInterface { Q_OBJECT - Q_FLAGS(Orientation SupportedOrientations) - Q_PROPERTY(QString desktopFile READ desktopFile CONSTANT) Q_PROPERTY(QString exec READ exec CONSTANT) Q_PROPERTY(bool fullscreen READ fullscreen NOTIFY fullscreenChanged) Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged) - Q_PROPERTY(SupportedOrientations supportedOrientations READ supportedOrientations CONSTANT) Q_PROPERTY(Session* session READ session NOTIFY sessionChanged DESIGNABLE false) public: Q_DECLARE_FLAGS(Stages, Stage) - // Matching Qt::ScreenOrientation values for convenience - enum Orientation { - PortraitOrientation = 0x1, - LandscapeOrientation = 0x2, - InvertedPortraitOrientation = 0x4, - InvertedLandscapeOrientation = 0x8 - }; - Q_DECLARE_FLAGS(SupportedOrientations, Orientation) - Application(const QSharedPointer<TaskController>& taskController, const QSharedPointer<SharedWakelock>& sharedWakelock, DesktopFileReader *desktopFileReader, @@ -90,6 +78,8 @@ public: QColor splashColor() const override; QColor splashColorHeader() const override; QColor splashColorFooter() const override; + Qt::ScreenOrientations supportedOrientations() const override; + bool rotatesWindowContents() const override; void setStage(Stage stage); void setState(State state); @@ -105,7 +95,6 @@ public: bool fullscreen() const; Stages supportedStages() const; - SupportedOrientations supportedOrientations() const; pid_t pid() const; @@ -140,7 +129,8 @@ private: bool m_focused; bool m_canBeResumed; QStringList m_arguments; - SupportedOrientations m_supportedOrientations; + Qt::ScreenOrientations m_supportedOrientations; + bool m_rotatesWindowContents; Session *m_session; friend class ApplicationManager; @@ -151,6 +141,5 @@ private: } // namespace qtmir Q_DECLARE_METATYPE(qtmir::Application*) -Q_DECLARE_OPERATORS_FOR_FLAGS(qtmir::Application::SupportedOrientations) #endif // APPLICATION_H diff --git a/src/modules/Unity/Application/application_manager.cpp b/src/modules/Unity/Application/application_manager.cpp index 6f6e5a6..ea316e7 100644 --- a/src/modules/Unity/Application/application_manager.cpp +++ b/src/modules/Unity/Application/application_manager.cpp @@ -62,36 +62,6 @@ namespace qtmir namespace { -// FIXME: AppManager should not implement policy based on display geometry, shell should do that -bool forceAllAppsIntoMainStage(const QSharedPointer<MirServer> &mirServer) -{ - const int tabletModeMinimimWithGU = 100; - - // Obtain display size - //TODO: should use mir::graphics::Display::configuration - mir::geometry::Rectangles view_area; - mirServer->the_display()->for_each_display_sync_group( - [&view_area](mir::graphics::DisplaySyncGroup &group) { - group.for_each_display_buffer( - [&view_area](const mir::graphics::DisplayBuffer &db) { - view_area.add(db.view_area()); - }); - }); - - // Get current Grid Unit value - int gridUnitPx = 8; - QByteArray gridUnitString = qgetenv("GRID_UNIT_PX"); - if (!gridUnitString.isEmpty()) { - bool ok; - int value = gridUnitString.toInt(&ok); - if (ok) { - gridUnitPx = value; - } - } - - return (view_area.bounding_rectangle().size.width.as_int() < tabletModeMinimimWithGU * gridUnitPx); -} - // FIXME: To be removed once shell has fully adopted short appIds!! QString toShortAppIdIfPossible(const QString &appId) { QRegExp longAppIdMask("[a-z0-9][a-z0-9+.-]+_[a-zA-Z0-9+.-]+_[0-9][a-zA-Z0-9.+:~-]*"); @@ -556,10 +526,6 @@ void ApplicationManager::onProcessStarting(const QString &appId) return; } - // override stage if necessary (i.e. side stage invalid on phone) - if (application->stage() == Application::SideStage && forceAllAppsIntoMainStage(m_mirServer)) - application->setStage(Application::MainStage); - add(application); Q_EMIT focusRequested(appId); } diff --git a/src/modules/Unity/Application/desktopfilereader.cpp b/src/modules/Unity/Application/desktopfilereader.cpp index 303e55f..2c2963a 100644 --- a/src/modules/Unity/Application/desktopfilereader.cpp +++ b/src/modules/Unity/Application/desktopfilereader.cpp @@ -68,6 +68,8 @@ DesktopFileReader::DesktopFileReader(const QString &appId, const QFileInfo &desk : d_ptr(new DesktopFileReaderPrivate(this)) { Q_D(DesktopFileReader); + qCDebug(QTMIR_APPLICATIONS) << "Loading desktop file" << desktopFile.absoluteFilePath() + << "for appId" << appId; d->appId = appId; d->file = desktopFile.absoluteFilePath(); @@ -202,6 +204,100 @@ QString DesktopFileReader::splashColorFooter() const return d->getKey("X-Ubuntu-Splash-Color-Footer"); } +Qt::ScreenOrientations DesktopFileReader::supportedOrientations() const +{ + Q_D(const DesktopFileReader); + Qt::ScreenOrientations result; + + if (!parseOrientations(d->getKey("X-Ubuntu-Supported-Orientations"), result)) { + qCWarning(QTMIR_APPLICATIONS) << d->file << "has an invalid X-Ubuntu-Supported-Orientations entry."; + } + + return result; +} + +bool DesktopFileReader::rotatesWindowContents() const +{ + Q_D(const DesktopFileReader); + bool result; + + if (!parseBoolean(d->getKey("X-Ubuntu-Rotates-Window-Contents"), result)) { + qCWarning(QTMIR_APPLICATIONS) << d->file << "has an invalid X-Ubuntu-Rotates-Window-Contents entry."; + } + + return result; +} + +bool DesktopFileReader::parseOrientations(const QString &rawString, Qt::ScreenOrientations &result) +{ + // Default to all orientations + result = Qt::PortraitOrientation | Qt::LandscapeOrientation + | Qt::InvertedPortraitOrientation | Qt::InvertedLandscapeOrientation; + + if (rawString.isEmpty()) { + return true; + } + + Qt::ScreenOrientations parsedOrientations = 0; + bool ok = true; + + QStringList orientationsList = rawString + .simplified() + .replace(QChar(','), ";") + .remove(QChar(' ')) + .remove(QChar('-')) + .remove(QChar('_')) + .toLower() + .split(";"); + + for (int i = 0; i < orientationsList.count() && ok; ++i) { + const QString &orientationString = orientationsList.at(i); + if (orientationString.isEmpty()) { + // skip it + continue; + } + + if (orientationString == "portrait") { + parsedOrientations |= Qt::PortraitOrientation; + } else if (orientationString == "landscape") { + parsedOrientations |= Qt::LandscapeOrientation; + } else if (orientationString == "invertedportrait") { + parsedOrientations |= Qt::InvertedPortraitOrientation; + } else if (orientationString == "invertedlandscape") { + parsedOrientations |= Qt::InvertedLandscapeOrientation; + } else if (orientationsList.count() == 1 && orientationString == "primary") { + // Special case: primary orientation must be alone + // There's no sense in supporting primary orientation + other orientations + // like "primary,landscape" + parsedOrientations = Qt::PrimaryOrientation; + } else { + ok = false; + } + } + + if (ok) { + result = parsedOrientations; + } + + return ok; +} + +bool DesktopFileReader::parseBoolean(const QString &rawString, bool &result) +{ + QString cookedString = rawString.trimmed().toLower(); + + result = cookedString == "y" + || cookedString == "1" + || cookedString == "yes" + || cookedString == "true"; + + return result || rawString.isEmpty() + || cookedString == "n" + || cookedString == "0" + || cookedString == "no" + || cookedString == "false"; +} + bool DesktopFileReader::loaded() const { Q_D(const DesktopFileReader); diff --git a/src/modules/Unity/Application/desktopfilereader.h b/src/modules/Unity/Application/desktopfilereader.h index 3670469..771855b 100644 --- a/src/modules/Unity/Application/desktopfilereader.h +++ b/src/modules/Unity/Application/desktopfilereader.h @@ -55,8 +55,13 @@ public: virtual QString splashColor() const; virtual QString splashColorHeader() const; virtual QString splashColorFooter() const; + virtual Qt::ScreenOrientations supportedOrientations() const; + virtual bool rotatesWindowContents() const; virtual bool loaded() const; + static bool parseOrientations(const QString &rawString, Qt::ScreenOrientations &result); + static bool parseBoolean(const QString &rawString, bool &result); + protected: DesktopFileReader(const QString &appId, const QFileInfo &desktopFile); diff --git a/src/modules/Unity/Application/mirsurfaceitem.cpp b/src/modules/Unity/Application/mirsurfaceitem.cpp index b816f65..c8d895a 100644 --- a/src/modules/Unity/Application/mirsurfaceitem.cpp +++ b/src/modules/Unity/Application/mirsurfaceitem.cpp @@ -196,7 +196,7 @@ MirSurfaceItem::MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface, , m_shell(shell) , m_firstFrameDrawn(false) , m_live(true) - , m_orientation(Qt::PortraitOrientation) + , m_orientationAngle(Angle0) , m_textureProvider(nullptr) , m_lastTouchEvent(nullptr) { @@ -306,49 +306,42 @@ MirSurfaceItem::State MirSurfaceItem::state() const return static_cast<MirSurfaceItem::State>(m_surface->state()); } -Qt::ScreenOrientation MirSurfaceItem::orientation() const +MirSurfaceItem::OrientationAngle MirSurfaceItem::orientationAngle() const { - return m_orientation; + return m_orientationAngle; } -void MirSurfaceItem::setOrientation(const Qt::ScreenOrientation orientation) +void MirSurfaceItem::setOrientationAngle(MirSurfaceItem::OrientationAngle angle) { - qCDebug(QTMIR_SURFACES) << "MirSurfaceItem::setOrientation - orientation=" << orientation; + qCDebug(QTMIR_SURFACES, "MirSurfaceItem::setOrientationAngle(%d)", angle); - if (m_orientation == orientation) + if (m_orientationAngle == angle) return; MirOrientation mirOrientation; - Qt::ScreenOrientation nativeOrientation = QGuiApplication::primaryScreen()->nativeOrientation(); - const bool landscapeNativeOrientation = (nativeOrientation == Qt::LandscapeOrientation); - Qt::ScreenOrientation requestedOrientation = orientation; - if (orientation == Qt::PrimaryOrientation) { // means orientation equals native orientation, set it as such - requestedOrientation = nativeOrientation; - } - - switch(requestedOrientation) { - case Qt::PortraitOrientation: - mirOrientation = (landscapeNativeOrientation) ? mir_orientation_right : mir_orientation_normal; + switch (angle) { + case Angle0: + mirOrientation = mir_orientation_normal; break; - case Qt::LandscapeOrientation: - mirOrientation = (landscapeNativeOrientation) ? mir_orientation_normal : mir_orientation_left; + case Angle90: + mirOrientation = mir_orientation_right; break; - case Qt::InvertedPortraitOrientation: - mirOrientation = (landscapeNativeOrientation) ? mir_orientation_left : mir_orientation_inverted; + case Angle180: + mirOrientation = mir_orientation_inverted; break; - case Qt::InvertedLandscapeOrientation: - mirOrientation = (landscapeNativeOrientation) ? mir_orientation_inverted : mir_orientation_right; + case Angle270: + mirOrientation = mir_orientation_left; break; default: - qWarning("Unrecognized Qt::ScreenOrientation!"); + qCWarning(QTMIR_SURFACES, "Unsupported orientation angle: %d", angle); return; } m_surface->set_orientation(mirOrientation); - m_orientation = orientation; - Q_EMIT orientationChanged(); + m_orientationAngle = angle; + Q_EMIT orientationAngleChanged(angle); } QString MirSurfaceItem::name() const diff --git a/src/modules/Unity/Application/mirsurfaceitem.h b/src/modules/Unity/Application/mirsurfaceitem.h index 769f4bb..fd3ab45 100644 --- a/src/modules/Unity/Application/mirsurfaceitem.h +++ b/src/modules/Unity/Application/mirsurfaceitem.h @@ -48,12 +48,17 @@ class MirSurfaceItem : public QQuickItem Q_OBJECT Q_ENUMS(Type) Q_ENUMS(State) + Q_ENUMS(OrientationAngle) Q_PROPERTY(Type type READ type NOTIFY typeChanged) Q_PROPERTY(State state READ state NOTIFY stateChanged) Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(bool live READ live NOTIFY liveChanged) - Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged DESIGNABLE false) + + // How many degrees, clockwise, the UI in the surface has to rotate to match with the + // shell UI orientation + Q_PROPERTY(OrientationAngle orientationAngle READ orientationAngle WRITE setOrientationAngle + NOTIFY orientationAngleChanged DESIGNABLE false) public: explicit MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface, @@ -83,12 +88,18 @@ public: Fullscreen = mir_surface_state_fullscreen, }; + enum OrientationAngle { + Angle0 = 0, + Angle90 = 90, + Angle180 = 180, + Angle270 = 270 + }; + //getters Type type() const; State state() const; QString name() const; bool live() const; - Qt::ScreenOrientation orientation() const; SessionInterface *session() const; Q_INVOKABLE void release(); @@ -102,7 +113,9 @@ public: bool isFirstFrameDrawn() const { return m_firstFrameDrawn; } - void setOrientation(const Qt::ScreenOrientation orientation); + OrientationAngle orientationAngle() const; + void setOrientationAngle(OrientationAngle angle); + void setSession(SessionInterface *app); // to allow easy touch event injection from tests @@ -116,7 +129,7 @@ Q_SIGNALS: void typeChanged(); void stateChanged(); void nameChanged(); - void orientationChanged(); + void orientationAngleChanged(OrientationAngle angle); void liveChanged(bool live); void firstFrameDrawn(MirSurfaceItem *item); @@ -182,7 +195,9 @@ private: MirShell *const m_shell; bool m_firstFrameDrawn; bool m_live; - Qt::ScreenOrientation m_orientation; //FIXME - have to save the state as Mir has no getter for it (bug:1357429) + + //FIXME - have to save the state as Mir has no getter for it (bug:1357429) + OrientationAngle m_orientationAngle; QMirSurfaceTextureProvider *m_textureProvider; @@ -218,5 +233,6 @@ private: } // namespace qtmir Q_DECLARE_METATYPE(qtmir::MirSurfaceItem*) +Q_DECLARE_METATYPE(qtmir::MirSurfaceItem::OrientationAngle) #endif // MIRSURFACEITEM_H diff --git a/src/platforms/mirserver/CMakeLists.txt b/src/platforms/mirserver/CMakeLists.txt index a47cb1a..60abe20 100644 --- a/src/platforms/mirserver/CMakeLists.txt +++ b/src/platforms/mirserver/CMakeLists.txt @@ -44,6 +44,7 @@ set(MIRSERVER_QPA_PLUGIN_SRC qteventfeeder.cpp plugin.cpp qmirserver.cpp + qmirserver_p.cpp sessionauthorizer.cpp sessionlistener.cpp surfaceobserver.cpp diff --git a/src/platforms/mirserver/display.cpp b/src/platforms/mirserver/display.cpp index 70a6b15..7228f6e 100644 --- a/src/platforms/mirserver/display.cpp +++ b/src/platforms/mirserver/display.cpp @@ -23,18 +23,13 @@ #include <mir/graphics/display.h> #include <mir/graphics/display_configuration.h> -#include <QDebug> namespace mg = mir::graphics; // TODO: Listen for display changes and update the list accordingly -Display::Display(const QSharedPointer<MirServer> &server, QObject *parent) - : QObject(parent) - , m_mirServer(server) +Display::Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig) { - std::shared_ptr<mir::graphics::DisplayConfiguration> displayConfig = m_mirServer->the_display()->configuration(); - displayConfig->for_each_output([this](mg::DisplayConfigurationOutput const& output) { if (output.used) { auto screen = new Screen(output); diff --git a/src/platforms/mirserver/display.h b/src/platforms/mirserver/display.h index 21c7767..bc77381 100644 --- a/src/platforms/mirserver/display.h +++ b/src/platforms/mirserver/display.h @@ -19,23 +19,21 @@ #ifndef DISPLAY_H #define DISPLAY_H -#include <QObject> #include <qpa/qplatformscreen.h> +#include <memory> -class MirServer; +namespace mir { namespace graphics { class DisplayConfiguration; }} -class Display : public QObject +class Display { - Q_OBJECT public: - Display(const QSharedPointer<MirServer> &server, QObject *parent = 0); - ~Display(); + Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig); + virtual ~Display(); QList<QPlatformScreen *> screens() const { return m_screens; } private: QList<QPlatformScreen *> m_screens; - const QSharedPointer<MirServer> m_mirServer; }; #endif // DISPLAY_H diff --git a/src/platforms/mirserver/miropenglcontext.cpp b/src/platforms/mirserver/miropenglcontext.cpp index cf5ef9d..cb84666 100644 --- a/src/platforms/mirserver/miropenglcontext.cpp +++ b/src/platforms/mirserver/miropenglcontext.cpp @@ -36,12 +36,11 @@ // (i.e. individual display output buffers) to use as a common base context. 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(); // create a temporary GL context to fetch the EGL display and config, so Qt can determine the surface format std::unique_ptr<mir::graphics::GLContext> mirContext = display->create_gl_context(); diff --git a/src/platforms/mirserver/miropenglcontext.h b/src/platforms/mirserver/miropenglcontext.h index e09a992..de3ec9c 100644 --- a/src/platforms/mirserver/miropenglcontext.h +++ b/src/platforms/mirserver/miropenglcontext.h @@ -52,7 +52,6 @@ public: #endif private: - const QSharedPointer<MirServer> m_mirServer; QSurfaceFormat m_format; #if GL_DEBUG QOpenGLDebugLogger *m_logger; diff --git a/src/platforms/mirserver/mirserverintegration.cpp b/src/platforms/mirserver/mirserverintegration.cpp index 2292831..ad33caa 100644 --- a/src/platforms/mirserver/mirserverintegration.cpp +++ b/src/platforms/mirserver/mirserverintegration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Canonical, Ltd. + * Copyright (C) 2013-2015 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by @@ -30,7 +30,6 @@ #include <qpa/qwindowsysteminterface.h> #include <QCoreApplication> -#include <QStringList> #include <QOpenGLContext> #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) @@ -41,10 +40,7 @@ // Mir #include <mir/graphics/display.h> -#include <mir/graphics/display_buffer.h> - -// std -#include <csignal> +#include <mir/graphics/display_configuration.h> // local #include "clipboard.h" @@ -66,36 +62,25 @@ MirServerIntegration::MirServerIntegration() #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) , m_eventDispatcher(createUnixEventDispatcher()) #endif + , m_mirServer(new QMirServer(QCoreApplication::arguments())) , m_display(nullptr) - , m_qmirServer(nullptr) , m_nativeInterface(nullptr) , m_clipboard(new Clipboard) { - // Start Mir server only once Qt has initialized its event dispatcher, see initialize() - - QStringList args = QCoreApplication::arguments(); - // convert arguments back into argc-argv form that Mir wants - char **argv; - argv = new char*[args.size() + 1]; - for (int i = 0; i < args.size(); i++) { - argv[i] = new char[strlen(args.at(i).toStdString().c_str())+1]; - memcpy(argv[i], args.at(i).toStdString().c_str(), strlen(args.at(i).toStdString().c_str())+1); - } - argv[args.size()] = '\0'; - // For access to sensors, qtmir uses qtubuntu-sensors. qtubuntu-sensors reads the // UBUNTU_PLATFORM_API_BACKEND variable to decide if to load a valid sensor backend or not. // For it to function we need to ensure a valid backend has been specified if (qEnvironmentVariableIsEmpty("UBUNTU_PLATFORM_API_BACKEND")) { - if (qgetenv("DESKTOP_SESSION").contains("mir")) { + if (qgetenv("DESKTOP_SESSION").contains("mir") || !qEnvironmentVariableIsSet("ANDROID_DATA")) { qputenv("UBUNTU_PLATFORM_API_BACKEND", "desktop_mirclient"); } else { qputenv("UBUNTU_PLATFORM_API_BACKEND", "touch_mirclient"); } } - m_mirServer = QSharedPointer<MirServer>( - new MirServer(args.length(), const_cast<const char**>(argv))); + // If Mir shuts down, quit. + QObject::connect(m_mirServer.data(), &QMirServer::stopped, + QCoreApplication::instance(), &QCoreApplication::quit); #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) QGuiApplicationPrivate::instance()->setEventDispatcher(eventDispatcher_); @@ -109,7 +94,6 @@ MirServerIntegration::~MirServerIntegration() { delete m_nativeInterface; delete m_display; - delete m_qmirServer; } bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const @@ -135,18 +119,21 @@ QPlatformWindow *MirServerIntegration::createPlatformWindow(QWindow *window) con DisplayWindow* displayWindow = nullptr; + auto const mirServer = m_mirServer->mirServer().lock(); mg::DisplayBuffer* first_buffer{nullptr}; mg::DisplaySyncGroup* first_group{nullptr}; - m_mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) { - if (!first_group) { - first_group = &group; - } - group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) { - if (!first_buffer) { - first_buffer = &buffer; + if (mirServer) { + mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) { + if (!first_group) { + first_group = &group; } + group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) { + if (!first_buffer) { + first_buffer = &buffer; + } + }); }); - }); + } // FIXME(gerry) this will go very bad for >1 display buffer if (first_group && first_buffer) @@ -168,7 +155,7 @@ QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { qDebug() << "createPlatformOpenGLContext" << context; - return new MirOpenGLContext(m_mirServer, context->format()); + return new MirOpenGLContext(m_mirServer->mirServer(), context->format()); } #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) @@ -181,10 +168,12 @@ QAbstractEventDispatcher *MirServerIntegration::createEventDispatcher() const void MirServerIntegration::initialize() { // Creates instance of and start the Mir server in a separate thread - m_qmirServer = new QMirServer(m_mirServer); + if (!m_mirServer->start()) { + exit(2); + } - m_display = new Display(m_mirServer); - m_nativeInterface = new NativeInterface(m_mirServer); + m_display = new Display(m_mirServer->mirServer().data()->the_display()->configuration()); + m_nativeInterface = new NativeInterface(m_mirServer->mirServer()); for (QPlatformScreen *screen : m_display->screens()) screenAdded(screen); diff --git a/src/platforms/mirserver/mirserverintegration.h b/src/platforms/mirserver/mirserverintegration.h index 37e0dc0..a02405e 100644 --- a/src/platforms/mirserver/mirserverintegration.h +++ b/src/platforms/mirserver/mirserverintegration.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Canonical, Ltd. + * Copyright (C) 2013-2015 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by @@ -69,8 +69,6 @@ public: QPlatformNativeInterface *nativeInterface() const override; private: - QSharedPointer<MirServer> m_mirServer; - QScopedPointer<QPlatformAccessibility> m_accessibility; QScopedPointer<QPlatformFontDatabase> m_fontDb; QScopedPointer<QPlatformServices> m_services; @@ -78,8 +76,9 @@ private: QScopedPointer<QAbstractEventDispatcher> m_eventDispatcher; #endif + QScopedPointer<QMirServer> m_mirServer; + Display *m_display; - QMirServer *m_qmirServer; NativeInterface *m_nativeInterface; QPlatformInputContext* m_inputContext; QScopedPointer<qtmir::Clipboard> m_clipboard; diff --git a/src/platforms/mirserver/nativeinterface.cpp b/src/platforms/mirserver/nativeinterface.cpp index b013345..6cc4c0d 100644 --- a/src/platforms/mirserver/nativeinterface.cpp +++ b/src/platforms/mirserver/nativeinterface.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Canonical, Ltd. + * Copyright (C) 2013-2015 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by @@ -18,7 +18,7 @@ #include "nativeinterface.h" -NativeInterface::NativeInterface(const QSharedPointer<MirServer> &server) +NativeInterface::NativeInterface(const QWeakPointer<MirServer> &server) : m_mirServer(server) { } @@ -27,14 +27,17 @@ void *NativeInterface::nativeResourceForIntegration(const QByteArray &resource) { void *result = nullptr; - if (resource == "SessionAuthorizer") - result = m_mirServer->sessionAuthorizer(); - else if (resource == "Shell") - result = m_mirServer->shell(); - else if (resource == "SessionListener") - result = m_mirServer->sessionListener(); - else if (resource == "PromptSessionListener") - result = m_mirServer->promptSessionListener(); + auto const server = m_mirServer.lock(); + if (server) { + if (resource == "SessionAuthorizer") + result = server->sessionAuthorizer(); + else if (resource == "Shell") + result = server->shell(); + else if (resource == "SessionListener") + result = server->sessionListener(); + else if (resource == "PromptSessionListener") + result = server->promptSessionListener(); + } return result; } diff --git a/src/platforms/mirserver/nativeinterface.h b/src/platforms/mirserver/nativeinterface.h index 5a5c377..da97663 100644 --- a/src/platforms/mirserver/nativeinterface.h +++ b/src/platforms/mirserver/nativeinterface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Canonical, Ltd. + * Copyright (C) 2013-2015 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by @@ -29,11 +29,11 @@ class NativeInterface : public QPlatformNativeInterface { public: - NativeInterface(const QSharedPointer<MirServer> &); + NativeInterface(const QWeakPointer<MirServer> &); virtual void *nativeResourceForIntegration(const QByteArray &resource); - QSharedPointer<MirServer> m_mirServer; + QWeakPointer<MirServer> m_mirServer; }; #endif // NATIVEINTEGRATION_H diff --git a/src/platforms/mirserver/qmirserver.cpp b/src/platforms/mirserver/qmirserver.cpp index f28393a..c7dc580 100644 --- a/src/platforms/mirserver/qmirserver.cpp +++ b/src/platforms/mirserver/qmirserver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Canonical, Ltd. + * Copyright (C) 2013-2015 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by @@ -19,80 +19,77 @@ #include <QCoreApplication> #include <QDebug> -#include <mir/main_loop.h> - // local +#include "mirserver.h" #include "qmirserver.h" +#include "qmirserver_p.h" -void MirServerWorker::run() +QMirServer::QMirServer(const QStringList &arguments, QObject *parent) + : QObject(parent) + , d_ptr(new QMirServerPrivate()) { - auto const main_loop = server->the_main_loop(); - // By enqueuing the notification code in the main loop, we are - // ensuring that the server has really and fully started before - // leaving wait_for_startup(). - main_loop->enqueue( - this, - [&] - { - std::lock_guard<std::mutex> lock(mutex); - mir_running = true; - started_cv.notify_one(); - }); - - server->run(); - Q_EMIT stopped(); + Q_D(QMirServer); + + // convert arguments back into argc-argv form that Mir wants + int argc = arguments.size(); + char **argv = new char*[argc + 1]; + for (int i = 0; i < argc; i++) { + argv[i] = new char[strlen(arguments.at(i).toStdString().c_str())+1]; + memcpy(argv[i], arguments.at(i).toStdString().c_str(), strlen(arguments.at(i).toStdString().c_str())+1); + } + argv[argc] = '\0'; + + d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv))); + + d->serverThread = new MirServerThread(d->server); + + connect(d->serverThread, &MirServerThread::stopped, this, &QMirServer::stopped); } -bool MirServerWorker::wait_for_mir_startup() +QMirServer::~QMirServer() { - std::unique_lock<decltype(mutex)> lock(mutex); - started_cv.wait_for(lock, std::chrono::seconds{10}, [&]{ return mir_running; }); - return mir_running; + stop(); } -QMirServer::QMirServer(const QSharedPointer<MirServer> &server, QObject *parent) - : QObject(parent) - , m_mirServer(new MirServerWorker(server)) +bool QMirServer::start() { - m_mirServer->moveToThread(&m_mirThread); + Q_D(QMirServer); - connect(this, &QMirServer::run, m_mirServer, &MirServerWorker::run); - connect(this, &QMirServer::stop, m_mirServer, &MirServerWorker::stop); + d->serverThread->start(QThread::TimeCriticalPriority); - connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QMirServer::shutDownMirServer); - connect(m_mirServer, &MirServerWorker::stopped, this, &QMirServer::shutDownQApplication, Qt::DirectConnection); // since no event loop - - m_mirThread.start(QThread::TimeCriticalPriority); - Q_EMIT run(); - - if (!m_mirServer->wait_for_mir_startup()) + if (!d->serverThread->waitForMirStartup()) { qCritical() << "ERROR: QMirServer - Mir failed to start"; - exit(2); + return false; } -} -QMirServer::~QMirServer() -{ - shutDownMirServer(); + Q_EMIT started(); + return true; } -void QMirServer::shutDownMirServer() +void QMirServer::stop() { - if (m_mirThread.isRunning()) { - m_mirServer->stop(); - m_mirThread.wait(); + Q_D(QMirServer); + + if (d->serverThread->isRunning()) { + d->serverThread->stop(); + if (!d->serverThread->wait(10000)) { + // do something to indicate fail during shutdown + qCritical() << "ERROR: QMirServer - Mir failed to shut down correctly, terminating it"; + d->serverThread->terminate(); + } } } -void QMirServer::shutDownQApplication() +bool QMirServer::isRunning() const { - if (m_mirThread.isRunning()) - m_mirThread.quit(); + Q_D(const QMirServer); + return d->serverThread->isRunning(); +} - // if unexpected mir server stop, better quit the QApplication - if (!QCoreApplication::closingDown()) { - QCoreApplication::quit(); - } +QWeakPointer<MirServer> QMirServer::mirServer() const +{ + Q_D(const QMirServer); + return d->server.toWeakRef(); } diff --git a/src/platforms/mirserver/qmirserver.h b/src/platforms/mirserver/qmirserver.h index be74149..ecb943b 100644 --- a/src/platforms/mirserver/qmirserver.h +++ b/src/platforms/mirserver/qmirserver.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Canonical, Ltd. + * Copyright (C) 2013-2015 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by @@ -19,63 +19,35 @@ // Qt #include <QObject> -#include <QThread> -#include <QSharedPointer> +#include <QWeakPointer> -// local -#include "mirserver.h" +class QMirServerPrivate; +class MirServer; -#include <condition_variable> -#include <mutex> - -// Wrap mir::Server with QObject, so it can be controlled via QThread -class MirServerWorker : public QObject +class QMirServer: public QObject { Q_OBJECT public: - MirServerWorker(const QSharedPointer<MirServer> &server) - : server(server) - {} - - bool wait_for_mir_startup(); + QMirServer(const QStringList &arguments, QObject* parent=0); + virtual ~QMirServer(); -Q_SIGNALS: - void stopped(); + bool start(); + Q_SLOT void stop(); + bool isRunning() const; -public Q_SLOTS: - void run(); - void stop() { server->stop(); } - -private: - std::mutex mutex; - std::condition_variable started_cv; - bool mir_running{false}; - - const QSharedPointer<MirServer> server; -}; - - -class QMirServer: public QObject -{ - Q_OBJECT - -public: - QMirServer(const QSharedPointer<MirServer> &config, QObject* parent=0); - ~QMirServer(); + QWeakPointer<MirServer> mirServer() const; Q_SIGNALS: - void run(); - void stop(); + void started(); + void stopped(); -protected Q_SLOTS: - void shutDownMirServer(); - void shutDownQApplication(); +protected: + QMirServerPrivate * const d_ptr; private: - QThread m_mirThread; - MirServerWorker *m_mirServer; Q_DISABLE_COPY(QMirServer) + Q_DECLARE_PRIVATE(QMirServer) }; #endif // QMIRSERVER_H diff --git a/src/platforms/mirserver/qmirserver_p.cpp b/src/platforms/mirserver/qmirserver_p.cpp new file mode 100644 index 0000000..d784a46 --- /dev/null +++ b/src/platforms/mirserver/qmirserver_p.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Canonical, Ltd. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3, as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// Mir +#include <mir/main_loop.h> + +// local +#include "qmirserver_p.h" + + +void MirServerThread::run() +{ + auto const main_loop = server->the_main_loop(); + // By enqueuing the notification code in the main loop, we are + // ensuring that the server has really and fully started before + // leaving wait_for_startup(). + main_loop->enqueue( + this, + [&] + { + std::lock_guard<std::mutex> lock(mutex); + mir_running = true; + started_cv.notify_one(); + }); + + server->run(); // blocks until Mir server stopped + Q_EMIT stopped(); +} + +void MirServerThread::stop() +{ + server->stop(); +} + +bool MirServerThread::waitForMirStartup() +{ + std::unique_lock<decltype(mutex)> lock(mutex); + started_cv.wait_for(lock, std::chrono::seconds{10}, [&]{ return mir_running; }); + return mir_running; +} diff --git a/src/platforms/mirserver/qmirserver_p.h b/src/platforms/mirserver/qmirserver_p.h new file mode 100644 index 0000000..6e86d8d --- /dev/null +++ b/src/platforms/mirserver/qmirserver_p.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 Canonical, Ltd. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3, as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QMIRSERVER_P_H +#define QMIRSERVER_P_H + +// Qt +#include <QThread> +#include <QSharedPointer> + +// std +#include <condition_variable> +#include <mutex> + +// local +#include "mirserver.h" + +class QMirServer; +class MirServerThread; + +struct QMirServerPrivate +{ + QSharedPointer<MirServer> server; + MirServerThread *serverThread; +}; + + +class MirServerThread : public QThread +{ + Q_OBJECT + +public: + MirServerThread(const QSharedPointer<MirServer> &server) + : server(server) + {} + + bool waitForMirStartup(); + +Q_SIGNALS: + void stopped(); + +public Q_SLOTS: + void run() override; + void stop(); + +private: + std::mutex mutex; + std::condition_variable started_cv; + bool mir_running{false}; + + const QSharedPointer<MirServer> server; +}; + +#endif // QMIRSERVER_P_H |