Mirclient: update with upstream changes
Merge in the changes up to revision 306 of the lp:qtubuntu repo. Change-Id: I55dcb9e06e0a3503d6abe4b0894d5ef5a785b6bb Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
This commit is contained in:
parent
1172e18c3c
commit
bfd367c6ec
@ -21,6 +21,7 @@ PKGCONFIG += egl mirclient ubuntu-platform-api
|
||||
SOURCES = \
|
||||
qmirclientbackingstore.cpp \
|
||||
qmirclientclipboard.cpp \
|
||||
qmirclientcursor.cpp \
|
||||
qmirclientglcontext.cpp \
|
||||
qmirclientinput.cpp \
|
||||
qmirclientintegration.cpp \
|
||||
@ -34,6 +35,7 @@ SOURCES = \
|
||||
HEADERS = \
|
||||
qmirclientbackingstore.h \
|
||||
qmirclientclipboard.h \
|
||||
qmirclientcursor.h \
|
||||
qmirclientglcontext.h \
|
||||
qmirclientinput.h \
|
||||
qmirclientintegration.h \
|
||||
|
@ -87,12 +87,12 @@ void QMirClientClipboard::requestDBusClipboardContents()
|
||||
if (!mPendingGetContentsCall.isNull())
|
||||
return;
|
||||
|
||||
QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("GetContents");
|
||||
QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("GetContents"));
|
||||
|
||||
mPendingGetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
|
||||
|
||||
QObject::connect(mPendingGetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*)));
|
||||
QObject::connect(mPendingGetContentsCall.data(), &QDBusPendingCallWatcher::finished,
|
||||
this, &QMirClientClipboard::onDBusClipboardGetContentsFinished);
|
||||
}
|
||||
|
||||
void QMirClientClipboard::onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher* call)
|
||||
@ -143,18 +143,18 @@ void QMirClientClipboard::setupDBus()
|
||||
QDBusConnection dbusConnection = QDBusConnection::sessionBus();
|
||||
|
||||
bool ok = dbusConnection.connect(
|
||||
"com.canonical.QtMir",
|
||||
"/com/canonical/QtMir/Clipboard",
|
||||
"com.canonical.QtMir.Clipboard",
|
||||
"ContentsChanged",
|
||||
QStringLiteral("com.canonical.QtMir"),
|
||||
QStringLiteral("/com/canonical/QtMir/Clipboard"),
|
||||
QStringLiteral("com.canonical.QtMir.Clipboard"),
|
||||
QStringLiteral("ContentsChanged"),
|
||||
this, SLOT(updateMimeData(QByteArray)));
|
||||
if (!ok) {
|
||||
qCritical("QMirClientClipboard - Failed to connect to ContentsChanged signal form the D-Bus system clipboard.");
|
||||
}
|
||||
|
||||
mDBusClipboard = new QDBusInterface("com.canonical.QtMir",
|
||||
"/com/canonical/QtMir/Clipboard",
|
||||
"com.canonical.QtMir.Clipboard",
|
||||
mDBusClipboard = new QDBusInterface(QStringLiteral("com.canonical.QtMir"),
|
||||
QStringLiteral("/com/canonical/QtMir/Clipboard"),
|
||||
QStringLiteral("com.canonical.QtMir.Clipboard"),
|
||||
dbusConnection);
|
||||
|
||||
mDBusSetupDone = true;
|
||||
@ -162,6 +162,8 @@ void QMirClientClipboard::setupDBus()
|
||||
|
||||
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));
|
||||
@ -180,12 +182,13 @@ QByteArray QMirClientClipboard::serializeMimeData(QMimeData *mimeData) const
|
||||
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 = mimeData->data(formats[i]).size();
|
||||
const int dataSize = data.size();
|
||||
memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize);
|
||||
memcpy(&buffer[dataOffset], mimeData->data(formats[i]).data(), dataSize);
|
||||
memcpy(&buffer[dataOffset], data.data(), dataSize);
|
||||
header[i*4+1] = formatOffset;
|
||||
header[i*4+2] = formatSize;
|
||||
header[i*4+3] = dataOffset;
|
||||
@ -265,6 +268,7 @@ void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode
|
||||
delete mPendingGetContentsCall.data();
|
||||
}
|
||||
|
||||
if (mimeData != nullptr) {
|
||||
QByteArray serializedMimeData = serializeMimeData(mimeData);
|
||||
if (!serializedMimeData.isEmpty()) {
|
||||
setDBusClipboardContents(serializedMimeData);
|
||||
@ -272,6 +276,7 @@ void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode
|
||||
|
||||
mMimeData = mimeData;
|
||||
emitChanged(QClipboard::Clipboard);
|
||||
}
|
||||
}
|
||||
|
||||
bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const
|
||||
@ -287,6 +292,10 @@ bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const
|
||||
|
||||
void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardContents)
|
||||
{
|
||||
if (!mDBusSetupDone) {
|
||||
setupDBus();
|
||||
}
|
||||
|
||||
if (!mPendingSetContentsCall.isNull()) {
|
||||
// Ignore any previous set call as we are going to overwrite it anyway
|
||||
QObject::disconnect(mPendingSetContentsCall.data(), 0, this, 0);
|
||||
@ -296,10 +305,10 @@ void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardCo
|
||||
delete mPendingSetContentsCall.data();
|
||||
}
|
||||
|
||||
QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("SetContents", clipboardContents);
|
||||
QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("SetContents"), clipboardContents);
|
||||
|
||||
mPendingSetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
|
||||
|
||||
QObject::connect(mPendingSetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*)));
|
||||
QObject::connect(mPendingSetContentsCall.data(), &QDBusPendingCallWatcher::finished,
|
||||
this, &QMirClientClipboard::onDBusClipboardSetContentsFinished);
|
||||
}
|
||||
|
201
src/plugins/platforms/mirclient/qmirclientcursor.cpp
Normal file
201
src/plugins/platforms/mirclient/qmirclientcursor.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Canonical, Ltd.
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL3$
|
||||
** 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 http://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.GPL included in
|
||||
** the packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 2.0 requirements will be
|
||||
** met: http://www.gnu.org/licenses/gpl-2.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "qmirclientcursor.h"
|
||||
|
||||
#include "qmirclientlogging.h"
|
||||
#include "qmirclientwindow.h"
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
QMirClientCursor::QMirClientCursor(MirConnection *connection)
|
||||
: mConnection(connection)
|
||||
{
|
||||
mShapeToCursorName[Qt::ArrowCursor] = "left_ptr";
|
||||
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::ForbiddenCursor] = "forbidden";
|
||||
mShapeToCursorName[Qt::WhatsThisCursor] = "whats_this";
|
||||
mShapeToCursorName[Qt::BusyCursor] = "left_ptr_watch";
|
||||
mShapeToCursorName[Qt::OpenHandCursor] = "openhand";
|
||||
mShapeToCursorName[Qt::ClosedHandCursor] = "closedhand";
|
||||
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) {
|
||||
case Qt::ArrowCursor:
|
||||
return "Arrow";
|
||||
case Qt::UpArrowCursor:
|
||||
return "UpArrow";
|
||||
case Qt::CrossCursor:
|
||||
return "Cross";
|
||||
case Qt::WaitCursor:
|
||||
return "Wait";
|
||||
case Qt::IBeamCursor:
|
||||
return "IBeam";
|
||||
case Qt::SizeVerCursor:
|
||||
return "SizeVer";
|
||||
case Qt::SizeHorCursor:
|
||||
return "SizeHor";
|
||||
case Qt::SizeBDiagCursor:
|
||||
return "SizeBDiag";
|
||||
case Qt::SizeFDiagCursor:
|
||||
return "SizeFDiag";
|
||||
case Qt::SizeAllCursor:
|
||||
return "SizeAll";
|
||||
case Qt::BlankCursor:
|
||||
return "Blank";
|
||||
case Qt::SplitVCursor:
|
||||
return "SplitV";
|
||||
case Qt::SplitHCursor:
|
||||
return "SplitH";
|
||||
case Qt::PointingHandCursor:
|
||||
return "PointingHand";
|
||||
case Qt::ForbiddenCursor:
|
||||
return "Forbidden";
|
||||
case Qt::WhatsThisCursor:
|
||||
return "WhatsThis";
|
||||
case Qt::BusyCursor:
|
||||
return "Busy";
|
||||
case Qt::OpenHandCursor:
|
||||
return "OpenHand";
|
||||
case Qt::ClosedHandCursor:
|
||||
return "ClosedHand";
|
||||
case Qt::DragCopyCursor:
|
||||
return "DragCopy";
|
||||
case Qt::DragMoveCursor:
|
||||
return "DragMove";
|
||||
case Qt::DragLinkCursor:
|
||||
return "DragLink";
|
||||
case Qt::BitmapCursor:
|
||||
return "Bitmap";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
#endif // !defined(QT_NO_DEBUG)
|
||||
} // anonymous namespace
|
||||
|
||||
void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)
|
||||
{
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
MirSurface *surface = static_cast<QMirClientWindow*>(window->handle())->mirSurface();
|
||||
|
||||
if (!surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (windowCursor) {
|
||||
DLOG("[ubuntumirclient QPA] changeCursor shape=%s, window=%p\n", qtCursorShapeToStr(windowCursor->shape()), window);
|
||||
if (!windowCursor->pixmap().isNull()) {
|
||||
configureMirCursorWithPixmapQCursor(surface, *windowCursor);
|
||||
} else if (windowCursor->shape() == Qt::BitmapCursor) {
|
||||
// TODO: Implement bitmap cursor support
|
||||
applyDefaultCursorConfiguration(surface);
|
||||
} else {
|
||||
const auto &cursorName = mShapeToCursorName.value(windowCursor->shape(), QByteArray("left_ptr"));
|
||||
auto cursorConfiguration = mir_cursor_configuration_from_name(cursorName.data());
|
||||
mir_surface_configure_cursor(surface, cursorConfiguration);
|
||||
mir_cursor_configuration_destroy(cursorConfiguration);
|
||||
}
|
||||
} else {
|
||||
applyDefaultCursorConfiguration(surface);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QMirClientCursor::configureMirCursorWithPixmapQCursor(MirSurface *surface, QCursor &cursor)
|
||||
{
|
||||
QImage image = cursor.pixmap().toImage();
|
||||
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
MirBufferStream *bufferStream = mir_connection_create_buffer_stream_sync(mConnection,
|
||||
image.width(), image.height(), mir_pixel_format_argb_8888, mir_buffer_usage_software);
|
||||
|
||||
{
|
||||
MirGraphicsRegion region;
|
||||
mir_buffer_stream_get_graphics_region(bufferStream, ®ion);
|
||||
|
||||
char *regionLine = region.vaddr;
|
||||
Q_ASSERT(image.bytesPerLine() <= region.stride);
|
||||
for (int i = 0; i < image.height(); ++i) {
|
||||
memcpy(regionLine, image.scanLine(i), image.bytesPerLine());
|
||||
regionLine += region.stride;
|
||||
}
|
||||
}
|
||||
|
||||
mir_buffer_stream_swap_buffers_sync(bufferStream);
|
||||
|
||||
{
|
||||
auto configuration = mir_cursor_configuration_from_buffer_stream(bufferStream, cursor.hotSpot().x(), cursor.hotSpot().y());
|
||||
mir_surface_configure_cursor(surface, configuration);
|
||||
mir_cursor_configuration_destroy(configuration);
|
||||
}
|
||||
|
||||
mir_buffer_stream_release_sync(bufferStream);
|
||||
}
|
||||
|
||||
void QMirClientCursor::applyDefaultCursorConfiguration(MirSurface *surface)
|
||||
{
|
||||
auto cursorConfiguration = mir_cursor_configuration_from_name("left_ptr");
|
||||
mir_surface_configure_cursor(surface, cursorConfiguration);
|
||||
mir_cursor_configuration_destroy(cursorConfiguration);
|
||||
}
|
61
src/plugins/platforms/mirclient/qmirclientcursor.h
Normal file
61
src/plugins/platforms/mirclient/qmirclientcursor.h
Normal file
@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Canonical, Ltd.
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL3$
|
||||
** 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 http://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.GPL included in
|
||||
** the packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 2.0 requirements will be
|
||||
** met: http://www.gnu.org/licenses/gpl-2.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef QMIRCLIENTCURSOR_H
|
||||
#define QMIRCLIENTCURSOR_H
|
||||
|
||||
#include <qpa/qplatformcursor.h>
|
||||
|
||||
#include <QMap>
|
||||
#include <QByteArray>
|
||||
|
||||
struct MirConnection;
|
||||
struct MirSurface;
|
||||
|
||||
class QMirClientCursor : public QPlatformCursor
|
||||
{
|
||||
public:
|
||||
QMirClientCursor(MirConnection *connection);
|
||||
void changeCursor(QCursor *windowCursor, QWindow *window) override;
|
||||
private:
|
||||
void configureMirCursorWithPixmapQCursor(MirSurface *surface, QCursor &cursor);
|
||||
void applyDefaultCursorConfiguration(MirSurface *surface);
|
||||
QMap<int, QByteArray> mShapeToCursorName;
|
||||
MirConnection *mConnection;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTCURSOR_H
|
@ -130,19 +130,7 @@ void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface)
|
||||
ASSERT(eglSwapBuffers(mEglDisplay, eglSurface) == EGL_TRUE);
|
||||
#endif
|
||||
|
||||
// "Technique" copied from mir, in examples/eglapp.c around line 96
|
||||
EGLint newBufferWidth = -1;
|
||||
EGLint newBufferHeight = -1;
|
||||
/*
|
||||
* Querying the surface (actually the current buffer) dimensions here is
|
||||
* the only truly safe way to be sure that the dimensions we think we
|
||||
* have are those of the buffer being rendered to. But this should be
|
||||
* improved in future; https://bugs.launchpad.net/mir/+bug/1194384
|
||||
*/
|
||||
eglQuerySurface(mEglDisplay, eglSurface, EGL_WIDTH, &newBufferWidth);
|
||||
eglQuerySurface(mEglDisplay, eglSurface, EGL_HEIGHT, &newBufferHeight);
|
||||
|
||||
ubuntuWindow->onBuffersSwapped_threadSafe(newBufferWidth, newBufferHeight);
|
||||
ubuntuWindow->onSwapBuffersDone();
|
||||
}
|
||||
|
||||
void (*QMirClientOpenGLContext::getProcAddress(const QByteArray& procName)) ()
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
bool makeCurrent(QPlatformSurface* surface) override;
|
||||
void doneCurrent() override;
|
||||
bool isValid() const override { return mEglContext != EGL_NO_CONTEXT; }
|
||||
void (*getProcAddress(const QByteArray& procName)) ();
|
||||
void (*getProcAddress(const QByteArray& procName)) () override;
|
||||
|
||||
EGLContext eglContext() const { return mEglContext; }
|
||||
|
||||
|
@ -163,6 +163,7 @@ QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration)
|
||||
, mEventFilterType(static_cast<QMirClientNativeInterface*>(
|
||||
integration->nativeInterface())->genericEventFilterType())
|
||||
, mEventType(static_cast<QEvent::Type>(QEvent::registerEventType()))
|
||||
, mLastFocusedWindow(nullptr)
|
||||
{
|
||||
// Initialize touch device.
|
||||
mTouchDevice = new QTouchDevice;
|
||||
@ -234,7 +235,7 @@ void QMirClientInput::customEvent(QEvent* event)
|
||||
switch (mir_event_get_type(nativeEvent))
|
||||
{
|
||||
case mir_event_type_input:
|
||||
dispatchInputEvent(ubuntuEvent->window->window(), mir_event_get_input_event(nativeEvent));
|
||||
dispatchInputEvent(ubuntuEvent->window, mir_event_get_input_event(nativeEvent));
|
||||
break;
|
||||
case mir_event_type_resize:
|
||||
{
|
||||
@ -246,7 +247,7 @@ void QMirClientInput::customEvent(QEvent* event)
|
||||
mir_resize_event_get_width(resizeEvent),
|
||||
mir_resize_event_get_height(resizeEvent));
|
||||
|
||||
ubuntuEvent->window->handleSurfaceResize(mir_resize_event_get_width(resizeEvent),
|
||||
ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent),
|
||||
mir_resize_event_get_height(resizeEvent));
|
||||
break;
|
||||
}
|
||||
@ -254,8 +255,24 @@ void QMirClientInput::customEvent(QEvent* event)
|
||||
{
|
||||
auto surfaceEvent = mir_event_get_surface_event(nativeEvent);
|
||||
if (mir_surface_event_get_attribute(surfaceEvent) == mir_surface_attrib_focus) {
|
||||
ubuntuEvent->window->handleSurfaceFocusChange(mir_surface_event_get_attribute_value(surfaceEvent) ==
|
||||
mir_surface_focused);
|
||||
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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -274,6 +291,17 @@ 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(
|
||||
platformWindow, event, mEventType));
|
||||
|
||||
@ -284,7 +312,7 @@ void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientInput::dispatchInputEvent(QWindow *window, const MirInputEvent *ev)
|
||||
void QMirClientInput::dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *ev)
|
||||
{
|
||||
switch (mir_input_event_get_type(ev))
|
||||
{
|
||||
@ -302,7 +330,7 @@ void QMirClientInput::dispatchInputEvent(QWindow *window, const MirInputEvent *e
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *ev)
|
||||
void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *ev)
|
||||
{
|
||||
const MirTouchEvent *tev = mir_input_event_get_touch_event(ev);
|
||||
|
||||
@ -333,6 +361,7 @@ void QMirClientInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *e
|
||||
switch (touch_action)
|
||||
{
|
||||
case mir_touch_action_down:
|
||||
mLastFocusedWindow = window;
|
||||
touchPoint.state = Qt::TouchPointPressed;
|
||||
break;
|
||||
case mir_touch_action_up:
|
||||
@ -347,7 +376,7 @@ void QMirClientInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *e
|
||||
}
|
||||
|
||||
ulong timestamp = mir_input_event_get_event_time(ev) / 1000000;
|
||||
QWindowSystemInterface::handleTouchEvent(window, timestamp,
|
||||
QWindowSystemInterface::handleTouchEvent(window->window(), timestamp,
|
||||
mTouchDevice, touchPoints);
|
||||
}
|
||||
|
||||
@ -390,7 +419,7 @@ Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers)
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *event)
|
||||
void QMirClientInput::dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event)
|
||||
{
|
||||
const MirKeyboardEvent *key_event = mir_input_event_get_keyboard_event(event);
|
||||
|
||||
@ -404,6 +433,9 @@ void QMirClientInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *eve
|
||||
QEvent::Type keyType = action == mir_keyboard_action_up
|
||||
? QEvent::KeyRelease : QEvent::KeyPress;
|
||||
|
||||
if (action == mir_keyboard_action_down)
|
||||
mLastFocusedWindow = window;
|
||||
|
||||
char s[2];
|
||||
int sym = translateKeysym(xk_sym, s, sizeof(s));
|
||||
QString text = QString::fromLatin1(s);
|
||||
@ -420,7 +452,7 @@ void QMirClientInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *eve
|
||||
}
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleKeyEvent(window, timestamp, keyType, sym, modifiers, text, is_auto_rep);
|
||||
QWindowSystemInterface::handleKeyEvent(window->window(), timestamp, keyType, sym, modifiers, text, is_auto_rep);
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -433,27 +465,54 @@ Qt::MouseButtons extract_buttons(const MirPointerEvent *pev)
|
||||
if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary))
|
||||
buttons |= Qt::RightButton;
|
||||
if (mir_pointer_event_button_state(pev, mir_pointer_button_tertiary))
|
||||
buttons |= Qt::MidButton;
|
||||
buttons |= Qt::MiddleButton;
|
||||
if (mir_pointer_event_button_state(pev, mir_pointer_button_back))
|
||||
buttons |= Qt::BackButton;
|
||||
if (mir_pointer_event_button_state(pev, mir_pointer_button_forward))
|
||||
buttons |= Qt::ForwardButton;
|
||||
|
||||
// TODO: Should mir back and forward buttons exist?
|
||||
// should they be Qt::X button 1 and 2?
|
||||
return buttons;
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientInput::dispatchPointerEvent(QWindow *window, const MirInputEvent *ev)
|
||||
void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, const MirInputEvent *ev)
|
||||
{
|
||||
auto window = platformWindow->window();
|
||||
auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
|
||||
|
||||
auto pev = mir_input_event_get_pointer_event(ev);
|
||||
auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
|
||||
auto buttons = extract_buttons(pev);
|
||||
|
||||
auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
|
||||
auto action = mir_pointer_event_action(pev);
|
||||
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));
|
||||
|
||||
QWindowSystemInterface::handleMouseEvent(window, timestamp, local_point, local_point /* Should we omit global point instead? */,
|
||||
switch (action) {
|
||||
case mir_pointer_action_button_up:
|
||||
case mir_pointer_action_button_down:
|
||||
case mir_pointer_action_motion:
|
||||
{
|
||||
const float hDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_hscroll);
|
||||
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);
|
||||
QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, window->position() + localPoint,
|
||||
QPoint(), angleDelta, modifiers, Qt::ScrollUpdate);
|
||||
}
|
||||
auto buttons = extract_buttons(pev);
|
||||
QWindowSystemInterface::handleMouseEvent(window, timestamp, localPoint, window->position() + localPoint /* Should we omit global point instead? */,
|
||||
buttons, modifiers);
|
||||
break;
|
||||
}
|
||||
case mir_pointer_action_enter:
|
||||
QWindowSystemInterface::handleEnterEvent(window, localPoint, window->position() + localPoint);
|
||||
break;
|
||||
case mir_pointer_action_leave:
|
||||
QWindowSystemInterface::handleLeaveEvent(window);
|
||||
break;
|
||||
default:
|
||||
DLOG("Unrecognized pointer event");
|
||||
}
|
||||
}
|
||||
|
||||
#if (LOG_EVENTS != 0)
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
// Qt
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QAtomicInt>
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
@ -59,12 +60,13 @@ public:
|
||||
|
||||
void postEvent(QMirClientWindow* window, const MirEvent *event);
|
||||
QMirClientClientIntegration* integration() const { return mIntegration; }
|
||||
QMirClientWindow *lastFocusedWindow() const {return mLastFocusedWindow; }
|
||||
|
||||
protected:
|
||||
void dispatchKeyEvent(QWindow *window, const MirInputEvent *event);
|
||||
void dispatchPointerEvent(QWindow *window, const MirInputEvent *event);
|
||||
void dispatchTouchEvent(QWindow *window, const MirInputEvent *event);
|
||||
void dispatchInputEvent(QWindow *window, const MirInputEvent *event);
|
||||
void dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event);
|
||||
void dispatchPointerEvent(QMirClientWindow *window, const MirInputEvent *event);
|
||||
void dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *event);
|
||||
void dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *event);
|
||||
|
||||
void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event);
|
||||
|
||||
@ -73,6 +75,9 @@ private:
|
||||
QTouchDevice* mTouchDevice;
|
||||
const QByteArray mEventFilterType;
|
||||
const QEvent::Type mEventType;
|
||||
|
||||
QMirClientWindow *mLastFocusedWindow;
|
||||
QAtomicInt mPendingFocusGainedEvents;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTINPUT_H
|
||||
|
@ -35,6 +35,18 @@
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
// Local
|
||||
#include "qmirclientintegration.h"
|
||||
#include "qmirclientbackingstore.h"
|
||||
#include "qmirclientclipboard.h"
|
||||
#include "qmirclientglcontext.h"
|
||||
#include "qmirclientinput.h"
|
||||
#include "qmirclientlogging.h"
|
||||
#include "qmirclientnativeinterface.h"
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclienttheme.h"
|
||||
#include "qmirclientwindow.h"
|
||||
|
||||
// Qt
|
||||
#include <QGuiApplication>
|
||||
#include <private/qguiapplication_p.h>
|
||||
@ -45,18 +57,6 @@
|
||||
#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
|
||||
#include <QOpenGLContext>
|
||||
|
||||
// Local
|
||||
#include "qmirclientbackingstore.h"
|
||||
#include "qmirclientclipboard.h"
|
||||
#include "qmirclientglcontext.h"
|
||||
#include "qmirclientinput.h"
|
||||
#include "qmirclientintegration.h"
|
||||
#include "qmirclientlogging.h"
|
||||
#include "qmirclientnativeinterface.h"
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclienttheme.h"
|
||||
#include "qmirclientwindow.h"
|
||||
|
||||
// platform-api
|
||||
#include <ubuntu/application/lifecycle_delegate.h>
|
||||
#include <ubuntu/application/id.h>
|
||||
@ -67,8 +67,11 @@ static void resumedCallback(const UApplicationOptions *options, void* context)
|
||||
Q_UNUSED(options)
|
||||
Q_UNUSED(context)
|
||||
DASSERT(context != NULL);
|
||||
QCoreApplication::postEvent(QCoreApplication::instance(),
|
||||
new QEvent(QEvent::ApplicationActivate));
|
||||
if (qGuiApp->focusWindow()) {
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
|
||||
} else {
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
|
||||
}
|
||||
}
|
||||
|
||||
static void aboutToStopCallback(UApplicationArchive *archive, void* context)
|
||||
@ -76,9 +79,13 @@ static void aboutToStopCallback(UApplicationArchive *archive, void* context)
|
||||
Q_UNUSED(archive)
|
||||
DASSERT(context != NULL);
|
||||
QMirClientClientIntegration* integration = static_cast<QMirClientClientIntegration*>(context);
|
||||
integration->inputContext()->hideInputPanel();
|
||||
QCoreApplication::postEvent(QCoreApplication::instance(),
|
||||
new QEvent(QEvent::ApplicationDeactivate));
|
||||
QPlatformInputContext *inputContext = integration->inputContext();
|
||||
if (inputContext) {
|
||||
inputContext->hideInputPanel();
|
||||
} else {
|
||||
qWarning("QMirClientClientIntegration aboutToStopCallback(): no input context");
|
||||
}
|
||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
|
||||
}
|
||||
|
||||
QMirClientClientIntegration::QMirClientClientIntegration()
|
||||
@ -100,6 +107,8 @@ 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));
|
||||
|
||||
// Create default screen.
|
||||
mScreen = new QMirClientScreen(u_application_instance_get_mir_connection(mInstance));
|
||||
screenAdded(mScreen);
|
||||
@ -176,10 +185,8 @@ QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* wind
|
||||
|
||||
QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window)
|
||||
{
|
||||
QPlatformWindow* platformWindow = new QMirClientWindow(
|
||||
window, mClipboard, static_cast<QMirClientScreen*>(mScreen), mInput, u_application_instance_get_mir_connection(mInstance));
|
||||
platformWindow->requestActivateWindow();
|
||||
return platformWindow;
|
||||
return new QMirClientWindow(window, mClipboard, static_cast<QMirClientScreen*>(mScreen),
|
||||
mInput, u_application_instance_get_mir_connection(mInstance));
|
||||
}
|
||||
|
||||
bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const
|
||||
@ -187,11 +194,12 @@ bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability
|
||||
switch (cap) {
|
||||
case ThreadedPixmaps:
|
||||
return true;
|
||||
break;
|
||||
|
||||
case OpenGL:
|
||||
return true;
|
||||
break;
|
||||
|
||||
case ApplicationState:
|
||||
return true;
|
||||
|
||||
case ThreadedOpenGL:
|
||||
if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) {
|
||||
@ -200,8 +208,9 @@ bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability
|
||||
DLOG("ubuntumirclient: disabled threaded OpenGL");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case MultipleWindows:
|
||||
case NonFullScreenWindows:
|
||||
return true;
|
||||
default:
|
||||
return QPlatformIntegration::hasCapability(cap);
|
||||
}
|
||||
@ -262,3 +271,8 @@ QPlatformClipboard* QMirClientClientIntegration::clipboard() const
|
||||
{
|
||||
return mClipboard.data();
|
||||
}
|
||||
|
||||
QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const
|
||||
{
|
||||
return mNativeInterface;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
class QMirClientClipboard;
|
||||
class QMirClientInput;
|
||||
class QMirClientNativeInterface;
|
||||
class QMirClientScreen;
|
||||
|
||||
class QMirClientClientIntegration : public QPlatformIntegration {
|
||||
@ -59,7 +60,7 @@ public:
|
||||
// QPlatformIntegration methods.
|
||||
bool hasCapability(QPlatformIntegration::Capability cap) const override;
|
||||
QAbstractEventDispatcher *createEventDispatcher() const override;
|
||||
QPlatformNativeInterface* nativeInterface() const override { return mNativeInterface; }
|
||||
QPlatformNativeInterface* nativeInterface() const override;
|
||||
QPlatformBackingStore* createPlatformBackingStore(QWindow* window) const override;
|
||||
QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context) const override;
|
||||
QPlatformFontDatabase* fontDatabase() const override { return mFontDb; }
|
||||
@ -79,7 +80,7 @@ private:
|
||||
void setupOptions();
|
||||
void setupDescription();
|
||||
|
||||
QPlatformNativeInterface* mNativeInterface;
|
||||
QMirClientNativeInterface* mNativeInterface;
|
||||
QPlatformFontDatabase* mFontDb;
|
||||
|
||||
QMirClientPlatformServices* mServices;
|
||||
|
@ -35,17 +35,17 @@
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
// Local
|
||||
#include "qmirclientnativeinterface.h"
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclientglcontext.h"
|
||||
|
||||
// Qt
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
// Local
|
||||
#include "qmirclientnativeinterface.h"
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclientglcontext.h"
|
||||
|
||||
class QMirClientResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType>
|
||||
{
|
||||
public:
|
||||
@ -55,6 +55,7 @@ public:
|
||||
insert("eglcontext", QMirClientNativeInterface::EglContext);
|
||||
insert("nativeorientation", QMirClientNativeInterface::NativeOrientation);
|
||||
insert("display", QMirClientNativeInterface::Display);
|
||||
insert("mirconnection", QMirClientNativeInterface::MirConnection);
|
||||
}
|
||||
};
|
||||
|
||||
@ -63,6 +64,7 @@ Q_GLOBAL_STATIC(QMirClientResourceMap, ubuntuResourceMap)
|
||||
QMirClientNativeInterface::QMirClientNativeInterface()
|
||||
: mGenericEventFilterType(QByteArrayLiteral("Event"))
|
||||
, mNativeOrientation(nullptr)
|
||||
, mMirConnection(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -72,6 +74,23 @@ QMirClientNativeInterface::~QMirClientNativeInterface()
|
||||
mNativeOrientation = nullptr;
|
||||
}
|
||||
|
||||
void* QMirClientNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
|
||||
{
|
||||
const QByteArray lowerCaseResource = resourceString.toLower();
|
||||
|
||||
if (!ubuntuResourceMap()->contains(lowerCaseResource)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ResourceType resourceType = ubuntuResourceMap()->value(lowerCaseResource);
|
||||
|
||||
if (resourceType == QMirClientNativeInterface::MirConnection) {
|
||||
return mMirConnection;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void* QMirClientNativeInterface::nativeResourceForContext(
|
||||
const QByteArray& resourceString, QOpenGLContext* context)
|
||||
{
|
||||
|
@ -42,12 +42,13 @@
|
||||
|
||||
class QMirClientNativeInterface : public QPlatformNativeInterface {
|
||||
public:
|
||||
enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display };
|
||||
enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection };
|
||||
|
||||
QMirClientNativeInterface();
|
||||
~QMirClientNativeInterface();
|
||||
|
||||
// QPlatformNativeInterface methods.
|
||||
void* nativeResourceForIntegration(const QByteArray &resource) override;
|
||||
void* nativeResourceForContext(const QByteArray& resourceString,
|
||||
QOpenGLContext* context) override;
|
||||
void* nativeResourceForWindow(const QByteArray& resourceString,
|
||||
@ -57,10 +58,12 @@ public:
|
||||
|
||||
// New methods.
|
||||
const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; }
|
||||
void setMirConnection(void *mirConnection) { mMirConnection = mirConnection; }
|
||||
|
||||
private:
|
||||
const QByteArray mGenericEventFilterType;
|
||||
Qt::ScreenOrientation* mNativeOrientation;
|
||||
void *mMirConnection;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTNATIVEINTERFACE_H
|
||||
|
@ -43,15 +43,7 @@
|
||||
|
||||
class OrientationChangeEvent : public QEvent {
|
||||
public:
|
||||
enum Orientation {
|
||||
Undefined = 0,
|
||||
TopUp,
|
||||
TopDown,
|
||||
LeftUp,
|
||||
RightUp,
|
||||
FaceUp,
|
||||
FaceDown
|
||||
};
|
||||
enum Orientation { TopUp, LeftUp, TopDown, RightUp };
|
||||
|
||||
OrientationChangeEvent(QEvent::Type type, Orientation orientation)
|
||||
: QEvent(type)
|
||||
|
@ -41,14 +41,14 @@
|
||||
QStringList QMirClientIntegrationPlugin::keys() const
|
||||
{
|
||||
QStringList list;
|
||||
list << "mirclient";
|
||||
list << QStringLiteral("mirclient");
|
||||
return list;
|
||||
}
|
||||
|
||||
QPlatformIntegration* QMirClientIntegrationPlugin::create(const QString &system,
|
||||
const QStringList &)
|
||||
{
|
||||
if (system.toLower() == "mirclient") {
|
||||
if (system.toLower() == QLatin1String("mirclient")) {
|
||||
return new QMirClientClientIntegration;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 Canonical, Ltd.
|
||||
** Copyright (C) 2014-2015 Canonical, Ltd.
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -35,6 +35,11 @@
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
// local
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclientlogging.h"
|
||||
#include "qmirclientorientationchangeevent_p.h"
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
// Qt
|
||||
@ -45,12 +50,7 @@
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QtPlatformSupport/private/qeglconvenience_p.h>
|
||||
|
||||
// local
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclientlogging.h"
|
||||
#include "qmirclientorientationchangeevent_p.h"
|
||||
|
||||
#include "memory"
|
||||
#include <memory>
|
||||
|
||||
static const int kSwapInterval = 1;
|
||||
|
||||
@ -149,9 +149,11 @@ static const MirDisplayOutput *find_active_output(
|
||||
QMirClientScreen::QMirClientScreen(MirConnection *connection)
|
||||
: mFormat(QImage::Format_RGB32)
|
||||
, mDepth(32)
|
||||
, mOutputId(0)
|
||||
, mSurfaceFormat()
|
||||
, mEglDisplay(EGL_NO_DISPLAY)
|
||||
, mEglConfig(nullptr)
|
||||
, mCursor(connection)
|
||||
{
|
||||
// Initialize EGL.
|
||||
ASSERT(eglBindAPI(EGL_OPENGL_ES_API) == EGL_TRUE);
|
||||
@ -203,6 +205,11 @@ QMirClientScreen::QMirClientScreen(MirConnection *connection)
|
||||
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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 Canonical, Ltd.
|
||||
** Copyright (C) 2014-2015 Canonical, Ltd.
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -42,6 +42,8 @@
|
||||
#include <QSurfaceFormat>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include "qmirclientcursor.h"
|
||||
|
||||
struct MirConnection;
|
||||
|
||||
class QMirClientScreen : public QObject, public QPlatformScreen
|
||||
@ -56,8 +58,10 @@ public:
|
||||
int depth() const override { return mDepth; }
|
||||
QRect geometry() const override { return mGeometry; }
|
||||
QRect availableGeometry() const override { return mGeometry; }
|
||||
QSizeF physicalSize() const override { return mPhysicalSize; }
|
||||
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; }
|
||||
@ -65,20 +69,24 @@ public:
|
||||
EGLConfig eglConfig() const { return mEglConfig; }
|
||||
EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
|
||||
void handleWindowSurfaceResize(int width, int height);
|
||||
uint32_t mirOutputId() const { return mOutputId; }
|
||||
|
||||
// QObject methods.
|
||||
void customEvent(QEvent* event);
|
||||
void customEvent(QEvent* event) override;
|
||||
|
||||
private:
|
||||
QRect mGeometry;
|
||||
QSizeF mPhysicalSize;
|
||||
Qt::ScreenOrientation mNativeOrientation;
|
||||
Qt::ScreenOrientation mCurrentOrientation;
|
||||
QImage::Format mFormat;
|
||||
int mDepth;
|
||||
uint32_t mOutputId;
|
||||
QSurfaceFormat mSurfaceFormat;
|
||||
EGLDisplay mEglDisplay;
|
||||
EGLConfig mEglConfig;
|
||||
EGLNativeDisplayType mEglNativeDisplay;
|
||||
QMirClientCursor mCursor;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTSCREEN_H
|
||||
|
@ -36,16 +36,16 @@
|
||||
|
||||
|
||||
// Local
|
||||
#include "qmirclientwindow.h"
|
||||
#include "qmirclientclipboard.h"
|
||||
#include "qmirclientinput.h"
|
||||
#include "qmirclientwindow.h"
|
||||
#include "qmirclientscreen.h"
|
||||
#include "qmirclientlogging.h"
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
// Qt
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QSize>
|
||||
#include <QtMath>
|
||||
@ -55,25 +55,46 @@
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#define IS_OPAQUE_FLAG 1
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// FIXME: this used to be defined by platform-api, but it's been removed in v3. Change ubuntu-keyboard to use
|
||||
// a different enum for window roles.
|
||||
enum UAUiWindowRole {
|
||||
U_MAIN_ROLE = 1,
|
||||
U_DASH_ROLE,
|
||||
U_INDICATOR_ROLE,
|
||||
U_NOTIFICATIONS_ROLE,
|
||||
U_GREETER_ROLE,
|
||||
U_LAUNCHER_ROLE,
|
||||
U_ON_SCREEN_KEYBOARD_ROLE,
|
||||
U_SHUTDOWN_DIALOG_ROLE,
|
||||
};
|
||||
|
||||
struct MirSpecDeleter
|
||||
{
|
||||
void operator()(MirSurfaceSpec *spec) { mir_surface_spec_release(spec); }
|
||||
};
|
||||
|
||||
using Spec = std::unique_ptr<MirSurfaceSpec, MirSpecDeleter>;
|
||||
|
||||
EGLNativeWindowType nativeWindowFor(MirSurface *surf)
|
||||
{
|
||||
auto stream = mir_surface_get_buffer_stream(surf);
|
||||
return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream));
|
||||
}
|
||||
|
||||
MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
|
||||
{
|
||||
switch (state) {
|
||||
case Qt::WindowNoState:
|
||||
return mir_surface_state_restored;
|
||||
|
||||
case Qt::WindowFullScreen:
|
||||
return mir_surface_state_fullscreen;
|
||||
|
||||
case Qt::WindowMaximized:
|
||||
return mir_surface_state_maximized;
|
||||
|
||||
case Qt::WindowMinimized:
|
||||
return mir_surface_state_minimized;
|
||||
|
||||
default:
|
||||
LOG("Unexpected Qt::WindowState: %d", state);
|
||||
return mir_surface_state_restored;
|
||||
@ -86,117 +107,137 @@ const char *qtWindowStateToStr(Qt::WindowState state)
|
||||
switch (state) {
|
||||
case Qt::WindowNoState:
|
||||
return "NoState";
|
||||
|
||||
case Qt::WindowFullScreen:
|
||||
return "FullScreen";
|
||||
|
||||
case Qt::WindowMaximized:
|
||||
return "Maximized";
|
||||
|
||||
case Qt::WindowMinimized:
|
||||
return "Minimized";
|
||||
|
||||
default:
|
||||
return "!?";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class QMirClientWindowPrivate
|
||||
WId makeId()
|
||||
{
|
||||
public:
|
||||
void createEGLSurface(EGLNativeWindowType nativeWindow);
|
||||
void destroyEGLSurface();
|
||||
int panelHeight();
|
||||
|
||||
QMirClientScreen* screen;
|
||||
EGLSurface eglSurface;
|
||||
WId id;
|
||||
QMirClientInput* input;
|
||||
Qt::WindowState state;
|
||||
MirConnection *connection;
|
||||
MirSurface* surface;
|
||||
QSize bufferSize;
|
||||
QMutex mutex;
|
||||
QSharedPointer<QMirClientClipboard> clipboard;
|
||||
};
|
||||
|
||||
static void eventCallback(MirSurface* surface, const MirEvent *event, void* context)
|
||||
{
|
||||
(void) surface;
|
||||
DASSERT(context != NULL);
|
||||
QMirClientWindow* platformWindow = static_cast<QMirClientWindow*>(context);
|
||||
platformWindow->priv()->input->postEvent(platformWindow, event);
|
||||
}
|
||||
|
||||
static void surfaceCreateCallback(MirSurface* surface, void* context)
|
||||
{
|
||||
DASSERT(context != NULL);
|
||||
QMirClientWindow* platformWindow = static_cast<QMirClientWindow*>(context);
|
||||
platformWindow->priv()->surface = surface;
|
||||
|
||||
mir_surface_set_event_handler(surface, eventCallback, context);
|
||||
}
|
||||
|
||||
QMirClientWindow::QMirClientWindow(QWindow* w, QSharedPointer<QMirClientClipboard> clipboard, QMirClientScreen* screen,
|
||||
QMirClientInput* input, MirConnection* connection)
|
||||
: QObject(nullptr), QPlatformWindow(w)
|
||||
{
|
||||
DASSERT(screen != NULL);
|
||||
|
||||
d = new QMirClientWindowPrivate;
|
||||
d->screen = screen;
|
||||
d->eglSurface = EGL_NO_SURFACE;
|
||||
d->input = input;
|
||||
d->state = window()->windowState();
|
||||
d->connection = connection;
|
||||
d->clipboard = clipboard;
|
||||
|
||||
static int id = 1;
|
||||
d->id = id++;
|
||||
|
||||
// Use client geometry if set explicitly, use available screen geometry otherwise.
|
||||
QPlatformWindow::setGeometry(window()->geometry().isValid() && window()->geometry() != screen->geometry() ?
|
||||
window()->geometry() : screen->availableGeometry());
|
||||
createWindow();
|
||||
DLOG("QMirClientWindow::QMirClientWindow (this=%p, w=%p, screen=%p, input=%p)", this, w, screen, input);
|
||||
return id++;
|
||||
}
|
||||
|
||||
QMirClientWindow::~QMirClientWindow()
|
||||
MirPixelFormat defaultPixelFormatFor(MirConnection *connection)
|
||||
{
|
||||
DLOG("QMirClientWindow::~QMirClientWindow");
|
||||
d->destroyEGLSurface();
|
||||
|
||||
mir_surface_release_sync(d->surface);
|
||||
|
||||
delete d;
|
||||
MirPixelFormat format;
|
||||
unsigned int nformats;
|
||||
mir_connection_get_available_surface_formats(connection, &format, 1, &nformats);
|
||||
return format;
|
||||
}
|
||||
|
||||
void QMirClientWindowPrivate::createEGLSurface(EGLNativeWindowType nativeWindow)
|
||||
UAUiWindowRole roleFor(QWindow *window)
|
||||
{
|
||||
DLOG("QMirClientWindowPrivate::createEGLSurface (this=%p, nativeWindow=%p)",
|
||||
this, reinterpret_cast<void*>(nativeWindow));
|
||||
QVariant roleVariant = window->property("role");
|
||||
if (!roleVariant.isValid())
|
||||
return U_MAIN_ROLE;
|
||||
|
||||
eglSurface = eglCreateWindowSurface(screen->eglDisplay(), screen->eglConfig(),
|
||||
nativeWindow, nullptr);
|
||||
uint role = roleVariant.toUInt();
|
||||
if (role < U_MAIN_ROLE || role > U_SHUTDOWN_DIALOG_ROLE)
|
||||
return U_MAIN_ROLE;
|
||||
|
||||
DASSERT(eglSurface != EGL_NO_SURFACE);
|
||||
return static_cast<UAUiWindowRole>(role);
|
||||
}
|
||||
|
||||
void QMirClientWindowPrivate::destroyEGLSurface()
|
||||
QMirClientWindow *transientParentFor(QWindow *window)
|
||||
{
|
||||
DLOG("QMirClientWindowPrivate::destroyEGLSurface (this=%p)", this);
|
||||
if (eglSurface != EGL_NO_SURFACE) {
|
||||
eglDestroySurface(screen->eglDisplay(), eglSurface);
|
||||
eglSurface = EGL_NO_SURFACE;
|
||||
QWindow *parent = window->transientParent();
|
||||
return parent ? static_cast<QMirClientWindow *>(parent->handle()) : nullptr;
|
||||
}
|
||||
|
||||
Spec makeSurfaceSpec(QWindow *window, QMirClientInput *input, MirConnection *connection)
|
||||
{
|
||||
const auto geom = window->geometry();
|
||||
const int width = geom.width() > 0 ? geom.width() : 1;
|
||||
const int height = geom.height() > 0 ? geom.height() : 1;
|
||||
const auto pixelFormat = defaultPixelFormatFor(connection);
|
||||
|
||||
if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
|
||||
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);
|
||||
return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
|
||||
}
|
||||
|
||||
const Qt::WindowType type = window->type();
|
||||
if (type == Qt::Popup) {
|
||||
auto parent = transientParentFor(window);
|
||||
if (parent == nullptr) {
|
||||
//NOTE: We cannot have a parentless popup -
|
||||
//try using the last surface to receive input as that will most likely be
|
||||
//the one that caused this popup to be created
|
||||
parent = input->lastFocusedWindow();
|
||||
}
|
||||
if (parent) {
|
||||
auto pos = geom.topLeft();
|
||||
pos -= parent->geometry().topLeft();
|
||||
MirRectangle location{pos.x(), pos.y(), 0, 0};
|
||||
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);
|
||||
return Spec{mir_connection_create_spec_for_menu(
|
||||
connection, width, height, pixelFormat, parent->mirSurface(),
|
||||
&location, mir_edge_attachment_any)};
|
||||
} else {
|
||||
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
|
||||
}
|
||||
} else if (type == Qt::Dialog) {
|
||||
auto parent = transientParentFor(window);
|
||||
if (parent) {
|
||||
// Modal dialog
|
||||
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);
|
||||
return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};
|
||||
} else {
|
||||
// TODO: do Qt parentless dialogs have the same semantics as mir?
|
||||
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);
|
||||
return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
|
||||
}
|
||||
}
|
||||
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);
|
||||
return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
|
||||
}
|
||||
|
||||
void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)
|
||||
{
|
||||
mir_surface_spec_set_min_width(spec, minSize.width());
|
||||
mir_surface_spec_set_min_height(spec, minSize.height());
|
||||
if (maxSize.width() >= minSize.width()) {
|
||||
mir_surface_spec_set_max_width(spec, maxSize.width());
|
||||
}
|
||||
if (maxSize.height() >= minSize.height()) {
|
||||
mir_surface_spec_set_max_height(spec, maxSize.height());
|
||||
}
|
||||
if (increment.width() > 0) {
|
||||
mir_surface_spec_set_width_increment(spec, increment.width());
|
||||
}
|
||||
if (increment.height() > 0) {
|
||||
mir_surface_spec_set_height_increment(spec, increment.height());
|
||||
}
|
||||
}
|
||||
|
||||
MirSurface *createMirSurface(QWindow *window, QMirClientScreen *screen, QMirClientInput *input, MirConnection *connection)
|
||||
{
|
||||
auto spec = makeSurfaceSpec(window, input, connection);
|
||||
const auto title = window->title().toUtf8();
|
||||
mir_surface_spec_set_name(spec.get(), title.constData());
|
||||
|
||||
setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement());
|
||||
|
||||
if (window->windowState() == Qt::WindowFullScreen) {
|
||||
mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());
|
||||
}
|
||||
|
||||
auto surface = mir_surface_create_sync(spec.get());
|
||||
Q_ASSERT(mir_surface_is_valid(surface));
|
||||
return surface;
|
||||
}
|
||||
|
||||
// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
|
||||
// we need to guess the panel height (3GU + 2DP)
|
||||
int QMirClientWindowPrivate::panelHeight()
|
||||
// we need to guess the panel height (3GU)
|
||||
int panelHeight()
|
||||
{
|
||||
if (qEnvironmentVariableIsSet("QT_MIRCLIENT_IGNORE_PANEL"))
|
||||
return 0;
|
||||
@ -210,245 +251,412 @@ int QMirClientWindowPrivate::panelHeight()
|
||||
gridUnit = defaultGridUnit;
|
||||
}
|
||||
}
|
||||
qreal densityPixelRatio = static_cast<qreal>(gridUnit) / defaultGridUnit;
|
||||
return gridUnit * 3 + qFloor(densityPixelRatio) * 2;
|
||||
return gridUnit * 3;
|
||||
}
|
||||
|
||||
namespace
|
||||
} //namespace
|
||||
|
||||
class QMirClientSurface
|
||||
{
|
||||
static MirPixelFormat
|
||||
mir_choose_default_pixel_format(MirConnection *connection)
|
||||
{
|
||||
MirPixelFormat format[mir_pixel_formats];
|
||||
unsigned int nformats;
|
||||
public:
|
||||
QMirClientSurface(QMirClientWindow *platformWindow, QMirClientScreen *screen, QMirClientInput *input, MirConnection *connection)
|
||||
: mWindow(platformWindow->window())
|
||||
, mPlatformWindow(platformWindow)
|
||||
, mInput(input)
|
||||
, mConnection(connection)
|
||||
, mMirSurface(createMirSurface(mWindow, screen, input, connection))
|
||||
, mEglDisplay(screen->eglDisplay())
|
||||
, mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr))
|
||||
, mVisible(false)
|
||||
, mNeedsRepaint(false)
|
||||
, mParented(mWindow->transientParent() || mWindow->parent())
|
||||
, mWindowState(mWindow->windowState())
|
||||
|
||||
mir_connection_get_available_surface_formats(connection,
|
||||
format, mir_pixel_formats, &nformats);
|
||||
|
||||
return format[0];
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientWindow::createWindow()
|
||||
{
|
||||
DLOG("QMirClientWindow::createWindow (this=%p)", this);
|
||||
|
||||
// FIXME: remove this remnant of an old platform-api enum - needs ubuntu-keyboard update
|
||||
const int SCREEN_KEYBOARD_ROLE = 7;
|
||||
// Get surface role and flags.
|
||||
QVariant roleVariant = window()->property("role");
|
||||
int role = roleVariant.isValid() ? roleVariant.toUInt() : 1; // 1 is the default role for apps.
|
||||
QVariant opaqueVariant = window()->property("opaque");
|
||||
uint flags = opaqueVariant.isValid() ?
|
||||
opaqueVariant.toUInt() ? static_cast<uint>(IS_OPAQUE_FLAG) : 0 : 0;
|
||||
|
||||
// FIXME(loicm) Opaque flag is forced for now for non-system sessions (applications) for
|
||||
// performance reasons.
|
||||
flags |= static_cast<uint>(IS_OPAQUE_FLAG);
|
||||
|
||||
const QByteArray title = (!window()->title().isNull()) ? window()->title().toUtf8() : "Window 1"; // legacy title
|
||||
const int panelHeight = d->panelHeight();
|
||||
|
||||
#if !defined(QT_NO_DEBUG)
|
||||
LOG("panelHeight: '%d'", panelHeight);
|
||||
LOG("role: '%d'", role);
|
||||
LOG("flags: '%s'", (flags & static_cast<uint>(1)) ? "Opaque" : "NotOpaque");
|
||||
LOG("title: '%s'", title.constData());
|
||||
#endif
|
||||
|
||||
// Get surface geometry.
|
||||
QRect geometry;
|
||||
if (d->state == Qt::WindowFullScreen) {
|
||||
printf("QMirClientWindow - fullscreen geometry\n");
|
||||
geometry = screen()->geometry();
|
||||
} else if (d->state == Qt::WindowMaximized) {
|
||||
printf("QMirClientWindow - maximized geometry\n");
|
||||
geometry = screen()->availableGeometry();
|
||||
/*
|
||||
* FIXME: Autopilot relies on being able to convert coordinates relative of the window
|
||||
* into absolute screen coordinates. Mir does not allow this, see bug lp:1346633
|
||||
* Until there's a correct way to perform this transformation agreed, this horrible hack
|
||||
* guesses the transformation heuristically.
|
||||
*
|
||||
* Assumption: this method only used on phone devices!
|
||||
*/
|
||||
geometry.setY(panelHeight);
|
||||
} else {
|
||||
printf("QMirClientWindow - regular geometry\n");
|
||||
geometry = this->geometry();
|
||||
geometry.setY(panelHeight);
|
||||
}
|
||||
|
||||
DLOG("[ubuntumirclient QPA] creating surface at (%d, %d) with size (%d, %d) with title '%s'\n",
|
||||
geometry.x(), geometry.y(), geometry.width(), geometry.height(), title.data());
|
||||
|
||||
MirSurfaceSpec *spec;
|
||||
if (role == SCREEN_KEYBOARD_ROLE)
|
||||
{
|
||||
spec = mir_connection_create_spec_for_input_method(d->connection, geometry.width(),
|
||||
geometry.height(), mir_choose_default_pixel_format(d->connection));
|
||||
}
|
||||
else
|
||||
{
|
||||
spec = mir_connection_create_spec_for_normal_surface(d->connection, geometry.width(),
|
||||
geometry.height(), mir_choose_default_pixel_format(d->connection));
|
||||
}
|
||||
mir_surface_spec_set_name(spec, title.data());
|
||||
|
||||
// Create platform window
|
||||
mir_wait_for(mir_surface_create(spec, surfaceCreateCallback, this));
|
||||
mir_surface_spec_release(spec);
|
||||
|
||||
DASSERT(d->surface != NULL);
|
||||
d->createEGLSurface((EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(d->surface)));
|
||||
|
||||
if (d->state == Qt::WindowFullScreen) {
|
||||
// TODO: We could set this on creation once surface spec supports it (mps already up)
|
||||
mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_fullscreen));
|
||||
}
|
||||
mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this);
|
||||
|
||||
// Window manager can give us a final size different from what we asked for
|
||||
// so let's check what we ended up getting
|
||||
{
|
||||
MirSurfaceParameters parameters;
|
||||
mir_surface_get_parameters(d->surface, ¶meters);
|
||||
mir_surface_get_parameters(mMirSurface, ¶meters);
|
||||
|
||||
geometry.setWidth(parameters.width);
|
||||
geometry.setHeight(parameters.height);
|
||||
auto geom = mWindow->geometry();
|
||||
geom.setWidth(parameters.width);
|
||||
geom.setHeight(parameters.height);
|
||||
if (mWindowState == Qt::WindowFullScreen) {
|
||||
geom.setY(0);
|
||||
} else {
|
||||
geom.setY(panelHeight());
|
||||
}
|
||||
|
||||
DLOG("[ubuntumirclient QPA] created surface has size (%d, %d)",
|
||||
geometry.width(), geometry.height());
|
||||
|
||||
// Assume that the buffer size matches the surface size at creation time
|
||||
d->bufferSize = geometry.size();
|
||||
mBufferSize = geom.size();
|
||||
platformWindow->QPlatformWindow::setGeometry(geom);
|
||||
QWindowSystemInterface::handleGeometryChange(mWindow, geom);
|
||||
|
||||
// Tell Qt about the geometry.
|
||||
QWindowSystemInterface::handleGeometryChange(window(), geometry);
|
||||
QPlatformWindow::setGeometry(geometry);
|
||||
DLOG("[ubuntumirclient QPA] created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n",
|
||||
geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow));
|
||||
}
|
||||
|
||||
~QMirClientSurface()
|
||||
{
|
||||
if (mEglSurface != EGL_NO_SURFACE)
|
||||
eglDestroySurface(mEglDisplay, mEglSurface);
|
||||
if (mMirSurface)
|
||||
mir_surface_release_sync(mMirSurface);
|
||||
}
|
||||
|
||||
QMirClientSurface(QMirClientSurface const&) = delete;
|
||||
QMirClientSurface& operator=(QMirClientSurface const&) = delete;
|
||||
|
||||
void resize(const QSize& newSize);
|
||||
void setState(Qt::WindowState newState);
|
||||
void setVisible(bool state);
|
||||
void updateTitle(const QString& title);
|
||||
void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
|
||||
|
||||
void onSwapBuffersDone();
|
||||
void handleSurfaceResized(int width, int height);
|
||||
int needsRepaint() const;
|
||||
|
||||
EGLSurface eglSurface() const { return mEglSurface; }
|
||||
MirSurface *mirSurface() const { return mMirSurface; }
|
||||
|
||||
private:
|
||||
static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context);
|
||||
void postEvent(const MirEvent *event);
|
||||
void updateSurface();
|
||||
|
||||
QWindow * const mWindow;
|
||||
QMirClientWindow * const mPlatformWindow;
|
||||
QMirClientInput * const mInput;
|
||||
MirConnection * const mConnection;
|
||||
|
||||
MirSurface * const mMirSurface;
|
||||
const EGLDisplay mEglDisplay;
|
||||
const EGLSurface mEglSurface;
|
||||
|
||||
bool mVisible;
|
||||
bool mNeedsRepaint;
|
||||
bool mParented;
|
||||
Qt::WindowState mWindowState;
|
||||
QSize mBufferSize;
|
||||
|
||||
QMutex mTargetSizeMutex;
|
||||
QSize mTargetSize;
|
||||
};
|
||||
|
||||
void QMirClientSurface::resize(const QSize& size)
|
||||
{
|
||||
DLOG("[ubuntumirclient QPA] resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
|
||||
|
||||
if (mWindowState == Qt::WindowFullScreen || mWindowState == Qt::WindowMaximized) {
|
||||
DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size.isEmpty()) {
|
||||
DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, size is empty", mWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
|
||||
mir_surface_spec_set_width(spec.get(), size.width());
|
||||
mir_surface_spec_set_height(spec.get(), size.height());
|
||||
mir_surface_apply_spec(mMirSurface, spec.get());
|
||||
}
|
||||
|
||||
void QMirClientWindow::moveResize(const QRect& rect)
|
||||
void QMirClientSurface::setState(Qt::WindowState newState)
|
||||
{
|
||||
(void) rect;
|
||||
// TODO: Not yet supported by mir.
|
||||
mir_wait_for(mir_surface_set_state(mMirSurface, qtWindowStateToMirSurfaceState(newState)));
|
||||
mWindowState = newState;
|
||||
}
|
||||
|
||||
void QMirClientWindow::handleSurfaceResize(int width, int height)
|
||||
void QMirClientSurface::setVisible(bool visible)
|
||||
{
|
||||
QMutexLocker(&d->mutex);
|
||||
LOG("QMirClientWindow::handleSurfaceResize(width=%d, height=%d)", width, height);
|
||||
if (mVisible == visible)
|
||||
return;
|
||||
|
||||
// The current buffer size hasn't actually changed. so just render on it and swap
|
||||
// buffers in the hope that the next buffer will match the surface size advertised
|
||||
// in this event.
|
||||
// But since this event is processed by a thread different from the one that swaps
|
||||
// buffers, you can never know if this information is already outdated as there's
|
||||
// no synchronicity whatsoever between the processing of resize events and the
|
||||
// consumption of buffers.
|
||||
if (d->bufferSize.width() != width || d->bufferSize.height() != height) {
|
||||
QWindowSystemInterface::handleExposeEvent(window(), geometry());
|
||||
QWindowSystemInterface::flushWindowSystemEvents();
|
||||
mVisible = visible;
|
||||
|
||||
if (mVisible)
|
||||
updateSurface();
|
||||
|
||||
// TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
|
||||
// Will have to change qtmir and unity8 for that.
|
||||
const auto newState = visible ? qtWindowStateToMirSurfaceState(mWindowState) : mir_surface_state_minimized;
|
||||
mir_wait_for(mir_surface_set_state(mMirSurface, newState));
|
||||
}
|
||||
|
||||
void QMirClientSurface::updateTitle(const QString& newTitle)
|
||||
{
|
||||
const auto title = newTitle.toUtf8();
|
||||
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
|
||||
mir_surface_spec_set_name(spec.get(), title.constData());
|
||||
mir_surface_apply_spec(mMirSurface, spec.get());
|
||||
}
|
||||
|
||||
void QMirClientSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment)
|
||||
{
|
||||
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
|
||||
::setSizingConstraints(spec.get(), minSize, maxSize, increment);
|
||||
mir_surface_apply_spec(mMirSurface, spec.get());
|
||||
}
|
||||
|
||||
void QMirClientSurface::handleSurfaceResized(int width, int height)
|
||||
{
|
||||
QMutexLocker lock(&mTargetSizeMutex);
|
||||
|
||||
// mir's resize event is mainly a signal that we need to redraw our content. We use the
|
||||
// width/height as identifiers to figure out if this is the latest surface resize event
|
||||
// that has posted, discarding any old ones. This avoids issuing too many redraw events.
|
||||
// see TODO in postEvent as the ideal way we should handle this.
|
||||
// The actual buffer size may or may have not changed at this point, so let the rendering
|
||||
// thread drive the window geometry updates.
|
||||
mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height;
|
||||
}
|
||||
|
||||
int QMirClientSurface::needsRepaint() const
|
||||
{
|
||||
if (mNeedsRepaint) {
|
||||
if (mTargetSize != mBufferSize) {
|
||||
//If the buffer hasn't changed yet, we need at least two redraws,
|
||||
//once to get the new buffer size and propagate the geometry changes
|
||||
//and the second to redraw the content at the new size
|
||||
return 2;
|
||||
} else {
|
||||
// The buffer size has already been updated so we only need one redraw
|
||||
// to render at the new size
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QMirClientSurface::onSwapBuffersDone()
|
||||
{
|
||||
#if !defined(QT_NO_DEBUG)
|
||||
static int sFrameNumber = 0;
|
||||
++sFrameNumber;
|
||||
#endif
|
||||
|
||||
EGLint eglSurfaceWidth = -1;
|
||||
EGLint eglSurfaceHeight = -1;
|
||||
eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth);
|
||||
eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight);
|
||||
|
||||
const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0;
|
||||
|
||||
if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {
|
||||
|
||||
DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
|
||||
mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);
|
||||
|
||||
mBufferSize.rwidth() = eglSurfaceWidth;
|
||||
mBufferSize.rheight() = eglSurfaceHeight;
|
||||
|
||||
QRect newGeometry = mPlatformWindow->geometry();
|
||||
newGeometry.setSize(mBufferSize);
|
||||
|
||||
mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
|
||||
QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
|
||||
} else {
|
||||
#if 0
|
||||
DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
|
||||
mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientWindow::handleSurfaceFocusChange(bool focused)
|
||||
void QMirClientSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context)
|
||||
{
|
||||
LOG("QMirClientWindow::handleSurfaceFocusChange(focused=%s)", focused ? "true" : "false");
|
||||
QWindow *activatedWindow = focused ? window() : nullptr;
|
||||
Q_UNUSED(surface);
|
||||
Q_ASSERT(context != nullptr);
|
||||
|
||||
// System clipboard contents might have changed while this window was unfocused and wihtout
|
||||
auto s = static_cast<QMirClientSurface *>(context);
|
||||
s->postEvent(event);
|
||||
}
|
||||
|
||||
void QMirClientSurface::postEvent(const MirEvent *event)
|
||||
{
|
||||
if (mir_event_type_resize == mir_event_get_type(event)) {
|
||||
// TODO: The current event queue just accumulates all resize events;
|
||||
// It would be nicer if we could update just one event if that event has not been dispatched.
|
||||
// As a workaround, we use the width/height as an identifier of this latest event
|
||||
// so the event handler (handleSurfaceResized) can discard/ignore old ones.
|
||||
const auto resizeEvent = mir_event_get_resize_event(event);
|
||||
const auto width = mir_resize_event_get_width(resizeEvent);
|
||||
const auto height = mir_resize_event_get_height(resizeEvent);
|
||||
DLOG("[ubuntumirclient QPA] resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);
|
||||
|
||||
QMutexLocker lock(&mTargetSizeMutex);
|
||||
mTargetSize.rwidth() = width;
|
||||
mTargetSize.rheight() = height;
|
||||
}
|
||||
|
||||
mInput->postEvent(mPlatformWindow, event);
|
||||
}
|
||||
|
||||
void QMirClientSurface::updateSurface()
|
||||
{
|
||||
DLOG("[ubuntumirclient QPA] updateSurface(window=%p)", mWindow);
|
||||
|
||||
if (!mParented && mWindow->type() == Qt::Dialog) {
|
||||
// The dialog may have been parented after creation time
|
||||
// so morph it into a modal dialog
|
||||
auto parent = transientParentFor(mWindow);
|
||||
if (parent) {
|
||||
DLOG("[ubuntumirclient QPA] updateSurface(window=%p) dialog now parented", mWindow);
|
||||
mParented = true;
|
||||
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
|
||||
mir_surface_spec_set_parent(spec.get(), parent->mirSurface());
|
||||
mir_surface_apply_spec(mMirSurface, spec.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMirClientWindow::QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen,
|
||||
QMirClientInput *input, MirConnection *connection)
|
||||
: QObject(nullptr)
|
||||
, QPlatformWindow(w)
|
||||
, mId(makeId())
|
||||
, mClipboard(clipboard)
|
||||
, mSurface(new QMirClientSurface{this, screen, input, connection})
|
||||
{
|
||||
DLOG("[ubuntumirclient QPA] QMirClientWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());
|
||||
}
|
||||
|
||||
QMirClientWindow::~QMirClientWindow()
|
||||
{
|
||||
DLOG("[ubuntumirclient QPA] ~QMirClientWindow(window=%p)", this);
|
||||
}
|
||||
|
||||
void QMirClientWindow::handleSurfaceResized(int width, int height)
|
||||
{
|
||||
QMutexLocker lock(&mMutex);
|
||||
DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height);
|
||||
|
||||
mSurface->handleSurfaceResized(width, height);
|
||||
|
||||
// This resize event could have occurred just after the last buffer swap for this window.
|
||||
// This means the client may still be holding a buffer with the older size. The first redraw call
|
||||
// will then render at the old size. After swapping the client now will get a new buffer with the
|
||||
// updated size but it still needs re-rendering so another redraw may be needed.
|
||||
// A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice
|
||||
auto const numRepaints = mSurface->needsRepaint();
|
||||
DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
|
||||
for (int i = 0; i < numRepaints; i++) {
|
||||
DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());
|
||||
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientWindow::handleSurfaceFocused()
|
||||
{
|
||||
DLOG("[ubuntumirclient QPA] handleSurfaceFocused(window=%p)", window());
|
||||
|
||||
// System clipboard contents might have changed while this window was unfocused and without
|
||||
// this process getting notified about it because it might have been suspended (due to
|
||||
// application lifecycle policies), thus unable to listen to any changes notified through
|
||||
// D-Bus.
|
||||
// Therefore let's ensure we are up to date with the system clipboard now that we are getting
|
||||
// focused again.
|
||||
if (focused) {
|
||||
d->clipboard->requestDBusClipboardContents();
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleWindowActivated(activatedWindow, Qt::ActiveWindowFocusReason);
|
||||
mClipboard->requestDBusClipboardContents();
|
||||
}
|
||||
|
||||
void QMirClientWindow::setWindowState(Qt::WindowState state)
|
||||
{
|
||||
QMutexLocker(&d->mutex);
|
||||
DLOG("QMirClientWindow::setWindowState (this=%p, %s)", this, qtWindowStateToStr(state));
|
||||
QMutexLocker lock(&mMutex);
|
||||
DLOG("[ubuntumirclient QPA] setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
|
||||
mSurface->setState(state);
|
||||
|
||||
if (state == d->state)
|
||||
return;
|
||||
updatePanelHeightHack(state);
|
||||
}
|
||||
|
||||
// TODO: Perhaps we should check if the states are applied?
|
||||
mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(state)));
|
||||
d->state = state;
|
||||
/*
|
||||
FIXME: Mir does not let clients know the position of their windows in the virtual
|
||||
desktop space. So we have this ugly hack that assumes a phone situation where the
|
||||
window is always on the top-left corner, right below the indicators panel if not
|
||||
in fullscreen.
|
||||
*/
|
||||
void QMirClientWindow::updatePanelHeightHack(Qt::WindowState state)
|
||||
{
|
||||
if (state == Qt::WindowFullScreen && geometry().y() != 0) {
|
||||
QRect newGeometry = geometry();
|
||||
newGeometry.setY(0);
|
||||
QPlatformWindow::setGeometry(newGeometry);
|
||||
QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
|
||||
} else if (geometry().y() == 0) {
|
||||
QRect newGeometry = geometry();
|
||||
newGeometry.setY(panelHeight());
|
||||
QPlatformWindow::setGeometry(newGeometry);
|
||||
QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientWindow::setGeometry(const QRect& rect)
|
||||
{
|
||||
DLOG("QMirClientWindow::setGeometry (this=%p)", this);
|
||||
QMutexLocker lock(&mMutex);
|
||||
DLOG("[ubuntumirclient QPA] setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)",
|
||||
window(), rect.x(), rect.y(), rect.width(), rect.height());
|
||||
|
||||
bool doMoveResize;
|
||||
//NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates
|
||||
const auto newSize = rect.size();
|
||||
auto newGeometry = geometry();
|
||||
newGeometry.setSize(newSize);
|
||||
QPlatformWindow::setGeometry(newGeometry);
|
||||
|
||||
{
|
||||
QMutexLocker(&d->mutex);
|
||||
QPlatformWindow::setGeometry(rect);
|
||||
doMoveResize = d->state != Qt::WindowFullScreen && d->state != Qt::WindowMaximized;
|
||||
}
|
||||
|
||||
if (doMoveResize) {
|
||||
moveResize(rect);
|
||||
}
|
||||
mSurface->resize(newSize);
|
||||
}
|
||||
|
||||
void QMirClientWindow::setVisible(bool visible)
|
||||
{
|
||||
QMutexLocker(&d->mutex);
|
||||
DLOG("QMirClientWindow::setVisible (this=%p, visible=%s)", this, visible ? "true" : "false");
|
||||
QMutexLocker lock(&mMutex);
|
||||
DLOG("[ubuntumirclient QPA] setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false");
|
||||
|
||||
if (visible) {
|
||||
mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(d->state)));
|
||||
mSurface->setVisible(visible);
|
||||
const QRect& exposeRect = visible ? QRect(QPoint(), geometry().size()) : QRect();
|
||||
|
||||
QWindowSystemInterface::handleExposeEvent(window(), QRect());
|
||||
lock.unlock();
|
||||
QWindowSystemInterface::handleExposeEvent(window(), exposeRect);
|
||||
QWindowSystemInterface::flushWindowSystemEvents();
|
||||
} else {
|
||||
// TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
|
||||
// Will have to change qtmir and unity8 for that.
|
||||
mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_minimized));
|
||||
}
|
||||
}
|
||||
|
||||
void QMirClientWindow::setWindowTitle(const QString& title)
|
||||
{
|
||||
QMutexLocker lock(&mMutex);
|
||||
DLOG("[ubuntumirclient QPA] setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
|
||||
mSurface->updateTitle(title);
|
||||
}
|
||||
|
||||
void QMirClientWindow::propagateSizeHints()
|
||||
{
|
||||
QMutexLocker lock(&mMutex);
|
||||
const auto win = window();
|
||||
DLOG("[ubuntumirclient QPA] propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",
|
||||
win, win->minimumSize().width(), win->minimumSize().height(),
|
||||
win->maximumSize().width(), win->maximumSize().height(),
|
||||
win->sizeIncrement().width(), win->sizeIncrement().height());
|
||||
mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement());
|
||||
}
|
||||
|
||||
void* QMirClientWindow::eglSurface() const
|
||||
{
|
||||
return d->eglSurface;
|
||||
return mSurface->eglSurface();
|
||||
}
|
||||
|
||||
MirSurface *QMirClientWindow::mirSurface() const
|
||||
{
|
||||
return mSurface->mirSurface();
|
||||
}
|
||||
|
||||
WId QMirClientWindow::winId() const
|
||||
{
|
||||
return d->id;
|
||||
return mId;
|
||||
}
|
||||
|
||||
void QMirClientWindow::onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight)
|
||||
void QMirClientWindow::onSwapBuffersDone()
|
||||
{
|
||||
QMutexLocker(&d->mutex);
|
||||
|
||||
bool sizeKnown = newBufferWidth > 0 && newBufferHeight > 0;
|
||||
|
||||
if (sizeKnown && (d->bufferSize.width() != newBufferWidth ||
|
||||
d->bufferSize.height() != newBufferHeight)) {
|
||||
|
||||
DLOG("QMirClientWindow::onBuffersSwapped_threadSafe - buffer size changed from (%d,%d) to (%d,%d)",
|
||||
d->bufferSize.width(), d->bufferSize.height(), newBufferWidth, newBufferHeight);
|
||||
|
||||
d->bufferSize.rwidth() = newBufferWidth;
|
||||
d->bufferSize.rheight() = newBufferHeight;
|
||||
|
||||
QRect newGeometry;
|
||||
|
||||
newGeometry = geometry();
|
||||
newGeometry.setWidth(d->bufferSize.width());
|
||||
newGeometry.setHeight(d->bufferSize.height());
|
||||
|
||||
QPlatformWindow::setGeometry(newGeometry);
|
||||
QWindowSystemInterface::handleGeometryChange(window(), newGeometry, QRect());
|
||||
}
|
||||
QMutexLocker lock(&mMutex);
|
||||
mSurface->onSwapBuffersDone();
|
||||
}
|
||||
|
@ -40,20 +40,23 @@
|
||||
|
||||
#include <qpa/qplatformwindow.h>
|
||||
#include <QSharedPointer>
|
||||
#include <QMutex>
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
#include <memory>
|
||||
|
||||
class QMirClientClipboard;
|
||||
class QMirClientInput;
|
||||
class QMirClientScreen;
|
||||
class QMirClientWindowPrivate;
|
||||
class QMirClientSurface;
|
||||
struct MirConnection;
|
||||
struct MirSurface;
|
||||
|
||||
class QMirClientWindow : public QObject, public QPlatformWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QMirClientWindow(QWindow *w, QSharedPointer<QMirClientClipboard> clipboard, QMirClientScreen *screen,
|
||||
QMirClientInput *input, MirConnection *mir_connection);
|
||||
QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen,
|
||||
QMirClientInput *input, MirConnection *mirConnection);
|
||||
virtual ~QMirClientWindow();
|
||||
|
||||
// QPlatformWindow methods.
|
||||
@ -61,20 +64,22 @@ public:
|
||||
void setGeometry(const QRect&) override;
|
||||
void setWindowState(Qt::WindowState state) override;
|
||||
void setVisible(bool visible) override;
|
||||
void setWindowTitle(const QString &title) override;
|
||||
void propagateSizeHints() override;
|
||||
|
||||
// New methods.
|
||||
void* eglSurface() const;
|
||||
void handleSurfaceResize(int width, int height);
|
||||
void handleSurfaceFocusChange(bool focused);
|
||||
void onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight);
|
||||
|
||||
QMirClientWindowPrivate* priv() { return d; }
|
||||
void *eglSurface() const;
|
||||
MirSurface *mirSurface() const;
|
||||
void handleSurfaceResized(int width, int height);
|
||||
void handleSurfaceFocused();
|
||||
void onSwapBuffersDone();
|
||||
|
||||
private:
|
||||
void createWindow();
|
||||
void moveResize(const QRect& rect);
|
||||
|
||||
QMirClientWindowPrivate *d;
|
||||
void updatePanelHeightHack(Qt::WindowState);
|
||||
mutable QMutex mMutex;
|
||||
const WId mId;
|
||||
const QSharedPointer<QMirClientClipboard> mClipboard;
|
||||
std::unique_ptr<QMirClientSurface> mSurface;
|
||||
};
|
||||
|
||||
#endif // QMIRCLIENTWINDOW_H
|
||||
|
Loading…
Reference in New Issue
Block a user