Mirclient: update based on upstream development in lp:qtubuntu
This is based on revision 360 of lp:qtubuntu. Main features/bugs fixed: - fix QQuickWidget-based app rendering - wire up Qt window types to Mir to enable desktop-based applications to function with a window manager - use QEGLPlatformContext and QEGLPBuffer instead of custom code - correctly populate and update list of QScreens - support for switching keyboard layouts - improve window resizing to fix visual glitching Change-Id: If816a858eb10b6356275d4b80c89a72562b3c29f Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io> Reviewed-by: Matti Paaso <matti.paaso@qt.io>
This commit is contained in:
parent
4b507e8257
commit
c28fde3fda
@ -168,7 +168,7 @@
|
||||
"label": "Mir client libraries",
|
||||
"test": "qpa/mirclient",
|
||||
"sources": [
|
||||
{ "type": "pkgConfig", "args": "egl mirclient ubuntu-platform-api" }
|
||||
{ "type": "pkgConfig", "args": "egl mirclient ubuntu-platform-api libcontent-hub" }
|
||||
]
|
||||
},
|
||||
"mtdev": {
|
||||
|
@ -5,6 +5,9 @@ QT += \
|
||||
theme_support-private eventdispatcher_support-private \
|
||||
fontdatabase_support-private egl_support-private
|
||||
|
||||
qtHaveModule(linuxaccessibility_support-private): \
|
||||
QT += linuxaccessibility_support-private
|
||||
|
||||
DEFINES += MESA_EGL_NO_X11_HEADERS
|
||||
# CONFIG += c++11 # only enables C++0x
|
||||
QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall
|
||||
@ -13,9 +16,12 @@ QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined
|
||||
QMAKE_USE_PRIVATE += mirclient
|
||||
|
||||
SOURCES = \
|
||||
qmirclientappstatecontroller.cpp \
|
||||
qmirclientbackingstore.cpp \
|
||||
qmirclientclipboard.cpp \
|
||||
qmirclientcursor.cpp \
|
||||
qmirclientdebugextension.cpp \
|
||||
qmirclientdesktopwindow.cpp \
|
||||
qmirclientglcontext.cpp \
|
||||
qmirclientinput.cpp \
|
||||
qmirclientintegration.cpp \
|
||||
@ -23,13 +29,17 @@ SOURCES = \
|
||||
qmirclientplatformservices.cpp \
|
||||
qmirclientplugin.cpp \
|
||||
qmirclientscreen.cpp \
|
||||
qmirclientscreenobserver.cpp \
|
||||
qmirclienttheme.cpp \
|
||||
qmirclientwindow.cpp
|
||||
|
||||
HEADERS = \
|
||||
qmirclientappstatecontroller.h \
|
||||
qmirclientbackingstore.h \
|
||||
qmirclientclipboard.h \
|
||||
qmirclientcursor.h \
|
||||
qmirclientdebugextension.h \
|
||||
qmirclientdesktopwindow.h \
|
||||
qmirclientglcontext.h \
|
||||
qmirclientinput.h \
|
||||
qmirclientintegration.h \
|
||||
@ -39,9 +49,17 @@ HEADERS = \
|
||||
qmirclientplatformservices.h \
|
||||
qmirclientplugin.h \
|
||||
qmirclientscreen.h \
|
||||
qmirclientscreenobserver.h \
|
||||
qmirclienttheme.h \
|
||||
qmirclientwindow.h
|
||||
|
||||
# libxkbcommon
|
||||
!qtConfig(xkbcommon-system) {
|
||||
include(../../../3rdparty/xkbcommon.pri)
|
||||
} else {
|
||||
QMAKE_USE += xkbcommon
|
||||
}
|
||||
|
||||
PLUGIN_TYPE = platforms
|
||||
PLUGIN_CLASS_NAME = MirServerIntegrationPlugin
|
||||
!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
|
||||
|
102
src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp
Normal file
102
src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "qmirclientappstatecontroller.h"
|
||||
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
|
||||
/*
|
||||
* QMirClientAppStateController - updates Qt's QApplication::applicationState property.
|
||||
*
|
||||
* Tries to avoid active-inactive-active invocations using a timer. The rapid state
|
||||
* change can confuse some applications.
|
||||
*/
|
||||
|
||||
QMirClientAppStateController::QMirClientAppStateController()
|
||||
: m_suspended(false)
|
||||
, m_lastActive(true)
|
||||
{
|
||||
m_inactiveTimer.setSingleShot(true);
|
||||
m_inactiveTimer.setInterval(10);
|
||||
QObject::connect(&m_inactiveTimer, &QTimer::timeout, []()
|
||||
{
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
|
||||
});
|
||||
}
|
||||
|
||||
void QMirClientAppStateController::setSuspended()
|
||||
{
|
||||
m_inactiveTimer.stop();
|
||||
if (!m_suspended) {
|
||||
m_suspended = true;
|
||||
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientAppStateController::setResumed()
|
||||
{
|
||||
m_inactiveTimer.stop();
|
||||
if (m_suspended) {
|
||||
m_suspended = false;
|
||||
|
||||
if (m_lastActive) {
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
|
||||
} else {
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientAppStateController::setWindowFocused(bool focused)
|
||||
{
|
||||
if (m_suspended) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (focused) {
|
||||
m_inactiveTimer.stop();
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
|
||||
} else {
|
||||
m_inactiveTimer.start();
|
||||
}
|
||||
|
||||
m_lastActive = focused;
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef QMIRCLIENTAPPSTATECONTROLLER_H
|
||||
#define QMIRCLIENTAPPSTATECONTROLLER_H
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
class QMirClientAppStateController
|
||||
{
|
||||
public:
|
||||
QMirClientAppStateController();
|
||||
|
||||
void setSuspended();
|
||||
void setResumed();
|
||||
|
||||
void setWindowFocused(bool focused);
|
||||
|
||||
private:
|
||||
bool m_suspended;
|
||||
bool m_lastActive;
|
||||
QTimer m_inactiveTimer;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTAPPSTATECONTROLLER_H
|
@ -61,6 +61,7 @@ QMirClientBackingStore::QMirClientBackingStore(QWindow* window)
|
||||
|
||||
QMirClientBackingStore::~QMirClientBackingStore()
|
||||
{
|
||||
mContext->makeCurrent(window()); // needed as QOpenGLTexture destructor assumes current context
|
||||
}
|
||||
|
||||
void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const QPoint& offset)
|
||||
@ -76,7 +77,6 @@ void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const
|
||||
mBlitter->create();
|
||||
|
||||
mBlitter->bind();
|
||||
mBlitter->setRedBlueSwizzle(true);
|
||||
mBlitter->blit(mTexture->textureId(), QMatrix4x4(), QOpenGLTextureBlitter::OriginTopLeft);
|
||||
mBlitter->release();
|
||||
|
||||
@ -137,7 +137,9 @@ void QMirClientBackingStore::beginPaint(const QRegion& region)
|
||||
|
||||
void QMirClientBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/)
|
||||
{
|
||||
mImage = QImage(size, QImage::Format_RGB32);
|
||||
mImage = QImage(size, QImage::Format_RGBA8888);
|
||||
|
||||
mContext->makeCurrent(window());
|
||||
|
||||
if (mTexture->isCreated())
|
||||
mTexture->destroy();
|
||||
@ -147,3 +149,9 @@ QPaintDevice* QMirClientBackingStore::paintDevice()
|
||||
{
|
||||
return &mImage;
|
||||
}
|
||||
|
||||
QImage QMirClientBackingStore::toImage() const
|
||||
{
|
||||
// used by QPlatformBackingStore::composeAndFlush
|
||||
return mImage;
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ public:
|
||||
void flush(QWindow* window, const QRegion& region, const QPoint& offset) override;
|
||||
void resize(const QSize& size, const QRegion& staticContents) override;
|
||||
QPaintDevice* paintDevice() override;
|
||||
QImage toImage() const override;
|
||||
|
||||
protected:
|
||||
void updateTexture();
|
||||
|
@ -39,41 +39,36 @@
|
||||
|
||||
|
||||
#include "qmirclientclipboard.h"
|
||||
#include "qmirclientlogging.h"
|
||||
#include "qmirclientwindow.h"
|
||||
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QGuiApplication>
|
||||
#include <QSignalBlocker>
|
||||
#include <QtCore/QMimeData>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QDBusPendingReply>
|
||||
|
||||
// FIXME(loicm) The clipboard data format is not defined by Ubuntu Platform API
|
||||
// which makes it impossible to have non-Qt applications communicate with Qt
|
||||
// applications through the clipboard API. The solution would be to have
|
||||
// Ubuntu Platform define the data format or propose an API that supports
|
||||
// embedding different mime types in the clipboard.
|
||||
// content-hub
|
||||
#include <com/ubuntu/content/hub.h>
|
||||
|
||||
// Data format:
|
||||
// number of mime types (sizeof(int))
|
||||
// data layout ((4 * sizeof(int)) * number of mime types)
|
||||
// mime type string offset (sizeof(int))
|
||||
// mime type string size (sizeof(int))
|
||||
// data offset (sizeof(int))
|
||||
// data size (sizeof(int))
|
||||
// data (n bytes)
|
||||
|
||||
namespace {
|
||||
|
||||
const int maxFormatsCount = 16;
|
||||
const int maxBufferSize = 4 * 1024 * 1024; // 4 Mb
|
||||
|
||||
}
|
||||
// get this cumbersome nested namespace out of the way
|
||||
using namespace com::ubuntu::content;
|
||||
|
||||
QMirClientClipboard::QMirClientClipboard()
|
||||
: mMimeData(new QMimeData)
|
||||
, mIsOutdated(true)
|
||||
, mUpdatesDisabled(false)
|
||||
, mDBusSetupDone(false)
|
||||
, mContentHub(Hub::Client::instance())
|
||||
{
|
||||
connect(mContentHub, &Hub::pasteboardChanged, this, [this]() {
|
||||
if (mClipboardState == QMirClientClipboard::SyncedClipboard) {
|
||||
mClipboardState = QMirClientClipboard::OutdatedClipboard;
|
||||
emitChanged(QClipboard::Clipboard);
|
||||
}
|
||||
});
|
||||
|
||||
connect(qGuiApp, &QGuiApplication::applicationStateChanged,
|
||||
this, &QMirClientClipboard::onApplicationStateChanged);
|
||||
|
||||
requestMimeData();
|
||||
}
|
||||
|
||||
QMirClientClipboard::~QMirClientClipboard()
|
||||
@ -81,202 +76,39 @@ QMirClientClipboard::~QMirClientClipboard()
|
||||
delete mMimeData;
|
||||
}
|
||||
|
||||
void QMirClientClipboard::requestDBusClipboardContents()
|
||||
{
|
||||
if (!mDBusSetupDone) {
|
||||
setupDBus();
|
||||
}
|
||||
|
||||
if (!mPendingGetContentsCall.isNull())
|
||||
return;
|
||||
|
||||
QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("GetContents"));
|
||||
|
||||
mPendingGetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
|
||||
|
||||
QObject::connect(mPendingGetContentsCall.data(), &QDBusPendingCallWatcher::finished,
|
||||
this, &QMirClientClipboard::onDBusClipboardGetContentsFinished);
|
||||
}
|
||||
|
||||
void QMirClientClipboard::onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher* call)
|
||||
{
|
||||
Q_ASSERT(call == mPendingGetContentsCall.data());
|
||||
|
||||
QDBusPendingReply<QByteArray> reply = *call;
|
||||
if (Q_UNLIKELY(reply.isError())) {
|
||||
qCritical("QMirClientClipboard - Failed to get system clipboard contents via D-Bus. %s, %s",
|
||||
qPrintable(reply.error().name()), qPrintable(reply.error().message()));
|
||||
// TODO: Might try again later a number of times...
|
||||
} else {
|
||||
QByteArray serializedMimeData = reply.argumentAt<0>();
|
||||
updateMimeData(serializedMimeData);
|
||||
}
|
||||
call->deleteLater();
|
||||
}
|
||||
|
||||
void QMirClientClipboard::onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher *call)
|
||||
{
|
||||
QDBusPendingReply<void> reply = *call;
|
||||
if (Q_UNLIKELY(reply.isError())) {
|
||||
qCritical("QMirClientClipboard - Failed to set the system clipboard contents via D-Bus. %s, %s",
|
||||
qPrintable(reply.error().name()), qPrintable(reply.error().message()));
|
||||
// TODO: Might try again later a number of times...
|
||||
}
|
||||
call->deleteLater();
|
||||
}
|
||||
|
||||
void QMirClientClipboard::updateMimeData(const QByteArray &serializedMimeData)
|
||||
{
|
||||
if (mUpdatesDisabled)
|
||||
return;
|
||||
|
||||
QMimeData *newMimeData = deserializeMimeData(serializedMimeData);
|
||||
if (newMimeData) {
|
||||
delete mMimeData;
|
||||
mMimeData = newMimeData;
|
||||
mIsOutdated = false;
|
||||
emitChanged(QClipboard::Clipboard);
|
||||
} else {
|
||||
qWarning("QMirClientClipboard - Got invalid serialized mime data. Ignoring it.");
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientClipboard::setupDBus()
|
||||
{
|
||||
QDBusConnection dbusConnection = QDBusConnection::sessionBus();
|
||||
|
||||
bool ok = dbusConnection.connect(
|
||||
QStringLiteral("com.canonical.QtMir"),
|
||||
QStringLiteral("/com/canonical/QtMir/Clipboard"),
|
||||
QStringLiteral("com.canonical.QtMir.Clipboard"),
|
||||
QStringLiteral("ContentsChanged"),
|
||||
this, SLOT(updateMimeData(QByteArray)));
|
||||
if (Q_UNLIKELY(!ok))
|
||||
qCritical("QMirClientClipboard - Failed to connect to ContentsChanged signal form the D-Bus system clipboard.");
|
||||
|
||||
mDBusClipboard = new QDBusInterface(QStringLiteral("com.canonical.QtMir"),
|
||||
QStringLiteral("/com/canonical/QtMir/Clipboard"),
|
||||
QStringLiteral("com.canonical.QtMir.Clipboard"),
|
||||
dbusConnection);
|
||||
|
||||
mDBusSetupDone = true;
|
||||
}
|
||||
|
||||
QByteArray QMirClientClipboard::serializeMimeData(QMimeData *mimeData) const
|
||||
{
|
||||
Q_ASSERT(mimeData != nullptr);
|
||||
|
||||
const QStringList formats = mimeData->formats();
|
||||
const int formatCount = qMin(formats.size(), maxFormatsCount);
|
||||
const int headerSize = sizeof(int) + (formatCount * 4 * sizeof(int));
|
||||
int bufferSize = headerSize;
|
||||
|
||||
for (int i = 0; i < formatCount; i++)
|
||||
bufferSize += formats[i].size() + mimeData->data(formats[i]).size();
|
||||
|
||||
QByteArray serializedMimeData;
|
||||
if (bufferSize <= maxBufferSize) {
|
||||
// Serialize data.
|
||||
serializedMimeData.resize(bufferSize);
|
||||
{
|
||||
char *buffer = serializedMimeData.data();
|
||||
int* header = reinterpret_cast<int*>(serializedMimeData.data());
|
||||
int offset = headerSize;
|
||||
header[0] = formatCount;
|
||||
for (int i = 0; i < formatCount; i++) {
|
||||
const QByteArray data = mimeData->data(formats[i]);
|
||||
const int formatOffset = offset;
|
||||
const int formatSize = formats[i].size();
|
||||
const int dataOffset = offset + formatSize;
|
||||
const int dataSize = data.size();
|
||||
memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize);
|
||||
memcpy(&buffer[dataOffset], data.data(), dataSize);
|
||||
header[i*4+1] = formatOffset;
|
||||
header[i*4+2] = formatSize;
|
||||
header[i*4+3] = dataOffset;
|
||||
header[i*4+4] = dataSize;
|
||||
offset += formatSize + dataSize;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning("QMirClientClipboard: Not sending contents (%d bytes) to the global clipboard as it's"
|
||||
" bigger than the maximum allowed size of %d bytes", bufferSize, maxBufferSize);
|
||||
}
|
||||
|
||||
return serializedMimeData;
|
||||
}
|
||||
|
||||
QMimeData *QMirClientClipboard::deserializeMimeData(const QByteArray &serializedMimeData) const
|
||||
{
|
||||
if (static_cast<std::size_t>(serializedMimeData.size()) < sizeof(int)) {
|
||||
// Data is invalid
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
|
||||
const char* const buffer = serializedMimeData.constData();
|
||||
const int* const header = reinterpret_cast<const int*>(serializedMimeData.constData());
|
||||
|
||||
const int count = qMin(header[0], maxFormatsCount);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
const int formatOffset = header[i*4+1];
|
||||
const int formatSize = header[i*4+2];
|
||||
const int dataOffset = header[i*4+3];
|
||||
const int dataSize = header[i*4+4];
|
||||
|
||||
if (formatOffset + formatSize <= serializedMimeData.size()
|
||||
&& dataOffset + dataSize <= serializedMimeData.size()) {
|
||||
|
||||
QString mimeType = QString::fromLatin1(&buffer[formatOffset], formatSize);
|
||||
QByteArray mimeDataBytes(&buffer[dataOffset], dataSize);
|
||||
|
||||
mimeData->setData(mimeType, mimeDataBytes);
|
||||
}
|
||||
}
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode)
|
||||
{
|
||||
if (mode != QClipboard::Clipboard)
|
||||
return nullptr;
|
||||
|
||||
if (mIsOutdated && mPendingGetContentsCall.isNull()) {
|
||||
requestDBusClipboardContents();
|
||||
// Blocks dataChanged() signal from being emitted. Makes no sense to emit it from
|
||||
// inside the data getter.
|
||||
const QSignalBlocker blocker(this);
|
||||
|
||||
if (mClipboardState == OutdatedClipboard) {
|
||||
updateMimeData();
|
||||
} else if (mClipboardState == SyncingClipboard) {
|
||||
mPasteReply->waitForFinished();
|
||||
}
|
||||
|
||||
// Return whatever we have at the moment instead of blocking until we have something.
|
||||
//
|
||||
// This might be called during app startup just for the sake of checking if some
|
||||
// "Paste" UI control should be enabled or not.
|
||||
// We will emit QClipboard::changed() once we finally have something.
|
||||
return mMimeData;
|
||||
}
|
||||
|
||||
void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode)
|
||||
{
|
||||
if (mode != QClipboard::Clipboard)
|
||||
return;
|
||||
QWindow *focusWindow = QGuiApplication::focusWindow();
|
||||
if (focusWindow && mode == QClipboard::Clipboard && mimeData != nullptr) {
|
||||
QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
|
||||
|
||||
if (!mPendingGetContentsCall.isNull()) {
|
||||
// Ignore whatever comes from the system clipboard as we are going to change it anyway
|
||||
QObject::disconnect(mPendingGetContentsCall.data(), 0, this, 0);
|
||||
mUpdatesDisabled = true;
|
||||
mPendingGetContentsCall->waitForFinished();
|
||||
mUpdatesDisabled = false;
|
||||
delete mPendingGetContentsCall.data();
|
||||
}
|
||||
QDBusPendingCall reply = mContentHub->createPaste(surfaceId, *mimeData);
|
||||
|
||||
if (mimeData != nullptr) {
|
||||
QByteArray serializedMimeData = serializeMimeData(mimeData);
|
||||
if (!serializedMimeData.isEmpty()) {
|
||||
setDBusClipboardContents(serializedMimeData);
|
||||
}
|
||||
// Don't care whether it succeeded
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished,
|
||||
watcher, &QObject::deleteLater);
|
||||
|
||||
mMimeData = mimeData;
|
||||
mClipboardState = SyncedClipboard;
|
||||
emitChanged(QClipboard::Clipboard);
|
||||
}
|
||||
}
|
||||
@ -292,25 +124,58 @@ bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardContents)
|
||||
void QMirClientClipboard::onApplicationStateChanged(Qt::ApplicationState state)
|
||||
{
|
||||
if (!mDBusSetupDone) {
|
||||
setupDBus();
|
||||
if (state == Qt::ApplicationActive) {
|
||||
// Only focused or active applications might be allowed to paste, so we probably
|
||||
// missed changes in the clipboard while we were hidden, inactive or, more importantly,
|
||||
// suspended.
|
||||
requestMimeData();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mPendingSetContentsCall.isNull()) {
|
||||
// Ignore any previous set call as we are going to overwrite it anyway
|
||||
QObject::disconnect(mPendingSetContentsCall.data(), 0, this, 0);
|
||||
mUpdatesDisabled = true;
|
||||
mPendingSetContentsCall->waitForFinished();
|
||||
mUpdatesDisabled = false;
|
||||
delete mPendingSetContentsCall.data();
|
||||
void QMirClientClipboard::updateMimeData()
|
||||
{
|
||||
if (qGuiApp->applicationState() != Qt::ApplicationActive) {
|
||||
// Don't even bother asking as content-hub would probably ignore our request (and should).
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("SetContents"), clipboardContents);
|
||||
delete mMimeData;
|
||||
|
||||
mPendingSetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
|
||||
|
||||
QObject::connect(mPendingSetContentsCall.data(), &QDBusPendingCallWatcher::finished,
|
||||
this, &QMirClientClipboard::onDBusClipboardSetContentsFinished);
|
||||
QWindow *focusWindow = QGuiApplication::focusWindow();
|
||||
if (focusWindow) {
|
||||
QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
|
||||
mMimeData = mContentHub->latestPaste(surfaceId);
|
||||
mClipboardState = SyncedClipboard;
|
||||
emitChanged(QClipboard::Clipboard);
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientClipboard::requestMimeData()
|
||||
{
|
||||
if (qGuiApp->applicationState() != Qt::ApplicationActive) {
|
||||
// Don't even bother asking as content-hub would probably ignore our request (and should).
|
||||
return;
|
||||
}
|
||||
|
||||
QWindow *focusWindow = QGuiApplication::focusWindow();
|
||||
if (!focusWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
|
||||
QDBusPendingCall reply = mContentHub->requestLatestPaste(surfaceId);
|
||||
mClipboardState = SyncingClipboard;
|
||||
|
||||
mPasteReply = new QDBusPendingCallWatcher(reply, this);
|
||||
connect(mPasteReply, &QDBusPendingCallWatcher::finished,
|
||||
this, [this]() {
|
||||
delete mMimeData;
|
||||
mMimeData = mContentHub->paste(*mPasteReply);
|
||||
mClipboardState = SyncedClipboard;
|
||||
mPasteReply->deleteLater();
|
||||
mPasteReply = nullptr;
|
||||
emitChanged(QClipboard::Clipboard);
|
||||
});
|
||||
}
|
||||
|
@ -45,7 +45,15 @@
|
||||
|
||||
#include <QMimeData>
|
||||
#include <QPointer>
|
||||
class QDBusInterface;
|
||||
|
||||
namespace com {
|
||||
namespace ubuntu {
|
||||
namespace content {
|
||||
class Hub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class QDBusPendingCallWatcher;
|
||||
|
||||
class QMirClientClipboard : public QObject, public QPlatformClipboard
|
||||
@ -61,31 +69,24 @@ public:
|
||||
bool supportsMode(QClipboard::Mode mode) const override;
|
||||
bool ownsMode(QClipboard::Mode mode) const override;
|
||||
|
||||
void requestDBusClipboardContents();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*);
|
||||
void onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*);
|
||||
void updateMimeData(const QByteArray &serializedMimeData);
|
||||
void onApplicationStateChanged(Qt::ApplicationState state);
|
||||
|
||||
private:
|
||||
void setupDBus();
|
||||
|
||||
QByteArray serializeMimeData(QMimeData *mimeData) const;
|
||||
QMimeData *deserializeMimeData(const QByteArray &serializedMimeData) const;
|
||||
|
||||
void setDBusClipboardContents(const QByteArray &clipboardContents);
|
||||
void updateMimeData();
|
||||
void requestMimeData();
|
||||
|
||||
QMimeData *mMimeData;
|
||||
bool mIsOutdated;
|
||||
|
||||
QPointer<QDBusInterface> mDBusClipboard;
|
||||
enum {
|
||||
OutdatedClipboard, // Our mimeData is outdated, need to fetch latest from ContentHub
|
||||
SyncingClipboard, // Our mimeData is outdated and we are waiting for ContentHub to reply with the latest paste
|
||||
SyncedClipboard // Our mimeData is in sync with what ContentHub has
|
||||
} mClipboardState{OutdatedClipboard};
|
||||
|
||||
QPointer<QDBusPendingCallWatcher> mPendingGetContentsCall;
|
||||
QPointer<QDBusPendingCallWatcher> mPendingSetContentsCall;
|
||||
com::ubuntu::content::Hub *mContentHub;
|
||||
|
||||
bool mUpdatesDisabled;
|
||||
bool mDBusSetupDone;
|
||||
QDBusPendingCallWatcher *mPasteReply{nullptr};
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTCLIPBOARD_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Canonical, Ltd.
|
||||
** Copyright (C) 2015-2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -45,35 +45,41 @@
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(mirclientCursor, "qt.qpa.mirclient.cursor", QtWarningMsg)
|
||||
|
||||
QMirClientCursor::QMirClientCursor(MirConnection *connection)
|
||||
: mConnection(connection)
|
||||
{
|
||||
mShapeToCursorName[Qt::ArrowCursor] = "left_ptr";
|
||||
/*
|
||||
* TODO: Add the missing cursors to Mir (LP: #1388987)
|
||||
* Those are the ones without a mir_ prefix, which are X11 cursors
|
||||
* and won't be understood by any shell other than Unity8.
|
||||
*/
|
||||
mShapeToCursorName[Qt::ArrowCursor] = mir_arrow_cursor_name;
|
||||
mShapeToCursorName[Qt::UpArrowCursor] = "up_arrow";
|
||||
mShapeToCursorName[Qt::CrossCursor] = "cross";
|
||||
mShapeToCursorName[Qt::WaitCursor] = "watch";
|
||||
mShapeToCursorName[Qt::IBeamCursor] = "xterm";
|
||||
mShapeToCursorName[Qt::SizeVerCursor] = "size_ver";
|
||||
mShapeToCursorName[Qt::SizeHorCursor] = "size_hor";
|
||||
mShapeToCursorName[Qt::SizeBDiagCursor] = "size_bdiag";
|
||||
mShapeToCursorName[Qt::SizeFDiagCursor] = "size_fdiag";
|
||||
mShapeToCursorName[Qt::SizeAllCursor] = "size_all";
|
||||
mShapeToCursorName[Qt::BlankCursor] = "blank";
|
||||
mShapeToCursorName[Qt::SplitVCursor] = "split_v";
|
||||
mShapeToCursorName[Qt::SplitHCursor] = "split_h";
|
||||
mShapeToCursorName[Qt::PointingHandCursor] = "hand";
|
||||
mShapeToCursorName[Qt::CrossCursor] = mir_crosshair_cursor_name;
|
||||
mShapeToCursorName[Qt::WaitCursor] = mir_busy_cursor_name;
|
||||
mShapeToCursorName[Qt::IBeamCursor] = mir_caret_cursor_name;
|
||||
mShapeToCursorName[Qt::SizeVerCursor] = mir_vertical_resize_cursor_name;
|
||||
mShapeToCursorName[Qt::SizeHorCursor] = mir_horizontal_resize_cursor_name;
|
||||
mShapeToCursorName[Qt::SizeBDiagCursor] = mir_diagonal_resize_bottom_to_top_cursor_name;
|
||||
mShapeToCursorName[Qt::SizeFDiagCursor] = mir_diagonal_resize_top_to_bottom_cursor_name;
|
||||
mShapeToCursorName[Qt::SizeAllCursor] = mir_omnidirectional_resize_cursor_name;
|
||||
mShapeToCursorName[Qt::BlankCursor] = mir_disabled_cursor_name;
|
||||
mShapeToCursorName[Qt::SplitVCursor] = mir_vsplit_resize_cursor_name;
|
||||
mShapeToCursorName[Qt::SplitHCursor] = mir_hsplit_resize_cursor_name;
|
||||
mShapeToCursorName[Qt::PointingHandCursor] = mir_pointing_hand_cursor_name;
|
||||
mShapeToCursorName[Qt::ForbiddenCursor] = "forbidden";
|
||||
mShapeToCursorName[Qt::WhatsThisCursor] = "whats_this";
|
||||
mShapeToCursorName[Qt::BusyCursor] = "left_ptr_watch";
|
||||
mShapeToCursorName[Qt::OpenHandCursor] = "openhand";
|
||||
mShapeToCursorName[Qt::ClosedHandCursor] = "closedhand";
|
||||
mShapeToCursorName[Qt::OpenHandCursor] = mir_open_hand_cursor_name;
|
||||
mShapeToCursorName[Qt::ClosedHandCursor] = mir_closed_hand_cursor_name;
|
||||
mShapeToCursorName[Qt::DragCopyCursor] = "dnd-copy";
|
||||
mShapeToCursorName[Qt::DragMoveCursor] = "dnd-move";
|
||||
mShapeToCursorName[Qt::DragLinkCursor] = "dnd-link";
|
||||
}
|
||||
|
||||
namespace {
|
||||
#if !defined(QT_NO_DEBUG)
|
||||
const char *qtCursorShapeToStr(Qt::CursorShape shape)
|
||||
{
|
||||
switch (shape) {
|
||||
@ -127,7 +133,6 @@ const char *qtCursorShapeToStr(Qt::CursorShape shape)
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
#endif // !defined(QT_NO_DEBUG)
|
||||
} // anonymous namespace
|
||||
|
||||
void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)
|
||||
@ -144,7 +149,7 @@ void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)
|
||||
|
||||
|
||||
if (windowCursor) {
|
||||
DLOG("[ubuntumirclient QPA] changeCursor shape=%s, window=%p\n", qtCursorShapeToStr(windowCursor->shape()), window);
|
||||
qCDebug(mirclientCursor, "changeCursor shape=%s, window=%p", qtCursorShapeToStr(windowCursor->shape()), window);
|
||||
if (!windowCursor->pixmap().isNull()) {
|
||||
configureMirCursorWithPixmapQCursor(surface, *windowCursor);
|
||||
} else if (windowCursor->shape() == Qt::BitmapCursor) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Canonical, Ltd.
|
||||
** Copyright (C) 2015-2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
|
79
src/plugins/platforms/mirclient/qmirclientdebugextension.cpp
Normal file
79
src/plugins/platforms/mirclient/qmirclientdebugextension.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "qmirclientdebugextension.h"
|
||||
|
||||
#include "qmirclientlogging.h"
|
||||
|
||||
// mir client debug
|
||||
#include <mir_toolkit/debug/surface.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(mirclientDebug, "qt.qpa.mirclient.debug")
|
||||
|
||||
QMirClientDebugExtension::QMirClientDebugExtension()
|
||||
: m_mirclientDebug(QStringLiteral("mirclient-debug-extension"), 1)
|
||||
, m_mapper(nullptr)
|
||||
{
|
||||
qCDebug(mirclientDebug) << "NOTICE: Loading mirclient-debug-extension";
|
||||
m_mapper = (MapperPrototype) m_mirclientDebug.resolve("mir_debug_surface_coords_to_screen");
|
||||
|
||||
if (!m_mirclientDebug.isLoaded()) {
|
||||
qCWarning(mirclientDebug) << "ERROR: mirclient-debug-extension failed to load:"
|
||||
<< m_mirclientDebug.errorString();
|
||||
} else if (!m_mapper) {
|
||||
qCWarning(mirclientDebug) << "ERROR: unable to find required symbols in mirclient-debug-extension:"
|
||||
<< m_mirclientDebug.errorString();
|
||||
}
|
||||
}
|
||||
|
||||
QPoint QMirClientDebugExtension::mapSurfacePointToScreen(MirSurface *surface, const QPoint &point)
|
||||
{
|
||||
if (!m_mapper) {
|
||||
return point;
|
||||
}
|
||||
|
||||
QPoint mappedPoint;
|
||||
bool status = m_mapper(surface, point.x(), point.y(), &mappedPoint.rx(), &mappedPoint.ry());
|
||||
if (status) {
|
||||
return mappedPoint;
|
||||
} else {
|
||||
return point;
|
||||
}
|
||||
}
|
63
src/plugins/platforms/mirclient/qmirclientdebugextension.h
Normal file
63
src/plugins/platforms/mirclient/qmirclientdebugextension.h
Normal file
@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef QMIRCLIENTDEBUGEXTENSION_H
|
||||
#define QMIRCLIENTDEBUGEXTENSION_H
|
||||
|
||||
#include <QPoint>
|
||||
#include <QLibrary>
|
||||
struct MirSurface;
|
||||
|
||||
typedef bool (*MapperPrototype)(MirSurface* surface, int x, int y, int* screenX, int* screenY);
|
||||
|
||||
|
||||
class QMirClientDebugExtension
|
||||
{
|
||||
public:
|
||||
QMirClientDebugExtension();
|
||||
|
||||
QPoint mapSurfacePointToScreen(MirSurface *, const QPoint &point);
|
||||
|
||||
private:
|
||||
QLibrary m_mirclientDebug;
|
||||
MapperPrototype m_mapper;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTDEBUGEXTENSION_H
|
50
src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp
Normal file
50
src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "qmirclientdesktopwindow.h"
|
||||
|
||||
// local
|
||||
#include "qmirclientlogging.h"
|
||||
|
||||
QMirClientDesktopWindow::QMirClientDesktopWindow(QWindow *window)
|
||||
: QPlatformWindow(window)
|
||||
{
|
||||
qCDebug(mirclient, "QMirClientDesktopWindow(window=%p)", window);
|
||||
}
|
53
src/plugins/platforms/mirclient/qmirclientdesktopwindow.h
Normal file
53
src/plugins/platforms/mirclient/qmirclientdesktopwindow.h
Normal file
@ -0,0 +1,53 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef QMIRCLIENTDESKTOPWINDOW_H
|
||||
#define QMIRCLIENTDESKTOPWINDOW_H
|
||||
|
||||
#include <qpa/qplatformwindow.h>
|
||||
|
||||
// TODO Implement it. For now it's just an empty, dummy class.
|
||||
class QMirClientDesktopWindow : public QPlatformWindow
|
||||
{
|
||||
public:
|
||||
QMirClientDesktopWindow(QWindow*);
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTDESKTOPWINDOW_H
|
@ -39,123 +39,94 @@
|
||||
|
||||
|
||||
#include "qmirclientglcontext.h"
|
||||
#include "qmirclientwindow.h"
|
||||
#include "qmirclientlogging.h"
|
||||
#include "qmirclientwindow.h"
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QtEglSupport/private/qeglconvenience_p.h>
|
||||
#include <QtEglSupport/private/qeglpbuffer_p.h>
|
||||
#include <QtGui/private/qopenglcontext_p.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#if !defined(QT_NO_DEBUG)
|
||||
static void printOpenGLESConfig() {
|
||||
static bool once = true;
|
||||
if (once) {
|
||||
const char* string = (const char*) glGetString(GL_VENDOR);
|
||||
LOG("OpenGL ES vendor: %s", string);
|
||||
string = (const char*) glGetString(GL_RENDERER);
|
||||
LOG("OpenGL ES renderer: %s", string);
|
||||
string = (const char*) glGetString(GL_VERSION);
|
||||
LOG("OpenGL ES version: %s", string);
|
||||
string = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||
LOG("OpenGL ES Shading Language version: %s", string);
|
||||
string = (const char*) glGetString(GL_EXTENSIONS);
|
||||
LOG("OpenGL ES extensions: %s", string);
|
||||
once = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Q_LOGGING_CATEGORY(mirclientGraphics, "qt.qpa.mirclient.graphics", QtWarningMsg)
|
||||
|
||||
static EGLenum api_in_use()
|
||||
namespace {
|
||||
|
||||
void printEglConfig(EGLDisplay display, EGLConfig config)
|
||||
{
|
||||
#ifdef QTUBUNTU_USE_OPENGL
|
||||
return EGL_OPENGL_API;
|
||||
#else
|
||||
return EGL_OPENGL_ES_API;
|
||||
#endif
|
||||
Q_ASSERT(display != EGL_NO_DISPLAY);
|
||||
Q_ASSERT(config != nullptr);
|
||||
|
||||
const char *string = eglQueryString(display, EGL_VENDOR);
|
||||
qCDebug(mirclientGraphics, "EGL vendor: %s", string);
|
||||
|
||||
string = eglQueryString(display, EGL_VERSION);
|
||||
qCDebug(mirclientGraphics, "EGL version: %s", string);
|
||||
|
||||
string = eglQueryString(display, EGL_EXTENSIONS);
|
||||
qCDebug(mirclientGraphics, "EGL extensions: %s", string);
|
||||
|
||||
qCDebug(mirclientGraphics, "EGL configuration attributes:");
|
||||
q_printEglConfig(display, config);
|
||||
}
|
||||
|
||||
QMirClientOpenGLContext::QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share)
|
||||
} // anonymous namespace
|
||||
|
||||
QMirClientOpenGLContext::QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
|
||||
EGLDisplay display)
|
||||
: QEGLPlatformContext(format, share, display, 0)
|
||||
{
|
||||
ASSERT(screen != NULL);
|
||||
mEglDisplay = screen->eglDisplay();
|
||||
mScreen = screen;
|
||||
|
||||
// Create an OpenGL ES 2 context.
|
||||
QVector<EGLint> attribs;
|
||||
attribs.append(EGL_CONTEXT_CLIENT_VERSION);
|
||||
attribs.append(2);
|
||||
attribs.append(EGL_NONE);
|
||||
ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
|
||||
|
||||
mEglContext = eglCreateContext(mEglDisplay, screen->eglConfig(), share ? share->eglContext() : EGL_NO_CONTEXT,
|
||||
attribs.constData());
|
||||
DASSERT(mEglContext != EGL_NO_CONTEXT);
|
||||
if (mirclientGraphics().isDebugEnabled()) {
|
||||
printEglConfig(display, eglConfig());
|
||||
}
|
||||
}
|
||||
|
||||
QMirClientOpenGLContext::~QMirClientOpenGLContext()
|
||||
static bool needsFBOReadBackWorkaround()
|
||||
{
|
||||
ASSERT(eglDestroyContext(mEglDisplay, mEglContext) == EGL_TRUE);
|
||||
static bool set = false;
|
||||
static bool needsWorkaround = false;
|
||||
|
||||
if (Q_UNLIKELY(!set)) {
|
||||
const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
|
||||
needsWorkaround = qstrncmp(rendererString, "Mali-400", 8) == 0
|
||||
|| qstrncmp(rendererString, "Mali-T7", 7) == 0
|
||||
|| qstrncmp(rendererString, "PowerVR Rogue G6200", 19) == 0;
|
||||
set = true;
|
||||
}
|
||||
|
||||
return needsWorkaround;
|
||||
}
|
||||
|
||||
bool QMirClientOpenGLContext::makeCurrent(QPlatformSurface* surface)
|
||||
{
|
||||
DASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
|
||||
EGLSurface eglSurface = static_cast<QMirClientWindow*>(surface)->eglSurface();
|
||||
#if defined(QT_NO_DEBUG)
|
||||
eglBindAPI(api_in_use());
|
||||
eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext);
|
||||
#else
|
||||
ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
|
||||
ASSERT(eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext) == EGL_TRUE);
|
||||
printOpenGLESConfig();
|
||||
#endif
|
||||
const bool ret = QEGLPlatformContext::makeCurrent(surface);
|
||||
|
||||
// When running on the emulator, shaders will be compiled using a thin wrapper around the desktop drivers.
|
||||
// These wrappers might not support the precision qualifiers, so set the workaround flag to true.
|
||||
const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
|
||||
if (rendererString != 0 && qstrncmp(rendererString, "Android Emulator", 16) == 0) {
|
||||
if (Q_LIKELY(ret)) {
|
||||
QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(context());
|
||||
ctx_d->workaround_missingPrecisionQualifiers = true;
|
||||
if (!ctx_d->workaround_brokenFBOReadBack && needsFBOReadBackWorkaround()) {
|
||||
ctx_d->workaround_brokenFBOReadBack = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QMirClientOpenGLContext::doneCurrent()
|
||||
// Following method used internally in the base class QEGLPlatformContext to access
|
||||
// the egl surface of a QPlatformSurface/QMirClientWindow
|
||||
EGLSurface QMirClientOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
|
||||
{
|
||||
#if defined(QT_NO_DEBUG)
|
||||
eglBindAPI(api_in_use());
|
||||
eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
#else
|
||||
ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
|
||||
ASSERT(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_TRUE);
|
||||
#endif
|
||||
if (surface->surface()->surfaceClass() == QSurface::Window) {
|
||||
return static_cast<QMirClientWindow *>(surface)->eglSurface();
|
||||
} else {
|
||||
return static_cast<QEGLPbuffer *>(surface)->pbuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface)
|
||||
{
|
||||
QMirClientWindow *ubuntuWindow = static_cast<QMirClientWindow*>(surface);
|
||||
QEGLPlatformContext::swapBuffers(surface);
|
||||
|
||||
EGLSurface eglSurface = ubuntuWindow->eglSurface();
|
||||
#if defined(QT_NO_DEBUG)
|
||||
eglBindAPI(api_in_use());
|
||||
eglSwapBuffers(mEglDisplay, eglSurface);
|
||||
#else
|
||||
ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
|
||||
ASSERT(eglSwapBuffers(mEglDisplay, eglSurface) == EGL_TRUE);
|
||||
#endif
|
||||
|
||||
ubuntuWindow->onSwapBuffersDone();
|
||||
if (surface->surface()->surfaceClass() == QSurface::Window) {
|
||||
// notify window on swap completion
|
||||
auto platformWindow = static_cast<QMirClientWindow *>(surface);
|
||||
platformWindow->onSwapBuffersDone();
|
||||
}
|
||||
|
||||
QFunctionPointer QMirClientOpenGLContext::getProcAddress(const char *procName)
|
||||
{
|
||||
#if defined(QT_NO_DEBUG)
|
||||
eglBindAPI(api_in_use());
|
||||
#else
|
||||
ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
|
||||
#endif
|
||||
QFunctionPointer proc = (QFunctionPointer) eglGetProcAddress(procName);
|
||||
if (!proc)
|
||||
proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, procName);
|
||||
return proc;
|
||||
}
|
||||
|
@ -42,28 +42,22 @@
|
||||
#define QMIRCLIENTGLCONTEXT_H
|
||||
|
||||
#include <qpa/qplatformopenglcontext.h>
|
||||
#include "qmirclientscreen.h"
|
||||
#include <QtEglSupport/private/qeglplatformcontext_p.h>
|
||||
|
||||
class QMirClientOpenGLContext : public QPlatformOpenGLContext
|
||||
#include <EGL/egl.h>
|
||||
|
||||
class QMirClientOpenGLContext : public QEGLPlatformContext
|
||||
{
|
||||
public:
|
||||
QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share);
|
||||
virtual ~QMirClientOpenGLContext();
|
||||
QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
|
||||
EGLDisplay display);
|
||||
|
||||
// QPlatformOpenGLContext methods.
|
||||
QSurfaceFormat format() const override { return mScreen->surfaceFormat(); }
|
||||
void swapBuffers(QPlatformSurface* surface) override;
|
||||
bool makeCurrent(QPlatformSurface* surface) override;
|
||||
void doneCurrent() override;
|
||||
bool isValid() const override { return mEglContext != EGL_NO_CONTEXT; }
|
||||
QFunctionPointer getProcAddress(const char *procName) override;
|
||||
// QEGLPlatformContext methods.
|
||||
void swapBuffers(QPlatformSurface *surface) final;
|
||||
bool makeCurrent(QPlatformSurface *surface) final;
|
||||
|
||||
EGLContext eglContext() const { return mEglContext; }
|
||||
|
||||
private:
|
||||
QMirClientScreen* mScreen;
|
||||
EGLContext mEglContext;
|
||||
EGLDisplay mEglDisplay;
|
||||
protected:
|
||||
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) final;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTGLCONTEXT_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014-2015 Canonical, Ltd.
|
||||
** Copyright (C) 2014-2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -48,21 +48,23 @@
|
||||
#include "qmirclientorientationchangeevent_p.h"
|
||||
|
||||
// Qt
|
||||
#if !defined(QT_NO_DEBUG)
|
||||
#include <QtCore/QThread>
|
||||
#endif
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <qpa/qplatforminputcontext.h>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QTextCodec>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
#define LOG_EVENTS 0
|
||||
Q_LOGGING_CATEGORY(mirclientInput, "qt.qpa.mirclient.input", QtWarningMsg)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points)
|
||||
static const uint32_t KeyTable[] = {
|
||||
@ -134,6 +136,27 @@ static const uint32_t KeyTable[] = {
|
||||
XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate,
|
||||
XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate,
|
||||
|
||||
// dead keys
|
||||
XKB_KEY_dead_grave, Qt::Key_Dead_Grave,
|
||||
XKB_KEY_dead_acute, Qt::Key_Dead_Acute,
|
||||
XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex,
|
||||
XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde,
|
||||
XKB_KEY_dead_macron, Qt::Key_Dead_Macron,
|
||||
XKB_KEY_dead_breve, Qt::Key_Dead_Breve,
|
||||
XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot,
|
||||
XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis,
|
||||
XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering,
|
||||
XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute,
|
||||
XKB_KEY_dead_caron, Qt::Key_Dead_Caron,
|
||||
XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla,
|
||||
XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek,
|
||||
XKB_KEY_dead_iota, Qt::Key_Dead_Iota,
|
||||
XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
|
||||
XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
|
||||
XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot,
|
||||
XKB_KEY_dead_hook, Qt::Key_Dead_Hook,
|
||||
XKB_KEY_dead_horn, Qt::Key_Dead_Horn,
|
||||
|
||||
XKB_KEY_Mode_switch, Qt::Key_Mode_switch,
|
||||
XKB_KEY_script_switch, Qt::Key_Mode_switch,
|
||||
XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp,
|
||||
@ -144,14 +167,37 @@ static const uint32_t KeyTable[] = {
|
||||
0, 0
|
||||
};
|
||||
|
||||
class QMirClientEvent : public QEvent
|
||||
Qt::WindowState mirSurfaceStateToWindowState(MirSurfaceState state)
|
||||
{
|
||||
switch (state) {
|
||||
case mir_surface_state_fullscreen:
|
||||
return Qt::WindowFullScreen;
|
||||
case mir_surface_state_maximized:
|
||||
case mir_surface_state_vertmaximized:
|
||||
case mir_surface_state_horizmaximized:
|
||||
return Qt::WindowMaximized;
|
||||
case mir_surface_state_minimized:
|
||||
return Qt::WindowMinimized;
|
||||
case mir_surface_state_hidden:
|
||||
// We should be handling this state separately.
|
||||
Q_ASSERT(false);
|
||||
case mir_surface_state_restored:
|
||||
case mir_surface_state_unknown:
|
||||
default:
|
||||
return Qt::WindowNoState;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class UbuntuEvent : public QEvent
|
||||
{
|
||||
public:
|
||||
QMirClientEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type)
|
||||
UbuntuEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type)
|
||||
: QEvent(type), window(window) {
|
||||
nativeEvent = mir_event_ref(event);
|
||||
}
|
||||
~QMirClientEvent()
|
||||
~UbuntuEvent()
|
||||
{
|
||||
mir_event_unref(nativeEvent);
|
||||
}
|
||||
@ -166,7 +212,7 @@ QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration)
|
||||
, mEventFilterType(static_cast<QMirClientNativeInterface*>(
|
||||
integration->nativeInterface())->genericEventFilterType())
|
||||
, mEventType(static_cast<QEvent::Type>(QEvent::registerEventType()))
|
||||
, mLastFocusedWindow(nullptr)
|
||||
, mLastInputWindow(nullptr)
|
||||
{
|
||||
// Initialize touch device.
|
||||
mTouchDevice = new QTouchDevice;
|
||||
@ -182,42 +228,47 @@ QMirClientInput::~QMirClientInput()
|
||||
// Qt will take care of deleting mTouchDevice.
|
||||
}
|
||||
|
||||
#if (LOG_EVENTS != 0)
|
||||
static const char* nativeEventTypeToStr(MirEventType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case mir_event_type_key:
|
||||
return "mir_event_type_key";
|
||||
return "key";
|
||||
case mir_event_type_motion:
|
||||
return "mir_event_type_motion";
|
||||
return "motion";
|
||||
case mir_event_type_surface:
|
||||
return "mir_event_type_surface";
|
||||
return "surface";
|
||||
case mir_event_type_resize:
|
||||
return "mir_event_type_resize";
|
||||
return "resize";
|
||||
case mir_event_type_prompt_session_state_change:
|
||||
return "mir_event_type_prompt_session_state_change";
|
||||
return "prompt_session_state_change";
|
||||
case mir_event_type_orientation:
|
||||
return "mir_event_type_orientation";
|
||||
return "orientation";
|
||||
case mir_event_type_close_surface:
|
||||
return "mir_event_type_close_surface";
|
||||
return "close_surface";
|
||||
case mir_event_type_input:
|
||||
return "mir_event_type_input";
|
||||
return "input";
|
||||
case mir_event_type_keymap:
|
||||
return "keymap";
|
||||
case mir_event_type_input_configuration:
|
||||
return "input_configuration";
|
||||
case mir_event_type_surface_output:
|
||||
return "surface_output";
|
||||
case mir_event_type_input_device_state:
|
||||
return "input_device_state";
|
||||
default:
|
||||
DLOG("Invalid event type %d", t);
|
||||
return "invalid";
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
#endif // LOG_EVENTS != 0
|
||||
|
||||
void QMirClientInput::customEvent(QEvent* event)
|
||||
{
|
||||
DASSERT(QThread::currentThread() == thread());
|
||||
QMirClientEvent* ubuntuEvent = static_cast<QMirClientEvent*>(event);
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
UbuntuEvent* ubuntuEvent = static_cast<UbuntuEvent*>(event);
|
||||
const MirEvent *nativeEvent = ubuntuEvent->nativeEvent;
|
||||
|
||||
if ((ubuntuEvent->window == nullptr) || (ubuntuEvent->window->window() == nullptr)) {
|
||||
qWarning("Attempted to deliver an event to a non-existent window, ignoring.");
|
||||
qCWarning(mirclient) << "Attempted to deliver an event to a non-existent window, ignoring.";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -226,13 +277,11 @@ void QMirClientInput::customEvent(QEvent* event)
|
||||
if (QWindowSystemInterface::handleNativeEvent(
|
||||
ubuntuEvent->window->window(), mEventFilterType,
|
||||
const_cast<void *>(static_cast<const void *>(nativeEvent)), &result) == true) {
|
||||
DLOG("event filtered out by native interface");
|
||||
qCDebug(mirclient, "event filtered out by native interface");
|
||||
return;
|
||||
}
|
||||
|
||||
#if (LOG_EVENTS != 0)
|
||||
LOG("QMirClientInput::customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent)));
|
||||
#endif
|
||||
qCDebug(mirclientInput, "customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent)));
|
||||
|
||||
// Event dispatching.
|
||||
switch (mir_event_get_type(nativeEvent))
|
||||
@ -242,43 +291,30 @@ void QMirClientInput::customEvent(QEvent* event)
|
||||
break;
|
||||
case mir_event_type_resize:
|
||||
{
|
||||
Q_ASSERT(ubuntuEvent->window->screen() == mIntegration->screen());
|
||||
|
||||
auto resizeEvent = mir_event_get_resize_event(nativeEvent);
|
||||
|
||||
mIntegration->screen()->handleWindowSurfaceResize(
|
||||
// Enable workaround for Screen rotation
|
||||
auto const targetWindow = ubuntuEvent->window;
|
||||
if (targetWindow) {
|
||||
auto const screen = static_cast<QMirClientScreen*>(targetWindow->screen());
|
||||
if (screen) {
|
||||
screen->handleWindowSurfaceResize(
|
||||
mir_resize_event_get_width(resizeEvent),
|
||||
mir_resize_event_get_height(resizeEvent));
|
||||
}
|
||||
|
||||
ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent),
|
||||
targetWindow->handleSurfaceResized(
|
||||
mir_resize_event_get_width(resizeEvent),
|
||||
mir_resize_event_get_height(resizeEvent));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case mir_event_type_surface:
|
||||
{
|
||||
auto surfaceEvent = mir_event_get_surface_event(nativeEvent);
|
||||
if (mir_surface_event_get_attribute(surfaceEvent) == mir_surface_attrib_focus) {
|
||||
const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
|
||||
// Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
|
||||
// so that we don't deactivate windows prematurely.
|
||||
if (focused) {
|
||||
mPendingFocusGainedEvents--;
|
||||
ubuntuEvent->window->handleSurfaceFocused();
|
||||
QWindowSystemInterface::handleWindowActivated(ubuntuEvent->window->window(), Qt::ActiveWindowFocusReason);
|
||||
|
||||
// NB: Since processing of system events is queued, never check qGuiApp->applicationState()
|
||||
// as it might be outdated. Always call handleApplicationStateChanged() with the latest
|
||||
// state regardless.
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
|
||||
|
||||
} else if (!mPendingFocusGainedEvents) {
|
||||
DLOG("[ubuntumirclient QPA] No windows have focus");
|
||||
QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
|
||||
}
|
||||
}
|
||||
handleSurfaceEvent(ubuntuEvent->window, mir_event_get_surface_event(nativeEvent));
|
||||
break;
|
||||
case mir_event_type_surface_output:
|
||||
handleSurfaceOutputEvent(ubuntuEvent->window, mir_event_get_surface_output_event(nativeEvent));
|
||||
break;
|
||||
}
|
||||
case mir_event_type_orientation:
|
||||
dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent));
|
||||
break;
|
||||
@ -286,7 +322,7 @@ void QMirClientInput::customEvent(QEvent* event)
|
||||
QWindowSystemInterface::handleCloseEvent(ubuntuEvent->window->window());
|
||||
break;
|
||||
default:
|
||||
DLOG("unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent)));
|
||||
qCDebug(mirclient, "unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,22 +330,11 @@ void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent
|
||||
{
|
||||
QWindow *window = platformWindow->window();
|
||||
|
||||
const auto eventType = mir_event_get_type(event);
|
||||
if (mir_event_type_surface == eventType) {
|
||||
auto surfaceEvent = mir_event_get_surface_event(event);
|
||||
if (mir_surface_attrib_focus == mir_surface_event_get_attribute(surfaceEvent)) {
|
||||
const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
|
||||
if (focused) {
|
||||
mPendingFocusGainedEvents++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QCoreApplication::postEvent(this, new QMirClientEvent(
|
||||
QCoreApplication::postEvent(this, new UbuntuEvent(
|
||||
platformWindow, event, mEventType));
|
||||
|
||||
if ((window->flags().testFlag(Qt::WindowTransparentForInput)) && window->parent()) {
|
||||
QCoreApplication::postEvent(this, new QMirClientEvent(
|
||||
QCoreApplication::postEvent(this, new UbuntuEvent(
|
||||
static_cast<QMirClientWindow*>(platformWindow->QPlatformWindow::parent()),
|
||||
event, mEventType));
|
||||
}
|
||||
@ -365,15 +390,17 @@ void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInpu
|
||||
switch (touch_action)
|
||||
{
|
||||
case mir_touch_action_down:
|
||||
mLastFocusedWindow = window;
|
||||
mLastInputWindow = window;
|
||||
touchPoint.state = Qt::TouchPointPressed;
|
||||
break;
|
||||
case mir_touch_action_up:
|
||||
touchPoint.state = Qt::TouchPointReleased;
|
||||
break;
|
||||
case mir_touch_action_change:
|
||||
default:
|
||||
touchPoint.state = Qt::TouchPointMoved;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
touchPoints.append(touchPoint);
|
||||
@ -384,22 +411,26 @@ void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInpu
|
||||
mTouchDevice, touchPoints);
|
||||
}
|
||||
|
||||
static uint32_t translateKeysym(uint32_t sym, char *string, size_t size)
|
||||
{
|
||||
Q_UNUSED(size);
|
||||
string[0] = '\0';
|
||||
static uint32_t translateKeysym(uint32_t sym, const QString &text) {
|
||||
int code = 0;
|
||||
|
||||
if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35)
|
||||
QTextCodec *systemCodec = QTextCodec::codecForLocale();
|
||||
if (sym < 128 || (sym < 256 && systemCodec->mibEnum() == 4)) {
|
||||
// upper-case key, if known
|
||||
code = isprint((int)sym) ? toupper((int)sym) : 0;
|
||||
} else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) {
|
||||
return Qt::Key_F1 + (int(sym) - XKB_KEY_F1);
|
||||
|
||||
for (int i = 0; KeyTable[i]; i += 2) {
|
||||
} else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
|
||||
&& text.unicode()->unicode() != 0x7f
|
||||
&& !(sym >= XKB_KEY_dead_grave && sym <= XKB_KEY_dead_currency)) {
|
||||
code = text.unicode()->toUpper().unicode();
|
||||
} else {
|
||||
for (int i = 0; KeyTable[i]; i += 2)
|
||||
if (sym == KeyTable[i])
|
||||
return KeyTable[i + 1];
|
||||
code = KeyTable[i + 1];
|
||||
}
|
||||
|
||||
string[0] = sym;
|
||||
string[1] = '\0';
|
||||
return toupper(sym);
|
||||
return code;
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -413,12 +444,15 @@ Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers)
|
||||
if (modifiers & mir_input_event_modifier_ctrl) {
|
||||
q_modifiers |= Qt::ControlModifier;
|
||||
}
|
||||
if (modifiers & mir_input_event_modifier_alt) {
|
||||
if (modifiers & mir_input_event_modifier_alt_left) {
|
||||
q_modifiers |= Qt::AltModifier;
|
||||
}
|
||||
if (modifiers & mir_input_event_modifier_meta) {
|
||||
q_modifiers |= Qt::MetaModifier;
|
||||
}
|
||||
if (modifiers & mir_input_event_modifier_alt_right) {
|
||||
q_modifiers |= Qt::GroupSwitchModifier;
|
||||
}
|
||||
return q_modifiers;
|
||||
}
|
||||
}
|
||||
@ -429,34 +463,43 @@ void QMirClientInput::dispatchKeyEvent(QMirClientWindow *window, const MirInputE
|
||||
|
||||
ulong timestamp = mir_input_event_get_event_time(event) / 1000000;
|
||||
xkb_keysym_t xk_sym = mir_keyboard_event_key_code(key_event);
|
||||
quint32 scan_code = mir_keyboard_event_scan_code(key_event);
|
||||
quint32 native_modifiers = mir_keyboard_event_modifiers(key_event);
|
||||
|
||||
// Key modifier and unicode index mapping.
|
||||
auto modifiers = qt_modifiers_from_mir(mir_keyboard_event_modifiers(key_event));
|
||||
auto modifiers = qt_modifiers_from_mir(native_modifiers);
|
||||
|
||||
MirKeyboardAction action = mir_keyboard_event_action(key_event);
|
||||
QEvent::Type keyType = action == mir_keyboard_action_up
|
||||
? QEvent::KeyRelease : QEvent::KeyPress;
|
||||
|
||||
if (action == mir_keyboard_action_down)
|
||||
mLastFocusedWindow = window;
|
||||
mLastInputWindow = window;
|
||||
|
||||
char s[2];
|
||||
int sym = translateKeysym(xk_sym, s, sizeof(s));
|
||||
QString text = QString::fromLatin1(s);
|
||||
QString text;
|
||||
QVarLengthArray<char, 32> chars(32);
|
||||
{
|
||||
int result = xkb_keysym_to_utf8(xk_sym, chars.data(), chars.size());
|
||||
|
||||
if (result > 0) {
|
||||
text = QString::fromUtf8(chars.constData());
|
||||
}
|
||||
}
|
||||
int sym = translateKeysym(xk_sym, text);
|
||||
|
||||
bool is_auto_rep = action == mir_keyboard_action_repeat;
|
||||
|
||||
QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
|
||||
if (context) {
|
||||
QKeyEvent qKeyEvent(keyType, sym, modifiers, text, is_auto_rep);
|
||||
QKeyEvent qKeyEvent(keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep);
|
||||
qKeyEvent.setTimestamp(timestamp);
|
||||
if (context->filterEvent(&qKeyEvent)) {
|
||||
DLOG("key event filtered out by input context");
|
||||
qCDebug(mirclient, "key event filtered out by input context");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleKeyEvent(window->window(), timestamp, keyType, sym, modifiers, text, is_auto_rep);
|
||||
QWindowSystemInterface::handleExtendedKeyEvent(window->window(), timestamp, keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep);
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -481,14 +524,17 @@ Qt::MouseButtons extract_buttons(const MirPointerEvent *pev)
|
||||
|
||||
void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, const MirInputEvent *ev)
|
||||
{
|
||||
auto window = platformWindow->window();
|
||||
auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
|
||||
const auto window = platformWindow->window();
|
||||
const auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
|
||||
|
||||
auto pev = mir_input_event_get_pointer_event(ev);
|
||||
auto action = mir_pointer_event_action(pev);
|
||||
auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
|
||||
const auto pev = mir_input_event_get_pointer_event(ev);
|
||||
const auto action = mir_pointer_event_action(pev);
|
||||
|
||||
const auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
|
||||
const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
|
||||
mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
|
||||
auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
|
||||
|
||||
mLastInputWindow = platformWindow;
|
||||
|
||||
switch (action) {
|
||||
case mir_pointer_action_button_up:
|
||||
@ -499,7 +545,8 @@ void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, con
|
||||
const float vDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_vscroll);
|
||||
|
||||
if (hDelta != 0 || vDelta != 0) {
|
||||
const QPoint angleDelta = QPoint(hDelta * 15, vDelta * 15);
|
||||
// QWheelEvent::DefaultDeltasPerStep = 120 but doesn't exist on vivid
|
||||
const QPoint angleDelta(120 * hDelta, 120 * vDelta);
|
||||
QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, window->position() + localPoint,
|
||||
QPoint(), angleDelta, modifiers, Qt::ScrollUpdate);
|
||||
}
|
||||
@ -515,42 +562,32 @@ void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, con
|
||||
QWindowSystemInterface::handleLeaveEvent(window);
|
||||
break;
|
||||
default:
|
||||
DLOG("Unrecognized pointer event");
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if (LOG_EVENTS != 0)
|
||||
static const char* nativeOrientationDirectionToStr(MirOrientation orientation)
|
||||
{
|
||||
switch (orientation) {
|
||||
case mir_orientation_normal:
|
||||
return "Normal";
|
||||
break;
|
||||
case mir_orientation_left:
|
||||
return "Left";
|
||||
break;
|
||||
case mir_orientation_inverted:
|
||||
return "Inverted";
|
||||
break;
|
||||
case mir_orientation_right:
|
||||
return "Right";
|
||||
break;
|
||||
default:
|
||||
return "INVALID!";
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
#endif
|
||||
|
||||
void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrientationEvent *event)
|
||||
{
|
||||
MirOrientation mir_orientation = mir_orientation_event_get_direction(event);
|
||||
#if (LOG_EVENTS != 0)
|
||||
// Orientation event logging.
|
||||
LOG("ORIENTATION direction: %s", nativeOrientationDirectionToStr(mir_orientation));
|
||||
#endif
|
||||
qCDebug(mirclientInput, "orientation direction: %s", nativeOrientationDirectionToStr(mir_orientation));
|
||||
|
||||
if (!window->screen()) {
|
||||
DLOG("Window has no associated screen, dropping orientation event");
|
||||
qCDebug(mirclient, "Window has no associated screen, dropping orientation event");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -569,7 +606,7 @@ void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrienta
|
||||
orientation = OrientationChangeEvent::RightUp;
|
||||
break;
|
||||
default:
|
||||
DLOG("No such orientation %d", mir_orientation);
|
||||
qCDebug(mirclient, "No such orientation %d", mir_orientation);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -581,3 +618,61 @@ void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrienta
|
||||
new OrientationChangeEvent(OrientationChangeEvent::mType, orientation));
|
||||
}
|
||||
|
||||
void QMirClientInput::handleSurfaceEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceEvent *event)
|
||||
{
|
||||
auto surfaceEventAttribute = mir_surface_event_get_attribute(event);
|
||||
|
||||
switch (surfaceEventAttribute) {
|
||||
case mir_surface_attrib_focus: {
|
||||
window->handleSurfaceFocusChanged(
|
||||
mir_surface_event_get_attribute_value(event) == mir_surface_focused);
|
||||
break;
|
||||
}
|
||||
case mir_surface_attrib_visibility: {
|
||||
window->handleSurfaceExposeChange(
|
||||
mir_surface_event_get_attribute_value(event) == mir_surface_visibility_exposed);
|
||||
break;
|
||||
}
|
||||
// Remaining attributes are ones client sets for server, and server should not override them
|
||||
case mir_surface_attrib_state: {
|
||||
MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(event));
|
||||
|
||||
if (state == mir_surface_state_hidden) {
|
||||
window->handleSurfaceVisibilityChanged(false);
|
||||
} else {
|
||||
// it's visible!
|
||||
window->handleSurfaceVisibilityChanged(true);
|
||||
window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case mir_surface_attrib_type:
|
||||
case mir_surface_attrib_swapinterval:
|
||||
case mir_surface_attrib_dpi:
|
||||
case mir_surface_attrib_preferred_orientation:
|
||||
case mir_surface_attribs:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientInput::handleSurfaceOutputEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceOutputEvent *event)
|
||||
{
|
||||
const uint32_t outputId = mir_surface_output_event_get_output_id(event);
|
||||
const int dpi = mir_surface_output_event_get_dpi(event);
|
||||
const MirFormFactor formFactor = mir_surface_output_event_get_form_factor(event);
|
||||
const float scale = mir_surface_output_event_get_scale(event);
|
||||
|
||||
const auto screenObserver = mIntegration->screenObserver();
|
||||
QMirClientScreen *screen = screenObserver->findScreenWithId(outputId);
|
||||
if (!screen) {
|
||||
qCWarning(mirclient) << "Mir notified window" << window->window() << "on an unknown screen with id" << outputId;
|
||||
return;
|
||||
}
|
||||
|
||||
screenObserver->handleScreenPropertiesChange(screen, dpi, formFactor, scale);
|
||||
window->handleScreenPropertiesChange(formFactor, scale);
|
||||
|
||||
if (window->screen() != screen) {
|
||||
QWindowSystemInterface::handleWindowScreenChanged(window->window(), screen->screen());
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014-2015 Canonical, Ltd.
|
||||
** Copyright (C) 2014-2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -43,7 +43,6 @@
|
||||
|
||||
// Qt
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QAtomicInt>
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
@ -63,7 +62,7 @@ public:
|
||||
|
||||
void postEvent(QMirClientWindow* window, const MirEvent *event);
|
||||
QMirClientClientIntegration* integration() const { return mIntegration; }
|
||||
QMirClientWindow *lastFocusedWindow() const {return mLastFocusedWindow; }
|
||||
QMirClientWindow *lastInputWindow() const {return mLastInputWindow; }
|
||||
|
||||
protected:
|
||||
void dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event);
|
||||
@ -72,6 +71,8 @@ protected:
|
||||
void dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *event);
|
||||
|
||||
void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event);
|
||||
void handleSurfaceEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceEvent *event);
|
||||
void handleSurfaceOutputEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceOutputEvent *event);
|
||||
|
||||
private:
|
||||
QMirClientClientIntegration* mIntegration;
|
||||
@ -79,8 +80,7 @@ private:
|
||||
const QByteArray mEventFilterType;
|
||||
const QEvent::Type mEventType;
|
||||
|
||||
QMirClientWindow *mLastFocusedWindow;
|
||||
QAtomicInt mPendingFocusGainedEvents;
|
||||
QMirClientWindow *mLastInputWindow;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTINPUT_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014-2015 Canonical, Ltd.
|
||||
** Copyright (C) 2014-2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -42,6 +42,8 @@
|
||||
#include "qmirclientintegration.h"
|
||||
#include "qmirclientbackingstore.h"
|
||||
#include "qmirclientclipboard.h"
|
||||
#include "qmirclientdebugextension.h"
|
||||
#include "qmirclientdesktopwindow.h"
|
||||
#include "qmirclientglcontext.h"
|
||||
#include "qmirclientinput.h"
|
||||
#include "qmirclientlogging.h"
|
||||
@ -51,56 +53,62 @@
|
||||
#include "qmirclientwindow.h"
|
||||
|
||||
// Qt
|
||||
#include <QFileInfo>
|
||||
#include <QGuiApplication>
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <qpa/qplatforminputcontextfactory_p.h>
|
||||
#include <qpa/qplatforminputcontext.h>
|
||||
#include <QtEglSupport/private/qeglconvenience_p.h>
|
||||
#include <QtEglSupport/private/qeglpbuffer_p.h>
|
||||
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
|
||||
#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
|
||||
#ifndef QT_NO_ACCESSIBILITY
|
||||
#include <qpa/qplatformaccessibility.h>
|
||||
#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
|
||||
#include <QtLinuxAccessibilitySupport/private/bridge_p.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOffscreenSurface>
|
||||
|
||||
// platform-api
|
||||
#include <ubuntu/application/lifecycle_delegate.h>
|
||||
#include <ubuntu/application/id.h>
|
||||
#include <ubuntu/application/options.h>
|
||||
|
||||
static void resumedCallback(const UApplicationOptions *options, void* context)
|
||||
static void resumedCallback(const UApplicationOptions */*options*/, void* context)
|
||||
{
|
||||
Q_UNUSED(options)
|
||||
Q_UNUSED(context)
|
||||
DASSERT(context != NULL);
|
||||
if (qGuiApp->focusWindow()) {
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
|
||||
} else {
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
|
||||
}
|
||||
auto integration = static_cast<QMirClientClientIntegration*>(context);
|
||||
integration->appStateController()->setResumed();
|
||||
}
|
||||
|
||||
static void aboutToStopCallback(UApplicationArchive *archive, void* context)
|
||||
static void aboutToStopCallback(UApplicationArchive */*archive*/, void* context)
|
||||
{
|
||||
Q_UNUSED(archive)
|
||||
DASSERT(context != NULL);
|
||||
QMirClientClientIntegration* integration = static_cast<QMirClientClientIntegration*>(context);
|
||||
QPlatformInputContext *inputContext = integration->inputContext();
|
||||
auto integration = static_cast<QMirClientClientIntegration*>(context);
|
||||
auto inputContext = integration->inputContext();
|
||||
if (inputContext) {
|
||||
inputContext->hideInputPanel();
|
||||
} else {
|
||||
qWarning("QMirClientClientIntegration aboutToStopCallback(): no input context");
|
||||
qCWarning(mirclient) << "aboutToStopCallback(): no input context";
|
||||
}
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
|
||||
integration->appStateController()->setSuspended();
|
||||
}
|
||||
|
||||
QMirClientClientIntegration::QMirClientClientIntegration()
|
||||
QMirClientClientIntegration::QMirClientClientIntegration(int argc, char **argv)
|
||||
: QPlatformIntegration()
|
||||
, mNativeInterface(new QMirClientNativeInterface)
|
||||
, mNativeInterface(new QMirClientNativeInterface(this))
|
||||
, mFontDb(new QGenericUnixFontDatabase)
|
||||
, mServices(new QMirClientPlatformServices)
|
||||
, mClipboard(new QMirClientClipboard)
|
||||
, mAppStateController(new QMirClientAppStateController)
|
||||
, mScaleFactor(1.0)
|
||||
{
|
||||
setupOptions();
|
||||
setupDescription();
|
||||
{
|
||||
QStringList args = QCoreApplication::arguments();
|
||||
setupOptions(args);
|
||||
QByteArray sessionName = generateSessionName(args);
|
||||
setupDescription(sessionName);
|
||||
}
|
||||
|
||||
// Create new application instance
|
||||
mInstance = u_application_instance_new_from_description_with_options(mDesc, mOptions);
|
||||
@ -110,19 +118,48 @@ QMirClientClientIntegration::QMirClientClientIntegration()
|
||||
"running, and the correct socket is being used and is accessible. The shell may have\n"
|
||||
"rejected the incoming connection, so check its log file");
|
||||
|
||||
mNativeInterface->setMirConnection(u_application_instance_get_mir_connection(mInstance));
|
||||
mMirConnection = u_application_instance_get_mir_connection(mInstance);
|
||||
|
||||
// Create default screen.
|
||||
screenAdded(new QMirClientScreen(u_application_instance_get_mir_connection(mInstance)));
|
||||
// Choose the default surface format suited to the Mir platform
|
||||
QSurfaceFormat defaultFormat;
|
||||
defaultFormat.setRedBufferSize(8);
|
||||
defaultFormat.setGreenBufferSize(8);
|
||||
defaultFormat.setBlueBufferSize(8);
|
||||
QSurfaceFormat::setDefaultFormat(defaultFormat);
|
||||
|
||||
// Initialize EGL.
|
||||
mEglNativeDisplay = mir_connection_get_egl_native_display(mMirConnection);
|
||||
ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY);
|
||||
ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);
|
||||
|
||||
// Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var
|
||||
bool testability = qEnvironmentVariableIsSet("QT_LOAD_TESTABILITY");
|
||||
for (int i=1; !testability && i<argc; i++) {
|
||||
if (strcmp(argv[i], "-testability") == 0) {
|
||||
testability = true;
|
||||
}
|
||||
}
|
||||
if (testability) {
|
||||
mDebugExtension.reset(new QMirClientDebugExtension);
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientClientIntegration::initialize()
|
||||
{
|
||||
// Init the ScreenObserver
|
||||
mScreenObserver.reset(new QMirClientScreenObserver(mMirConnection));
|
||||
connect(mScreenObserver.data(), &QMirClientScreenObserver::screenAdded,
|
||||
[this](QMirClientScreen *screen) { this->screenAdded(screen); });
|
||||
connect(mScreenObserver.data(), &QMirClientScreenObserver::screenRemoved,
|
||||
this, &QMirClientClientIntegration::destroyScreen);
|
||||
|
||||
Q_FOREACH (auto screen, mScreenObserver->screens()) {
|
||||
screenAdded(screen);
|
||||
}
|
||||
|
||||
// Initialize input.
|
||||
if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_INPUT")) {
|
||||
mInput = new QMirClientInput(this);
|
||||
mInputContext = QPlatformInputContextFactory::create();
|
||||
} else {
|
||||
mInput = nullptr;
|
||||
mInputContext = nullptr;
|
||||
}
|
||||
|
||||
// compute the scale factor
|
||||
const int defaultGridUnit = 8;
|
||||
@ -140,10 +177,9 @@ QMirClientClientIntegration::QMirClientClientIntegration()
|
||||
|
||||
QMirClientClientIntegration::~QMirClientClientIntegration()
|
||||
{
|
||||
eglTerminate(mEglDisplay);
|
||||
delete mInput;
|
||||
delete mInputContext;
|
||||
for (QScreen *screen : QGuiApplication::screens())
|
||||
QPlatformIntegration::destroyScreen(screen->handle());
|
||||
delete mServices;
|
||||
}
|
||||
|
||||
@ -152,9 +188,8 @@ QPlatformServices *QMirClientClientIntegration::services() const
|
||||
return mServices;
|
||||
}
|
||||
|
||||
void QMirClientClientIntegration::setupOptions()
|
||||
void QMirClientClientIntegration::setupOptions(QStringList &args)
|
||||
{
|
||||
QStringList args = QCoreApplication::arguments();
|
||||
int argc = args.size() + 1;
|
||||
char **argv = new char*[argc];
|
||||
for (int i = 0; i < argc - 1; i++)
|
||||
@ -168,10 +203,11 @@ void QMirClientClientIntegration::setupOptions()
|
||||
delete [] argv;
|
||||
}
|
||||
|
||||
void QMirClientClientIntegration::setupDescription()
|
||||
void QMirClientClientIntegration::setupDescription(QByteArray &sessionName)
|
||||
{
|
||||
mDesc = u_application_description_new();
|
||||
UApplicationId* id = u_application_id_new_from_stringn("QtUbuntu", 8);
|
||||
|
||||
UApplicationId* id = u_application_id_new_from_stringn(sessionName.data(), sessionName.count());
|
||||
u_application_description_set_application_id(mDesc, id);
|
||||
|
||||
UApplicationLifecycleDelegate* delegate = u_application_lifecycle_delegate_new();
|
||||
@ -181,43 +217,66 @@ void QMirClientClientIntegration::setupDescription()
|
||||
u_application_description_set_application_lifecycle_delegate(mDesc, delegate);
|
||||
}
|
||||
|
||||
QByteArray QMirClientClientIntegration::generateSessionName(QStringList &args)
|
||||
{
|
||||
// Try to come up with some meaningful session name to uniquely identify this session,
|
||||
// helping with shell debugging
|
||||
|
||||
if (args.count() == 0) {
|
||||
return QByteArray("QtUbuntu");
|
||||
} if (args[0].contains("qmlscene")) {
|
||||
return generateSessionNameFromQmlFile(args);
|
||||
} else {
|
||||
// use the executable name
|
||||
QFileInfo fileInfo(args[0]);
|
||||
return fileInfo.fileName().toLocal8Bit();
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray QMirClientClientIntegration::generateSessionNameFromQmlFile(QStringList &args)
|
||||
{
|
||||
Q_FOREACH (QString arg, args) {
|
||||
if (arg.endsWith(".qml")) {
|
||||
QFileInfo fileInfo(arg);
|
||||
return fileInfo.fileName().toLocal8Bit();
|
||||
}
|
||||
}
|
||||
|
||||
// give up
|
||||
return "qmlscene";
|
||||
}
|
||||
|
||||
QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const
|
||||
{
|
||||
return const_cast<QMirClientClientIntegration*>(this)->createPlatformWindow(window);
|
||||
if (window->type() == Qt::Desktop) {
|
||||
// Desktop windows should not be backed up by a mir surface as they don't draw anything (nor should).
|
||||
return new QMirClientDesktopWindow(window);
|
||||
} else {
|
||||
return new QMirClientWindow(window, mInput, mNativeInterface, mAppStateController.data(),
|
||||
mEglDisplay, mMirConnection, mDebugExtension.data());
|
||||
}
|
||||
|
||||
QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window)
|
||||
{
|
||||
return new QMirClientWindow(window, mClipboard, screen(),
|
||||
mInput, u_application_instance_get_mir_connection(mInstance));
|
||||
}
|
||||
|
||||
QMirClientScreen *QMirClientClientIntegration::screen() const
|
||||
{
|
||||
return static_cast<QMirClientScreen *>(QGuiApplication::primaryScreen()->handle());
|
||||
}
|
||||
|
||||
bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const
|
||||
{
|
||||
switch (cap) {
|
||||
case ThreadedPixmaps:
|
||||
return true;
|
||||
|
||||
case OpenGL:
|
||||
return true;
|
||||
|
||||
case ApplicationState:
|
||||
return true;
|
||||
|
||||
case ThreadedOpenGL:
|
||||
if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) {
|
||||
return true;
|
||||
} else {
|
||||
DLOG("ubuntumirclient: disabled threaded OpenGL");
|
||||
qCDebug(mirclient, "disabled threaded OpenGL");
|
||||
return false;
|
||||
}
|
||||
|
||||
case ThreadedPixmaps:
|
||||
case OpenGL:
|
||||
case ApplicationState:
|
||||
case MultipleWindows:
|
||||
case NonFullScreenWindows:
|
||||
#if QT_VERSION > QT_VERSION_CHECK(5, 5, 0)
|
||||
case SwitchableWidgetComposition:
|
||||
#endif
|
||||
case RasterGLSurface: // needed for QQuickWidget
|
||||
return true;
|
||||
default:
|
||||
return QPlatformIntegration::hasCapability(cap);
|
||||
@ -237,14 +296,25 @@ QPlatformBackingStore* QMirClientClientIntegration::createPlatformBackingStore(Q
|
||||
QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext(
|
||||
QOpenGLContext* context) const
|
||||
{
|
||||
return const_cast<QMirClientClientIntegration*>(this)->createPlatformOpenGLContext(context);
|
||||
}
|
||||
QSurfaceFormat format(context->format());
|
||||
|
||||
QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext(
|
||||
QOpenGLContext* context)
|
||||
{
|
||||
return new QMirClientOpenGLContext(static_cast<QMirClientScreen*>(context->screen()->handle()),
|
||||
static_cast<QMirClientOpenGLContext*>(context->shareHandle()));
|
||||
auto platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay);
|
||||
if (!platformContext->isValid()) {
|
||||
// Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default
|
||||
// QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a
|
||||
// 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to
|
||||
// have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default
|
||||
// requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455).
|
||||
static const bool isMesa = QString(eglQueryString(mEglDisplay, EGL_VENDOR)).contains(QStringLiteral("Mesa"));
|
||||
if (isMesa) {
|
||||
qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa");
|
||||
format.setMajorVersion(1);
|
||||
format.setMinorVersion(4);
|
||||
delete platformContext;
|
||||
platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay);
|
||||
}
|
||||
}
|
||||
return platformContext;
|
||||
}
|
||||
|
||||
QStringList QMirClientClientIntegration::themeNames() const
|
||||
@ -277,10 +347,65 @@ QVariant QMirClientClientIntegration::styleHint(StyleHint hint) const
|
||||
|
||||
QPlatformClipboard* QMirClientClientIntegration::clipboard() const
|
||||
{
|
||||
return mClipboard.data();
|
||||
static QPlatformClipboard *clipboard = nullptr;
|
||||
if (!clipboard) {
|
||||
clipboard = new QMirClientClipboard;
|
||||
}
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const
|
||||
{
|
||||
return mNativeInterface;
|
||||
}
|
||||
|
||||
QPlatformOffscreenSurface *QMirClientClientIntegration::createPlatformOffscreenSurface(
|
||||
QOffscreenSurface *surface) const
|
||||
{
|
||||
return new QEGLPbuffer(mEglDisplay, surface->requestedFormat(), surface);
|
||||
}
|
||||
|
||||
void QMirClientClientIntegration::destroyScreen(QMirClientScreen *screen)
|
||||
{
|
||||
// FIXME: on deleting a screen while a Window is on it, Qt will automatically
|
||||
// move the window to the primaryScreen(). This will trigger a screenChanged
|
||||
// signal, causing things like QQuickScreenAttached to re-fetch screen properties
|
||||
// like DPI and physical size. However this is crashing, as Qt is calling virtual
|
||||
// functions on QPlatformScreen, for reasons unclear. As workaround, move window
|
||||
// to primaryScreen() before deleting the screen. Might be QTBUG-38650
|
||||
|
||||
QScreen *primaryScreen = QGuiApplication::primaryScreen();
|
||||
if (screen != primaryScreen->handle()) {
|
||||
uint32_t movedWindowCount = 0;
|
||||
Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) {
|
||||
if (w->screen()->handle() == screen) {
|
||||
QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen);
|
||||
++movedWindowCount;
|
||||
}
|
||||
}
|
||||
if (movedWindowCount > 0) {
|
||||
QWindowSystemInterface::flushWindowSystemEvents();
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(mirclient) << "Removing Screen with id" << screen->mirOutputId() << "and geometry" << screen->geometry();
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
|
||||
delete screen;
|
||||
#else
|
||||
QPlatformIntegration::destroyScreen(screen);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef QT_NO_ACCESSIBILITY
|
||||
QPlatformAccessibility *QMirClientClientIntegration::accessibility() const
|
||||
{
|
||||
#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE)
|
||||
if (!mAccessibility) {
|
||||
Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QMirClientIntegration",
|
||||
"Initializing accessibility without event-dispatcher!");
|
||||
mAccessibility.reset(new QSpiAccessibleBridge());
|
||||
}
|
||||
#endif
|
||||
return mAccessibility.data();
|
||||
}
|
||||
#endif
|
||||
|
@ -44,20 +44,28 @@
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "qmirclientappstatecontroller.h"
|
||||
#include "qmirclientplatformservices.h"
|
||||
#include "qmirclientscreenobserver.h"
|
||||
|
||||
// platform-api
|
||||
#include <ubuntu/application/description.h>
|
||||
#include <ubuntu/application/instance.h>
|
||||
|
||||
class QMirClientClipboard;
|
||||
#include <EGL/egl.h>
|
||||
|
||||
class QMirClientDebugExtension;
|
||||
class QMirClientInput;
|
||||
class QMirClientNativeInterface;
|
||||
class QMirClientScreen;
|
||||
class MirConnection;
|
||||
|
||||
class QMirClientClientIntegration : public QObject, public QPlatformIntegration
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
class QMirClientClientIntegration : public QPlatformIntegration {
|
||||
public:
|
||||
QMirClientClientIntegration();
|
||||
QMirClientClientIntegration(int argc, char **argv);
|
||||
virtual ~QMirClientClientIntegration();
|
||||
|
||||
// QPlatformIntegration methods.
|
||||
@ -74,14 +82,26 @@ public:
|
||||
QPlatformWindow* createPlatformWindow(QWindow* window) const override;
|
||||
QPlatformInputContext* inputContext() const override { return mInputContext; }
|
||||
QPlatformClipboard* clipboard() const override;
|
||||
void initialize() override;
|
||||
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
|
||||
QPlatformAccessibility *accessibility() const override;
|
||||
|
||||
QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context);
|
||||
QPlatformWindow* createPlatformWindow(QWindow* window);
|
||||
QMirClientScreen* screen() const;
|
||||
// New methods.
|
||||
MirConnection *mirConnection() const { return mMirConnection; }
|
||||
EGLDisplay eglDisplay() const { return mEglDisplay; }
|
||||
EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
|
||||
QMirClientAppStateController *appStateController() const { return mAppStateController.data(); }
|
||||
QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); }
|
||||
QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); }
|
||||
|
||||
private Q_SLOTS:
|
||||
void destroyScreen(QMirClientScreen *screen);
|
||||
|
||||
private:
|
||||
void setupOptions();
|
||||
void setupDescription();
|
||||
void setupOptions(QStringList &args);
|
||||
void setupDescription(QByteArray &sessionName);
|
||||
static QByteArray generateSessionName(QStringList &args);
|
||||
static QByteArray generateSessionNameFromQmlFile(QStringList &args);
|
||||
|
||||
QMirClientNativeInterface* mNativeInterface;
|
||||
QPlatformFontDatabase* mFontDb;
|
||||
@ -90,13 +110,22 @@ private:
|
||||
|
||||
QMirClientInput* mInput;
|
||||
QPlatformInputContext* mInputContext;
|
||||
QSharedPointer<QMirClientClipboard> mClipboard;
|
||||
mutable QScopedPointer<QPlatformAccessibility> mAccessibility;
|
||||
QScopedPointer<QMirClientDebugExtension> mDebugExtension;
|
||||
QScopedPointer<QMirClientScreenObserver> mScreenObserver;
|
||||
QScopedPointer<QMirClientAppStateController> mAppStateController;
|
||||
qreal mScaleFactor;
|
||||
|
||||
MirConnection *mMirConnection;
|
||||
|
||||
// Platform API stuff
|
||||
UApplicationOptions* mOptions;
|
||||
UApplicationDescription* mDesc;
|
||||
UApplicationInstance* mInstance;
|
||||
|
||||
// EGL related
|
||||
EGLDisplay mEglDisplay{EGL_NO_DISPLAY};
|
||||
EGLNativeDisplayType mEglNativeDisplay;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTINTEGRATION_H
|
||||
|
@ -41,23 +41,15 @@
|
||||
#ifndef QMIRCLIENTLOGGING_H
|
||||
#define QMIRCLIENTLOGGING_H
|
||||
|
||||
// Logging and assertion macros.
|
||||
#define LOG(...) qDebug(__VA_ARGS__)
|
||||
#define LOG_IF(cond,...) do { if (cond) qDebug(__VA_ARGS__); } while (0)
|
||||
#define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
|
||||
#define NOT_REACHED() qt_assert("Not reached!",__FILE__,__LINE__)
|
||||
#include <QLoggingCategory>
|
||||
|
||||
// Logging and assertion macros are compiled out for release builds.
|
||||
#if !defined(QT_NO_DEBUG)
|
||||
#define DLOG(...) LOG(__VA_ARGS__)
|
||||
#define DLOG_IF(cond,...) LOG_IF((cond), __VA_ARGS__)
|
||||
#define DASSERT(cond) ASSERT((cond))
|
||||
#define DNOT_REACHED() NOT_REACHED()
|
||||
#else
|
||||
#define DLOG(...) qt_noop()
|
||||
#define DLOG_IF(cond,...) qt_noop()
|
||||
#define DASSERT(cond) qt_noop()
|
||||
#define DNOT_REACHED() qt_noop()
|
||||
#endif
|
||||
#define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(mirclient)
|
||||
Q_DECLARE_LOGGING_CATEGORY(mirclientBufferSwap)
|
||||
Q_DECLARE_LOGGING_CATEGORY(mirclientInput)
|
||||
Q_DECLARE_LOGGING_CATEGORY(mirclientGraphics)
|
||||
Q_DECLARE_LOGGING_CATEGORY(mirclientCursor)
|
||||
Q_DECLARE_LOGGING_CATEGORY(mirclientDebug)
|
||||
|
||||
#endif // QMIRCLIENTLOGGING_H
|
||||
|
@ -42,32 +42,36 @@
|
||||
#include "qmirclientnativeinterface.h"
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclientglcontext.h"
|
||||
#include "qmirclientwindow.h"
|
||||
|
||||
// Qt
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
class QMirClientResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType>
|
||||
class UbuntuResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType>
|
||||
{
|
||||
public:
|
||||
QMirClientResourceMap()
|
||||
UbuntuResourceMap()
|
||||
: QMap<QByteArray, QMirClientNativeInterface::ResourceType>() {
|
||||
insert("egldisplay", QMirClientNativeInterface::EglDisplay);
|
||||
insert("eglcontext", QMirClientNativeInterface::EglContext);
|
||||
insert("nativeorientation", QMirClientNativeInterface::NativeOrientation);
|
||||
insert("display", QMirClientNativeInterface::Display);
|
||||
insert("mirconnection", QMirClientNativeInterface::MirConnection);
|
||||
insert("mirsurface", QMirClientNativeInterface::MirSurface);
|
||||
insert("scale", QMirClientNativeInterface::Scale);
|
||||
insert("formfactor", QMirClientNativeInterface::FormFactor);
|
||||
}
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(QMirClientResourceMap, ubuntuResourceMap)
|
||||
Q_GLOBAL_STATIC(UbuntuResourceMap, ubuntuResourceMap)
|
||||
|
||||
QMirClientNativeInterface::QMirClientNativeInterface()
|
||||
: mGenericEventFilterType(QByteArrayLiteral("Event"))
|
||||
QMirClientNativeInterface::QMirClientNativeInterface(const QMirClientClientIntegration *integration)
|
||||
: mIntegration(integration)
|
||||
, mGenericEventFilterType(QByteArrayLiteral("Event"))
|
||||
, mNativeOrientation(nullptr)
|
||||
, mMirConnection(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -88,7 +92,7 @@ void* QMirClientNativeInterface::nativeResourceForIntegration(const QByteArray &
|
||||
const ResourceType resourceType = ubuntuResourceMap()->value(lowerCaseResource);
|
||||
|
||||
if (resourceType == QMirClientNativeInterface::MirConnection) {
|
||||
return mMirConnection;
|
||||
return mIntegration->mirConnection();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
@ -119,14 +123,11 @@ void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resou
|
||||
if (!ubuntuResourceMap()->contains(kLowerCaseResource))
|
||||
return NULL;
|
||||
const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
|
||||
if (kResourceType == QMirClientNativeInterface::EglDisplay) {
|
||||
if (window) {
|
||||
return static_cast<QMirClientScreen*>(window->screen()->handle())->eglDisplay();
|
||||
} else {
|
||||
return static_cast<QMirClientScreen*>(
|
||||
QGuiApplication::primaryScreen()->handle())->eglDisplay();
|
||||
}
|
||||
} else if (kResourceType == QMirClientNativeInterface::NativeOrientation) {
|
||||
|
||||
switch (kResourceType) {
|
||||
case EglDisplay:
|
||||
return mIntegration->eglDisplay();
|
||||
case NativeOrientation:
|
||||
// Return the device's native screen orientation.
|
||||
if (window) {
|
||||
QMirClientScreen *ubuntuScreen = static_cast<QMirClientScreen*>(window->screen()->handle());
|
||||
@ -136,8 +137,19 @@ void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resou
|
||||
mNativeOrientation = new Qt::ScreenOrientation(platformScreen->nativeOrientation());
|
||||
}
|
||||
return mNativeOrientation;
|
||||
case MirSurface:
|
||||
if (window) {
|
||||
auto ubuntuWindow = static_cast<QMirClientWindow*>(window->handle());
|
||||
if (ubuntuWindow) {
|
||||
return ubuntuWindow->mirSurface();
|
||||
} else {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,10 +159,59 @@ void* QMirClientNativeInterface::nativeResourceForScreen(const QByteArray& resou
|
||||
if (!ubuntuResourceMap()->contains(kLowerCaseResource))
|
||||
return NULL;
|
||||
const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
|
||||
if (kResourceType == QMirClientNativeInterface::Display) {
|
||||
if (!screen)
|
||||
screen = QGuiApplication::primaryScreen();
|
||||
return static_cast<QMirClientScreen*>(screen->handle())->eglNativeDisplay();
|
||||
auto ubuntuScreen = static_cast<QMirClientScreen*>(screen->handle());
|
||||
if (kResourceType == QMirClientNativeInterface::Display) {
|
||||
return mIntegration->eglNativeDisplay();
|
||||
// Changes to the following properties are emitted via the QMirClientNativeInterface::screenPropertyChanged
|
||||
// signal fired by QMirClientScreen. Connect to this signal for these properties updates.
|
||||
// WARNING: code highly thread unsafe!
|
||||
} else if (kResourceType == QMirClientNativeInterface::Scale) {
|
||||
// In application code, read with:
|
||||
// float scale = *reinterpret_cast<float*>(nativeResourceForScreen("scale", screen()));
|
||||
return &ubuntuScreen->mScale;
|
||||
} else if (kResourceType == QMirClientNativeInterface::FormFactor) {
|
||||
return &ubuntuScreen->mFormFactor;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Changes to these properties are emitted via the QMirClientNativeInterface::windowPropertyChanged
|
||||
// signal fired by QMirClientWindow. Connect to this signal for these properties updates.
|
||||
QVariantMap QMirClientNativeInterface::windowProperties(QPlatformWindow *window) const
|
||||
{
|
||||
QVariantMap propertyMap;
|
||||
auto w = static_cast<QMirClientWindow*>(window);
|
||||
if (w) {
|
||||
propertyMap.insert("scale", w->scale());
|
||||
propertyMap.insert("formFactor", w->formFactor());
|
||||
}
|
||||
return propertyMap;
|
||||
}
|
||||
|
||||
QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const
|
||||
{
|
||||
auto w = static_cast<QMirClientWindow*>(window);
|
||||
if (!w) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (name == QStringLiteral("scale")) {
|
||||
return w->scale();
|
||||
} else if (name == QStringLiteral("formFactor")) {
|
||||
return w->formFactor();
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const
|
||||
{
|
||||
QVariant returnVal = windowProperty(window, name);
|
||||
if (!returnVal.isValid()) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return returnVal;
|
||||
}
|
||||
}
|
||||
|
@ -43,11 +43,16 @@
|
||||
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
class QMirClientNativeInterface : public QPlatformNativeInterface {
|
||||
public:
|
||||
enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection };
|
||||
#include "qmirclientintegration.h"
|
||||
|
||||
QMirClientNativeInterface();
|
||||
class QPlatformScreen;
|
||||
|
||||
class QMirClientNativeInterface : public QPlatformNativeInterface {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection, MirSurface, Scale, FormFactor };
|
||||
|
||||
QMirClientNativeInterface(const QMirClientClientIntegration *integration);
|
||||
~QMirClientNativeInterface();
|
||||
|
||||
// QPlatformNativeInterface methods.
|
||||
@ -59,14 +64,20 @@ public:
|
||||
void* nativeResourceForScreen(const QByteArray& resourceString,
|
||||
QScreen* screen) override;
|
||||
|
||||
QVariantMap windowProperties(QPlatformWindow *window) const override;
|
||||
QVariant windowProperty(QPlatformWindow *window, const QString &name) const override;
|
||||
QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override;
|
||||
|
||||
// New methods.
|
||||
const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; }
|
||||
void setMirConnection(void *mirConnection) { mMirConnection = mirConnection; }
|
||||
|
||||
Q_SIGNALS: // New signals
|
||||
void screenPropertyChanged(QPlatformScreen *screen, const QString &propertyName);
|
||||
|
||||
private:
|
||||
const QMirClientClientIntegration *mIntegration;
|
||||
const QByteArray mGenericEventFilterType;
|
||||
Qt::ScreenOrientation* mNativeOrientation;
|
||||
void *mMirConnection;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTNATIVEINTERFACE_H
|
||||
|
@ -40,19 +40,16 @@
|
||||
|
||||
#include "qmirclientplugin.h"
|
||||
#include "qmirclientintegration.h"
|
||||
#include "qmirclientlogging.h"
|
||||
|
||||
QStringList QMirClientIntegrationPlugin::keys() const
|
||||
{
|
||||
QStringList list;
|
||||
list << QStringLiteral("mirclient");
|
||||
return list;
|
||||
}
|
||||
Q_LOGGING_CATEGORY(mirclient, "qt.qpa.mirclient", QtWarningMsg)
|
||||
|
||||
QPlatformIntegration *QMirClientIntegrationPlugin::create(const QString &system,
|
||||
const QStringList &)
|
||||
const QStringList &/*paramList*/,
|
||||
int &argc, char **argv)
|
||||
{
|
||||
if (system.toLower() == QLatin1String("mirclient")) {
|
||||
return new QMirClientClientIntegration;
|
||||
return new QMirClientClientIntegration(argc, argv);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ class QMirClientIntegrationPlugin : public QPlatformIntegrationPlugin
|
||||
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "mirclient.json")
|
||||
|
||||
public:
|
||||
QStringList keys() const;
|
||||
QPlatformIntegration* create(const QString&, const QStringList&);
|
||||
QPlatformIntegration *create(const QString &system, const QStringList ¶mList,
|
||||
int &argc, char **argv) override;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTPLUGIN_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014-2015 Canonical, Ltd.
|
||||
** Copyright (C) 2014-2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -42,11 +42,12 @@
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclientlogging.h"
|
||||
#include "qmirclientorientationchangeevent_p.h"
|
||||
#include "qmirclientnativeinterface.h"
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
// Qt
|
||||
#include <QCoreApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QScreen>
|
||||
#include <QThread>
|
||||
@ -55,9 +56,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
static const int kSwapInterval = 1;
|
||||
|
||||
#if !defined(QT_NO_DEBUG)
|
||||
static const int overrideDevicePixelRatio = qgetenv("QT_DEVICE_PIXEL_RATIO").toInt();
|
||||
|
||||
static const char *orientationToStr(Qt::ScreenOrientation orientation) {
|
||||
switch (orientation) {
|
||||
@ -71,173 +70,33 @@ static const char *orientationToStr(Qt::ScreenOrientation orientation) {
|
||||
return "inverted portrait";
|
||||
case Qt::InvertedLandscapeOrientation:
|
||||
return "inverted landscape";
|
||||
default:
|
||||
return "INVALID!";
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
static void printEglConfig(EGLDisplay display, EGLConfig config) {
|
||||
DASSERT(display != EGL_NO_DISPLAY);
|
||||
DASSERT(config != nullptr);
|
||||
static const struct { const EGLint attrib; const char* name; } kAttribs[] = {
|
||||
{ EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE" },
|
||||
{ EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE" },
|
||||
{ EGL_BLUE_SIZE, "EGL_BLUE_SIZE" },
|
||||
{ EGL_GREEN_SIZE, "EGL_GREEN_SIZE" },
|
||||
{ EGL_RED_SIZE, "EGL_RED_SIZE" },
|
||||
{ EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE" },
|
||||
{ EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE" },
|
||||
{ EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT" },
|
||||
{ EGL_CONFIG_ID, "EGL_CONFIG_ID" },
|
||||
{ EGL_LEVEL, "EGL_LEVEL" },
|
||||
{ EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT" },
|
||||
{ EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS" },
|
||||
{ EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH" },
|
||||
{ EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE" },
|
||||
{ EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID" },
|
||||
{ EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE" },
|
||||
{ EGL_SAMPLES, "EGL_SAMPLES" },
|
||||
{ EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS" },
|
||||
{ EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE" },
|
||||
{ EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE" },
|
||||
{ EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE" },
|
||||
{ EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE" },
|
||||
{ EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE" },
|
||||
{ EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB" },
|
||||
{ EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA" },
|
||||
{ EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" },
|
||||
{ EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
const char* string = eglQueryString(display, EGL_VENDOR);
|
||||
LOG("EGL vendor: %s", string);
|
||||
string = eglQueryString(display, EGL_VERSION);
|
||||
LOG("EGL version: %s", string);
|
||||
string = eglQueryString(display, EGL_EXTENSIONS);
|
||||
LOG("EGL extensions: %s", string);
|
||||
LOG("EGL configuration attibutes:");
|
||||
for (int index = 0; kAttribs[index].attrib != -1; index++) {
|
||||
EGLint value;
|
||||
if (eglGetConfigAttrib(display, config, kAttribs[index].attrib, &value))
|
||||
LOG(" %s: %d", kAttribs[index].name, static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
const QEvent::Type OrientationChangeEvent::mType =
|
||||
static_cast<QEvent::Type>(QEvent::registerEventType());
|
||||
|
||||
static const MirDisplayOutput *find_active_output(
|
||||
const MirDisplayConfiguration *conf)
|
||||
{
|
||||
const MirDisplayOutput *output = NULL;
|
||||
for (uint32_t d = 0; d < conf->num_outputs; d++)
|
||||
{
|
||||
const MirDisplayOutput *out = conf->outputs + d;
|
||||
|
||||
if (out->used &&
|
||||
out->connected &&
|
||||
out->num_modes &&
|
||||
out->current_mode < out->num_modes)
|
||||
{
|
||||
output = out;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
QMirClientScreen::QMirClientScreen(MirConnection *connection)
|
||||
: mFormat(QImage::Format_RGB32)
|
||||
QMirClientScreen::QMirClientScreen(const MirOutput *output, MirConnection *connection)
|
||||
: mDevicePixelRatio(1.0)
|
||||
, mFormat(QImage::Format_RGB32)
|
||||
, mDepth(32)
|
||||
, mDpi{0}
|
||||
, mFormFactor{mir_form_factor_unknown}
|
||||
, mScale{1.0}
|
||||
, mOutputId(0)
|
||||
, mSurfaceFormat()
|
||||
, mEglDisplay(EGL_NO_DISPLAY)
|
||||
, mEglConfig(nullptr)
|
||||
, mCursor(connection)
|
||||
{
|
||||
// Initialize EGL.
|
||||
ASSERT(eglBindAPI(EGL_OPENGL_ES_API) == EGL_TRUE);
|
||||
|
||||
mEglNativeDisplay = mir_connection_get_egl_native_display(connection);
|
||||
ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY);
|
||||
ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);
|
||||
|
||||
// Configure EGL buffers format.
|
||||
mSurfaceFormat.setRedBufferSize(8);
|
||||
mSurfaceFormat.setGreenBufferSize(8);
|
||||
mSurfaceFormat.setBlueBufferSize(8);
|
||||
mSurfaceFormat.setAlphaBufferSize(8);
|
||||
mSurfaceFormat.setDepthBufferSize(24);
|
||||
mSurfaceFormat.setStencilBufferSize(8);
|
||||
if (!qEnvironmentVariableIsEmpty("QTUBUNTU_MULTISAMPLE")) {
|
||||
mSurfaceFormat.setSamples(4);
|
||||
DLOG("ubuntumirclient: setting MSAA to 4 samples");
|
||||
}
|
||||
#ifdef QTUBUNTU_USE_OPENGL
|
||||
mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
#else
|
||||
mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
|
||||
#endif
|
||||
mEglConfig = q_configFromGLFormat(mEglDisplay, mSurfaceFormat, true);
|
||||
|
||||
#if !defined(QT_NO_DEBUG)
|
||||
printEglConfig(mEglDisplay, mEglConfig);
|
||||
#endif
|
||||
|
||||
// Set vblank swap interval.
|
||||
int swapInterval = kSwapInterval;
|
||||
QByteArray swapIntervalString = qgetenv("QTUBUNTU_SWAPINTERVAL");
|
||||
if (!swapIntervalString.isEmpty()) {
|
||||
bool ok;
|
||||
swapInterval = swapIntervalString.toInt(&ok);
|
||||
if (!ok)
|
||||
swapInterval = kSwapInterval;
|
||||
}
|
||||
DLOG("ubuntumirclient: setting swap interval to %d", swapInterval);
|
||||
eglSwapInterval(mEglDisplay, swapInterval);
|
||||
|
||||
// Get screen resolution.
|
||||
auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); };
|
||||
using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>;
|
||||
configUp displayConfig(mir_connection_create_display_config(connection), configDeleter);
|
||||
ASSERT(displayConfig != nullptr);
|
||||
|
||||
auto const displayOutput = find_active_output(displayConfig.get());
|
||||
ASSERT(displayOutput != nullptr);
|
||||
|
||||
mOutputId = displayOutput->output_id;
|
||||
|
||||
mPhysicalSize = QSizeF(displayOutput->physical_width_mm, displayOutput->physical_height_mm);
|
||||
DLOG("ubuntumirclient: screen physical size: %.2fx%.2f", mPhysicalSize.width(), mPhysicalSize.height());
|
||||
|
||||
const MirDisplayMode *mode = &displayOutput->modes[displayOutput->current_mode];
|
||||
const int kScreenWidth = mode->horizontal_resolution;
|
||||
const int kScreenHeight = mode->vertical_resolution;
|
||||
DASSERT(kScreenWidth > 0 && kScreenHeight > 0);
|
||||
|
||||
DLOG("ubuntumirclient: screen resolution: %dx%d", kScreenWidth, kScreenHeight);
|
||||
|
||||
mGeometry = QRect(0, 0, kScreenWidth, kScreenHeight);
|
||||
|
||||
DLOG("QQMirClientScreen::QQMirClientScreen (this=%p)", this);
|
||||
|
||||
// Set the default orientation based on the initial screen dimmensions.
|
||||
mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
|
||||
|
||||
// If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
|
||||
mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
|
||||
setMirOutput(output);
|
||||
}
|
||||
|
||||
QMirClientScreen::~QMirClientScreen()
|
||||
{
|
||||
eglTerminate(mEglDisplay);
|
||||
}
|
||||
|
||||
void QMirClientScreen::customEvent(QEvent* event) {
|
||||
DASSERT(QThread::currentThread() == thread());
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
OrientationChangeEvent* oReadingEvent = static_cast<OrientationChangeEvent*>(event);
|
||||
switch (oReadingEvent->mOrientation) {
|
||||
@ -261,14 +120,10 @@ void QMirClientScreen::customEvent(QEvent* event) {
|
||||
Qt::InvertedLandscapeOrientation : Qt::InvertedPortraitOrientation;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DLOG("QMirClientScreen::customEvent - Unknown orientation.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Raise the event signal so that client apps know the orientation changed
|
||||
DLOG("QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation));
|
||||
qCDebug(mirclient, "QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation));
|
||||
QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);
|
||||
}
|
||||
|
||||
@ -289,7 +144,7 @@ void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeig
|
||||
mGeometry.setWidth(currGeometry.height());
|
||||
mGeometry.setHeight(currGeometry.width());
|
||||
|
||||
DLOG("QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)",
|
||||
qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)",
|
||||
mGeometry.width(), mGeometry.height());
|
||||
QWindowSystemInterface::handleScreenGeometryChange(screen(),
|
||||
mGeometry /* newGeometry */,
|
||||
@ -300,7 +155,108 @@ void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeig
|
||||
} else {
|
||||
mCurrentOrientation = Qt::LandscapeOrientation;
|
||||
}
|
||||
DLOG("QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation));
|
||||
qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation));
|
||||
QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientScreen::setMirOutput(const MirOutput *output)
|
||||
{
|
||||
// Physical screen size (in mm)
|
||||
mPhysicalSize.setWidth(mir_output_get_physical_width_mm(output));
|
||||
mPhysicalSize.setHeight(mir_output_get_physical_height_mm(output));
|
||||
|
||||
// Pixel Format
|
||||
// mFormat = qImageFormatFromMirPixelFormat(mir_output_get_current_pixel_format(output)); // GERRY: TODO
|
||||
|
||||
// Pixel depth
|
||||
mDepth = 8 * MIR_BYTES_PER_PIXEL(mir_output_get_current_pixel_format(output));
|
||||
|
||||
// Mode = Resolution & refresh rate
|
||||
const MirOutputMode *mode = mir_output_get_current_mode(output);
|
||||
mNativeGeometry.setX(mir_output_get_position_x(output));
|
||||
mNativeGeometry.setY(mir_output_get_position_y(output));
|
||||
mNativeGeometry.setWidth(mir_output_mode_get_width(mode));
|
||||
mNativeGeometry.setHeight(mir_output_mode_get_height(mode));
|
||||
|
||||
mRefreshRate = mir_output_mode_get_refresh_rate(mode);
|
||||
|
||||
// UI scale & DPR
|
||||
mScale = mir_output_get_scale_factor(output);
|
||||
if (overrideDevicePixelRatio > 0) {
|
||||
mDevicePixelRatio = overrideDevicePixelRatio;
|
||||
} else {
|
||||
mDevicePixelRatio = 1.0; // FIXME - need to determine suitable DPR for the specified scale
|
||||
}
|
||||
|
||||
mFormFactor = mir_output_get_form_factor(output);
|
||||
|
||||
mOutputId = mir_output_get_id(output);
|
||||
|
||||
mGeometry.setX(mNativeGeometry.x());
|
||||
mGeometry.setY(mNativeGeometry.y());
|
||||
mGeometry.setWidth(mNativeGeometry.width());
|
||||
mGeometry.setHeight(mNativeGeometry.height());
|
||||
|
||||
// Set the default orientation based on the initial screen dimensions.
|
||||
mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
|
||||
|
||||
// If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
|
||||
mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
|
||||
}
|
||||
|
||||
void QMirClientScreen::updateMirOutput(const MirOutput *output)
|
||||
{
|
||||
auto oldRefreshRate = mRefreshRate;
|
||||
auto oldScale = mScale;
|
||||
auto oldFormFactor = mFormFactor;
|
||||
auto oldGeometry = mGeometry;
|
||||
|
||||
setMirOutput(output);
|
||||
|
||||
// Emit change signals in particular order
|
||||
if (oldGeometry != mGeometry) {
|
||||
QWindowSystemInterface::handleScreenGeometryChange(screen(),
|
||||
mGeometry /* newGeometry */,
|
||||
mGeometry /* newAvailableGeometry */);
|
||||
}
|
||||
|
||||
if (!qFuzzyCompare(mRefreshRate, oldRefreshRate)) {
|
||||
QWindowSystemInterface::handleScreenRefreshRateChange(screen(), mRefreshRate);
|
||||
}
|
||||
|
||||
auto nativeInterface = static_cast<QMirClientNativeInterface *>(qGuiApp->platformNativeInterface());
|
||||
if (!qFuzzyCompare(mScale, oldScale)) {
|
||||
nativeInterface->screenPropertyChanged(this, QStringLiteral("scale"));
|
||||
}
|
||||
if (mFormFactor != oldFormFactor) {
|
||||
nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor"));
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientScreen::setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi)
|
||||
{
|
||||
if (mDpi != dpi) {
|
||||
mDpi = dpi;
|
||||
QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), dpi, dpi);
|
||||
}
|
||||
|
||||
auto nativeInterface = static_cast<QMirClientNativeInterface *>(qGuiApp->platformNativeInterface());
|
||||
if (!qFuzzyCompare(mScale, scale)) {
|
||||
mScale = scale;
|
||||
nativeInterface->screenPropertyChanged(this, QStringLiteral("scale"));
|
||||
}
|
||||
if (mFormFactor != formFactor) {
|
||||
mFormFactor = formFactor;
|
||||
nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor"));
|
||||
}
|
||||
}
|
||||
|
||||
QDpi QMirClientScreen::logicalDpi() const
|
||||
{
|
||||
if (mDpi > 0) {
|
||||
return QDpi(mDpi, mDpi);
|
||||
} else {
|
||||
return QPlatformScreen::logicalDpi();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014-2015 Canonical, Ltd.
|
||||
** Copyright (C) 2014-2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -43,17 +43,19 @@
|
||||
|
||||
#include <qpa/qplatformscreen.h>
|
||||
#include <QSurfaceFormat>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <mir_toolkit/common.h> // just for MirFormFactor enum
|
||||
|
||||
#include "qmirclientcursor.h"
|
||||
|
||||
struct MirConnection;
|
||||
struct MirOutput;
|
||||
|
||||
class QMirClientScreen : public QObject, public QPlatformScreen
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QMirClientScreen(MirConnection *connection);
|
||||
QMirClientScreen(const MirOutput *output, MirConnection *connection);
|
||||
virtual ~QMirClientScreen();
|
||||
|
||||
// QPlatformScreen methods.
|
||||
@ -62,34 +64,43 @@ public:
|
||||
QRect geometry() const override { return mGeometry; }
|
||||
QRect availableGeometry() const override { return mGeometry; }
|
||||
QSizeF physicalSize() const override { return mPhysicalSize; }
|
||||
qreal devicePixelRatio() const override { return mDevicePixelRatio; }
|
||||
QDpi logicalDpi() const override;
|
||||
Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; }
|
||||
Qt::ScreenOrientation orientation() const override { return mNativeOrientation; }
|
||||
QPlatformCursor *cursor() const override { return const_cast<QMirClientCursor*>(&mCursor); }
|
||||
|
||||
// New methods.
|
||||
QSurfaceFormat surfaceFormat() const { return mSurfaceFormat; }
|
||||
EGLDisplay eglDisplay() const { return mEglDisplay; }
|
||||
EGLConfig eglConfig() const { return mEglConfig; }
|
||||
EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
|
||||
// Additional Screen properties from Mir
|
||||
int mirOutputId() const { return mOutputId; }
|
||||
MirFormFactor formFactor() const { return mFormFactor; }
|
||||
float scale() const { return mScale; }
|
||||
|
||||
// Internally used methods
|
||||
void updateMirOutput(const MirOutput *output);
|
||||
void setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi);
|
||||
void handleWindowSurfaceResize(int width, int height);
|
||||
uint32_t mirOutputId() const { return mOutputId; }
|
||||
|
||||
// QObject methods.
|
||||
void customEvent(QEvent* event) override;
|
||||
|
||||
private:
|
||||
QRect mGeometry;
|
||||
void setMirOutput(const MirOutput *output);
|
||||
|
||||
QRect mGeometry, mNativeGeometry;
|
||||
QSizeF mPhysicalSize;
|
||||
qreal mDevicePixelRatio;
|
||||
Qt::ScreenOrientation mNativeOrientation;
|
||||
Qt::ScreenOrientation mCurrentOrientation;
|
||||
QImage::Format mFormat;
|
||||
int mDepth;
|
||||
uint32_t mOutputId;
|
||||
QSurfaceFormat mSurfaceFormat;
|
||||
EGLDisplay mEglDisplay;
|
||||
EGLConfig mEglConfig;
|
||||
EGLNativeDisplayType mEglNativeDisplay;
|
||||
int mDpi;
|
||||
qreal mRefreshRate;
|
||||
MirFormFactor mFormFactor;
|
||||
float mScale;
|
||||
int mOutputId;
|
||||
QMirClientCursor mCursor;
|
||||
|
||||
friend class QMirClientNativeInterface;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTSCREEN_H
|
||||
|
161
src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp
Normal file
161
src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "qmirclientscreenobserver.h"
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclientwindow.h"
|
||||
#include "qmirclientlogging.h"
|
||||
|
||||
// Qt
|
||||
#include <QMetaObject>
|
||||
#include <QPointer>
|
||||
|
||||
// Mir
|
||||
#include <mirclient/mir_toolkit/mir_connection.h>
|
||||
#include <mirclient/mir_toolkit/mir_display_configuration.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
static void displayConfigurationChangedCallback(MirConnection */*connection*/, void* context)
|
||||
{
|
||||
ASSERT(context != NULL);
|
||||
QMirClientScreenObserver *observer = static_cast<QMirClientScreenObserver *>(context);
|
||||
QMetaObject::invokeMethod(observer, "update");
|
||||
}
|
||||
|
||||
const char *mirFormFactorToStr(MirFormFactor formFactor)
|
||||
{
|
||||
switch (formFactor) {
|
||||
case mir_form_factor_unknown: return "unknown";
|
||||
case mir_form_factor_phone: return "phone";
|
||||
case mir_form_factor_tablet: return "tablet";
|
||||
case mir_form_factor_monitor: return "monitor";
|
||||
case mir_form_factor_tv: return "tv";
|
||||
case mir_form_factor_projector: return "projector";
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
QMirClientScreenObserver::QMirClientScreenObserver(MirConnection *mirConnection)
|
||||
: mMirConnection(mirConnection)
|
||||
{
|
||||
mir_connection_set_display_config_change_callback(mirConnection, ::displayConfigurationChangedCallback, this);
|
||||
update();
|
||||
}
|
||||
|
||||
void QMirClientScreenObserver::update()
|
||||
{
|
||||
// Wrap MirDisplayConfiguration to always delete when out of scope
|
||||
auto configDeleter = [](MirDisplayConfig *config) { mir_display_config_release(config); };
|
||||
using configUp = std::unique_ptr<MirDisplayConfig, decltype(configDeleter)>;
|
||||
configUp displayConfig(mir_connection_create_display_configuration(mMirConnection), configDeleter);
|
||||
|
||||
// Mir only tells us something changed, it is up to us to figure out what.
|
||||
QList<QMirClientScreen*> newScreenList;
|
||||
QList<QMirClientScreen*> oldScreenList = mScreenList;
|
||||
mScreenList.clear();
|
||||
|
||||
for (int i = 0; i < mir_display_config_get_num_outputs(displayConfig.get()); i++) {
|
||||
const MirOutput *output = mir_display_config_get_output(displayConfig.get(), i);
|
||||
if (mir_output_is_enabled(output)) {
|
||||
QMirClientScreen *screen = findScreenWithId(oldScreenList, mir_output_get_id(output));
|
||||
if (screen) { // we've already set up this display before
|
||||
screen->updateMirOutput(output);
|
||||
oldScreenList.removeAll(screen);
|
||||
} else {
|
||||
// new display, so create QMirClientScreen for it
|
||||
screen = new QMirClientScreen(output, mMirConnection);
|
||||
newScreenList.append(screen);
|
||||
qCDebug(mirclient) << "Added Screen with id" << mir_output_get_id(output)
|
||||
<< "and geometry" << screen->geometry();
|
||||
}
|
||||
mScreenList.append(screen);
|
||||
}
|
||||
}
|
||||
|
||||
// Announce old & unused Screens, should be deleted by the slot
|
||||
Q_FOREACH (const auto screen, oldScreenList) {
|
||||
Q_EMIT screenRemoved(screen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mir's MirDisplayOutput does not include formFactor or scale for some reason, but Qt
|
||||
* will want that information on creating the QScreen. Only way we get that info is when
|
||||
* Mir positions a Window on that Screen. See "handleScreenPropertiesChange" method
|
||||
*/
|
||||
|
||||
// Announce new Screens
|
||||
Q_FOREACH (const auto screen, newScreenList) {
|
||||
Q_EMIT screenAdded(screen);
|
||||
}
|
||||
|
||||
qCDebug(mirclient) << "=======================================";
|
||||
for (auto screen: mScreenList) {
|
||||
qCDebug(mirclient) << screen << "- id:" << screen->mirOutputId()
|
||||
<< "geometry:" << screen->geometry()
|
||||
<< "form factor:" << mirFormFactorToStr(screen->formFactor())
|
||||
<< "scale:" << screen->scale();
|
||||
}
|
||||
qCDebug(mirclient) << "=======================================";
|
||||
}
|
||||
|
||||
QMirClientScreen *QMirClientScreenObserver::findScreenWithId(int id)
|
||||
{
|
||||
return findScreenWithId(mScreenList, id);
|
||||
}
|
||||
|
||||
QMirClientScreen *QMirClientScreenObserver::findScreenWithId(const QList<QMirClientScreen *> &list, int id)
|
||||
{
|
||||
Q_FOREACH (const auto screen, list) {
|
||||
if (screen->mirOutputId() == id) {
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void QMirClientScreenObserver::handleScreenPropertiesChange(QMirClientScreen *screen, int dpi,
|
||||
MirFormFactor formFactor, float scale)
|
||||
{
|
||||
screen->setAdditionalMirDisplayProperties(scale, formFactor, dpi);
|
||||
}
|
||||
|
78
src/plugins/platforms/mirclient/qmirclientscreenobserver.h
Normal file
78
src/plugins/platforms/mirclient/qmirclientscreenobserver.h
Normal file
@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef QMIRCLIENTSCREENOBSERVER_H
|
||||
#define QMIRCLIENTSCREENOBSERVER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <mir_toolkit/mir_connection.h>
|
||||
|
||||
class QMirClientScreen;
|
||||
|
||||
class QMirClientScreenObserver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QMirClientScreenObserver(MirConnection *connection);
|
||||
|
||||
QList<QMirClientScreen*> screens() const { return mScreenList; }
|
||||
QMirClientScreen *findScreenWithId(int id);
|
||||
|
||||
void handleScreenPropertiesChange(QMirClientScreen *screen, int dpi,
|
||||
MirFormFactor formFactor, float scale);
|
||||
|
||||
Q_SIGNALS:
|
||||
void screenAdded(QMirClientScreen *screen);
|
||||
void screenRemoved(QMirClientScreen *screen);
|
||||
|
||||
private Q_SLOTS:
|
||||
void update();
|
||||
|
||||
private:
|
||||
QMirClientScreen *findScreenWithId(const QList<QMirClientScreen *> &list, int id);
|
||||
void removeScreen(QMirClientScreen *screen);
|
||||
|
||||
MirConnection *mMirConnection;
|
||||
QList<QMirClientScreen*> mScreenList;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTSCREENOBSERVER_H
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014-2015 Canonical, Ltd.
|
||||
** Copyright (C) 2014-2016 Canonical, Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -45,44 +45,74 @@
|
||||
#include <QSharedPointer>
|
||||
#include <QMutex>
|
||||
|
||||
#include <mir_toolkit/common.h> // needed only for MirFormFactor enum
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QMirClientClipboard;
|
||||
#include <EGL/egl.h>
|
||||
|
||||
class QMirClientAppStateController;
|
||||
class QMirClientDebugExtension;
|
||||
class QMirClientNativeInterface;
|
||||
class QMirClientInput;
|
||||
class QMirClientScreen;
|
||||
class QMirClientSurface;
|
||||
struct MirConnection;
|
||||
class UbuntuSurface;
|
||||
struct MirSurface;
|
||||
class MirConnection;
|
||||
|
||||
class QMirClientWindow : public QObject, public QPlatformWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen,
|
||||
QMirClientInput *input, MirConnection *mirConnection);
|
||||
QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface* native,
|
||||
QMirClientAppStateController *appState, EGLDisplay eglDisplay,
|
||||
MirConnection *mirConnection, QMirClientDebugExtension *debugExt);
|
||||
virtual ~QMirClientWindow();
|
||||
|
||||
// QPlatformWindow methods.
|
||||
WId winId() const override;
|
||||
QRect geometry() const override;
|
||||
void setGeometry(const QRect&) override;
|
||||
void setWindowState(Qt::WindowState state) override;
|
||||
void setWindowFlags(Qt::WindowFlags flags) override;
|
||||
void setVisible(bool visible) override;
|
||||
void setWindowTitle(const QString &title) override;
|
||||
void propagateSizeHints() override;
|
||||
bool isExposed() const override;
|
||||
|
||||
QPoint mapToGlobal(const QPoint &pos) const override;
|
||||
QSurfaceFormat format() const override;
|
||||
|
||||
// Additional Window properties exposed by NativeInterface
|
||||
MirFormFactor formFactor() const { return mFormFactor; }
|
||||
float scale() const { return mScale; }
|
||||
|
||||
// New methods.
|
||||
void *eglSurface() const;
|
||||
MirSurface *mirSurface() const;
|
||||
void handleSurfaceResized(int width, int height);
|
||||
void handleSurfaceFocused();
|
||||
void handleSurfaceExposeChange(bool exposed);
|
||||
void handleSurfaceFocusChanged(bool focused);
|
||||
void handleSurfaceVisibilityChanged(bool visible);
|
||||
void handleSurfaceStateChanged(Qt::WindowState state);
|
||||
void onSwapBuffersDone();
|
||||
void handleScreenPropertiesChange(MirFormFactor formFactor, float scale);
|
||||
QString persistentSurfaceId();
|
||||
|
||||
private:
|
||||
void updatePanelHeightHack(Qt::WindowState);
|
||||
void updateSurfaceState();
|
||||
mutable QMutex mMutex;
|
||||
const WId mId;
|
||||
const QSharedPointer<QMirClientClipboard> mClipboard;
|
||||
std::unique_ptr<QMirClientSurface> mSurface;
|
||||
Qt::WindowState mWindowState;
|
||||
Qt::WindowFlags mWindowFlags;
|
||||
bool mWindowVisible;
|
||||
bool mWindowExposed;
|
||||
QMirClientAppStateController *mAppStateController;
|
||||
QMirClientDebugExtension *mDebugExtention;
|
||||
QMirClientNativeInterface *mNativeInterface;
|
||||
std::unique_ptr<UbuntuSurface> mSurface;
|
||||
float mScale;
|
||||
MirFormFactor mFormFactor;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTWINDOW_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user