Merge lp:~unity-team/qtubuntu/screen-info into lp:qtubuntu

Proposed by Michał Sawicz
Status: Work in progress
Proposed branch: lp:~unity-team/qtubuntu/screen-info
Merge into: lp:qtubuntu
Prerequisite: lp:~nick-dedekind/qtubuntu/shell_chrome
Diff against target: 1696 lines (+777/-270)
15 files modified
src/ubuntumirclient/backingstore.cpp (+11/-5)
src/ubuntumirclient/input.cpp (+101/-53)
src/ubuntumirclient/input.h (+2/-0)
src/ubuntumirclient/integration.cpp (+51/-14)
src/ubuntumirclient/integration.h (+12/-3)
src/ubuntumirclient/nativeinterface.cpp (+55/-3)
src/ubuntumirclient/nativeinterface.h (+11/-1)
src/ubuntumirclient/screen.cpp (+100/-62)
src/ubuntumirclient/screen.h (+26/-4)
src/ubuntumirclient/screenobserver.cpp (+131/-0)
src/ubuntumirclient/screenobserver.h (+54/-0)
src/ubuntumirclient/ubuntumirclient.pro (+4/-1)
src/ubuntumirclient/utils.h (+29/-0)
src/ubuntumirclient/window.cpp (+172/-118)
src/ubuntumirclient/window.h (+18/-6)
To merge this branch: bzr merge lp:~unity-team/qtubuntu/screen-info
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Approve
Ubuntu Phablet Team Pending
Review via email: mp+286329@code.launchpad.net

This proposal supersedes a proposal from 2016-02-03.

Commit message

Dynamic scaling support

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:329
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/37/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/1381
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1350
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1350
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/1350
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/1350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/1350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/1350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/1350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/1350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/1350/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)

Unmerged revisions

329. By Michał Sawicz

Merge trunk

328. By Nick Dedekind

remerge

327. By Nick Dedekind

merged with parent

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/ubuntumirclient/backingstore.cpp'
--- src/ubuntumirclient/backingstore.cpp 2014-12-04 12:29:39 +0000
+++ src/ubuntumirclient/backingstore.cpp 2016-04-20 15:51:01 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2014 Canonical, Ltd.2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -43,8 +43,10 @@
43{43{
44 Q_UNUSED(region);44 Q_UNUSED(region);
45 Q_UNUSED(offset);45 Q_UNUSED(offset);
46 const int dpr = int(window->devicePixelRatio());
47
46 mContext->makeCurrent(window);48 mContext->makeCurrent(window);
47 glViewport(0, 0, window->width(), window->height());49 glViewport(0, 0, window->width() * dpr, window->height() * dpr);
4850
49 updateTexture();51 updateTexture();
5052
@@ -75,12 +77,14 @@
7577
76 QRegion fixed;78 QRegion fixed;
77 QRect imageRect = mImage.rect();79 QRect imageRect = mImage.rect();
80 const int dpr = int(window()->devicePixelRatio());
7881
79 /* Following code taken from QEGLPlatformBackingStore under the terms of the Lesser GPL v2.1 licence82 /* Following code a modified form of that in QEGLPlatformBackingStore, used under the terms of the Lesser GPL v2.1 licence
80 * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). */83 * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). */
81 Q_FOREACH (const QRect &rect, mDirty.rects()) {84 Q_FOREACH (const QRect &rect, mDirty.rects()) {
85 QRect scaledRect(rect.topLeft() * dpr, rect.size() * dpr);
82 // intersect with image rect to be sure86 // intersect with image rect to be sure
83 QRect r = imageRect & rect;87 QRect r = imageRect & scaledRect;
8488
85 // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy89 // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy
86 if (r.width() >= imageRect.width() / 2) {90 if (r.width() >= imageRect.width() / 2) {
@@ -115,7 +119,9 @@
115119
116void UbuntuBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/)120void UbuntuBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/)
117{121{
118 mImage = QImage(size, QImage::Format_RGB32);122 const int dpr = int(window()->devicePixelRatio());
123 mImage = QImage(size * dpr, QImage::Format_RGB32);
124 mImage.setDevicePixelRatio(dpr);
119125
120 if (mTexture->isCreated())126 if (mTexture->isCreated())
121 mTexture->destroy();127 mTexture->destroy();
122128
=== modified file 'src/ubuntumirclient/input.cpp'
--- src/ubuntumirclient/input.cpp 2016-03-22 08:49:43 +0000
+++ src/ubuntumirclient/input.cpp 2016-04-20 15:51:01 +0000
@@ -224,6 +224,8 @@
224 return "mir_event_type_close_surface";224 return "mir_event_type_close_surface";
225 case mir_event_type_input:225 case mir_event_type_input:
226 return "mir_event_type_input";226 return "mir_event_type_input";
227 case mir_event_type_surface_output:
228 return "mir_event_type_surface_output";
227 default:229 default:
228 return "invalid";230 return "invalid";
229 }231 }
@@ -259,55 +261,26 @@
259 break;261 break;
260 case mir_event_type_resize:262 case mir_event_type_resize:
261 {263 {
262 Q_ASSERT(ubuntuEvent->window->screen() == mIntegration->screen());
263
264 auto resizeEvent = mir_event_get_resize_event(nativeEvent);264 auto resizeEvent = mir_event_get_resize_event(nativeEvent);
265265
266 mIntegration->screen()->handleWindowSurfaceResize(266 // Enable workaround for Screen rotation
267 mir_resize_event_get_width(resizeEvent),267 auto screen = static_cast<UbuntuScreen*>(ubuntuEvent->window->screen());
268 mir_resize_event_get_height(resizeEvent));268 if (screen) {
269 screen->handleWindowSurfaceResize(
270 mir_resize_event_get_width(resizeEvent),
271 mir_resize_event_get_height(resizeEvent));
272 }
269273
270 ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent),274 ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent),
271 mir_resize_event_get_height(resizeEvent));275 mir_resize_event_get_height(resizeEvent));
272 break;276 break;
273 }277 }
274 case mir_event_type_surface:278 case mir_event_type_surface:
275 {279 handleSurfaceEvent(ubuntuEvent->window, mir_event_get_surface_event(nativeEvent));
276 auto surfaceEvent = mir_event_get_surface_event(nativeEvent);280 break;
277 auto surfaceEventAttribute = mir_surface_event_get_attribute(surfaceEvent);281 case mir_event_type_surface_output:
278 282 handleSurfaceOutputEvent(ubuntuEvent->window, mir_event_get_surface_output_event(nativeEvent));
279 if (surfaceEventAttribute == mir_surface_attrib_focus) {283 break;
280 const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
281 // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
282 // so that we don't deactivate windows prematurely.
283 if (focused) {
284 mPendingFocusGainedEvents--;
285 ubuntuEvent->window->handleSurfaceFocused();
286 QWindowSystemInterface::handleWindowActivated(ubuntuEvent->window->window(), Qt::ActiveWindowFocusReason);
287
288 // NB: Since processing of system events is queued, never check qGuiApp->applicationState()
289 // as it might be outdated. Always call handleApplicationStateChanged() with the latest
290 // state regardless.
291 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
292
293 } else if(!mPendingFocusGainedEvents) {
294 qCDebug(ubuntumirclient, "No windows have focus");
295 QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
296 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
297 }
298 } else if (surfaceEventAttribute == mir_surface_attrib_state) {
299 MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(surfaceEvent));
300
301 if (state == mir_surface_state_hidden) {
302 ubuntuEvent->window->handleSurfaceVisibilityChanged(false);
303 } else {
304 // it's visible!
305 ubuntuEvent->window->handleSurfaceVisibilityChanged(true);
306 ubuntuEvent->window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state));
307 }
308 }
309 break;
310 }
311 case mir_event_type_orientation:284 case mir_event_type_orientation:
312 dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent));285 dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent));
313 break;286 break;
@@ -372,6 +345,7 @@
372 const QRect kWindowGeometry = window->geometry();345 const QRect kWindowGeometry = window->geometry();
373 QList<QWindowSystemInterface::TouchPoint> touchPoints;346 QList<QWindowSystemInterface::TouchPoint> touchPoints;
374347
348 const int dpr = int(window->devicePixelRatio());
375349
376 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left350 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
377 // as Qt::TouchPointMoved351 // as Qt::TouchPointMoved
@@ -379,10 +353,10 @@
379 for (unsigned int i = 0; i < kPointerCount; ++i) {353 for (unsigned int i = 0; i < kPointerCount; ++i) {
380 QWindowSystemInterface::TouchPoint touchPoint;354 QWindowSystemInterface::TouchPoint touchPoint;
381355
382 const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) + kWindowGeometry.x();356 const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) / dpr + kWindowGeometry.x();
383 const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere357 const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) / dpr + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere
384 const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);358 const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major) / dpr;
385 const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);359 const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor) / dpr;
386 const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);360 const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);
387 touchPoint.id = mir_touch_event_id(tev, i);361 touchPoint.id = mir_touch_event_id(tev, i);
388 touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());362 touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());
@@ -525,14 +499,16 @@
525499
526void UbuntuInput::dispatchPointerEvent(UbuntuWindow *platformWindow, const MirInputEvent *ev)500void UbuntuInput::dispatchPointerEvent(UbuntuWindow *platformWindow, const MirInputEvent *ev)
527{501{
528 auto window = platformWindow->window();502 const int dpr = int(platformWindow->devicePixelRatio());
529 auto timestamp = mir_input_event_get_event_time(ev) / 1000000;503 const auto window = platformWindow->window();
530504 const auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
531 auto pev = mir_input_event_get_pointer_event(ev);505
532 auto action = mir_pointer_event_action(pev);506 const auto pev = mir_input_event_get_pointer_event(ev);
533 auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),507 const auto action = mir_pointer_event_action(pev);
534 mir_pointer_event_axis_value(pev, mir_pointer_axis_y));508
535 auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));509 const auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
510 const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x) / dpr,
511 mir_pointer_event_axis_value(pev, mir_pointer_axis_y) / dpr);
536512
537 switch (action) {513 switch (action) {
538 case mir_pointer_action_button_up:514 case mir_pointer_action_button_up:
@@ -620,3 +596,75 @@
620 new OrientationChangeEvent(OrientationChangeEvent::mType, orientation));596 new OrientationChangeEvent(OrientationChangeEvent::mType, orientation));
621}597}
622598
599void UbuntuInput::handleSurfaceEvent(const QPointer<UbuntuWindow> &window, const MirSurfaceEvent *event)
600{
601 auto surfaceEventAttribute = mir_surface_event_get_attribute(event);
602
603 switch (surfaceEventAttribute) {
604 case mir_surface_attrib_focus: {
605 const bool focused = mir_surface_event_get_attribute_value(event) == mir_surface_focused;
606 // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
607 // so that we don't deactivate windows prematurely.
608 if (focused) {
609 mPendingFocusGainedEvents--;
610 window->handleSurfaceFocused();
611 QWindowSystemInterface::handleWindowActivated(window->window(), Qt::ActiveWindowFocusReason);
612
613 // NB: Since processing of system events is queued, never check qGuiApp->applicationState()
614 // as it might be outdated. Always call handleApplicationStateChanged() with the latest
615 // state regardless.
616 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
617
618 } else if(!mPendingFocusGainedEvents) {
619 qCDebug(ubuntumirclient, "No windows have focus");
620 QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
621 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
622 }
623 break;
624 }
625 case mir_surface_attrib_visibility:
626 window->handleSurfaceExposeChange(
627 mir_surface_event_get_attribute_value(event) == mir_surface_visibility_exposed);
628 break;
629 // Remaining attributes are ones client sets for server, and server should not override them
630 case mir_surface_attrib_state: {
631 MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(event));
632 if (state == mir_surface_state_hidden) {
633 window->handleSurfaceVisibilityChanged(false);
634 } else {
635 // it's visible!
636 window->handleSurfaceVisibilityChanged(true);
637 window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state));
638 }
639 break;
640 }
641 case mir_surface_attrib_type:
642 case mir_surface_attrib_swapinterval:
643 case mir_surface_attrib_dpi:
644 case mir_surface_attrib_preferred_orientation:
645 case mir_surface_attribs:
646 break;
647 }
648}
649
650void UbuntuInput::handleSurfaceOutputEvent(const QPointer<UbuntuWindow> &window, const MirSurfaceOutputEvent *event)
651{
652 const uint32_t outputId = mir_surface_output_event_get_output_id(event);
653 const int dpi = mir_surface_output_event_get_dpi(event);
654 const MirFormFactor formFactor = mir_surface_output_event_get_form_factor(event);
655 const float scale = mir_surface_output_event_get_scale(event);
656
657 const auto screenObserver = mIntegration->screenObserver();
658 UbuntuScreen *screen = screenObserver->findScreenWithId(outputId);
659 if (!screen) {
660 qWarning() << "Mir notified window" << window->window() << "on an unknown screen with id" << outputId;
661 return;
662 }
663
664 screenObserver->handleScreenPropertiesChange(screen, dpi, formFactor, scale);
665 window->handleScreenPropertiesChange(formFactor, scale);
666
667 if (window->screen() != screen) {
668 QWindowSystemInterface::handleWindowScreenChanged(window->window(), screen->screen());
669 }
670}
623671
=== modified file 'src/ubuntumirclient/input.h'
--- src/ubuntumirclient/input.h 2015-12-09 13:02:07 +0000
+++ src/ubuntumirclient/input.h 2016-04-20 15:51:01 +0000
@@ -49,6 +49,8 @@
49 void dispatchInputEvent(UbuntuWindow *window, const MirInputEvent *event);49 void dispatchInputEvent(UbuntuWindow *window, const MirInputEvent *event);
5050
51 void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event);51 void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event);
52 void handleSurfaceEvent(const QPointer<UbuntuWindow> &window, const MirSurfaceEvent *event);
53 void handleSurfaceOutputEvent(const QPointer<UbuntuWindow> &window, const MirSurfaceOutputEvent *event);
5254
53private:55private:
54 UbuntuClientIntegration* mIntegration;56 UbuntuClientIntegration* mIntegration;
5557
=== modified file 'src/ubuntumirclient/integration.cpp'
--- src/ubuntumirclient/integration.cpp 2016-01-04 17:18:51 +0000
+++ src/ubuntumirclient/integration.cpp 2016-04-20 15:51:01 +0000
@@ -88,19 +88,26 @@
88 "rejected the incoming connection, so check its log file");88 "rejected the incoming connection, so check its log file");
8989
90 mNativeInterface->setMirConnection(u_application_instance_get_mir_connection(mInstance));90 mNativeInterface->setMirConnection(u_application_instance_get_mir_connection(mInstance));
9191}
92 // Create default screen.92
93 mScreen = new UbuntuScreen(u_application_instance_get_mir_connection(mInstance));93void UbuntuClientIntegration::initialize()
94 screenAdded(mScreen);94{
95 MirConnection *mirConnection = u_application_instance_get_mir_connection(mInstance);
96
97 // Init the ScreenObserver
98 mScreenObserver.reset(new UbuntuScreenObserver(mirConnection));
99 connect(mScreenObserver.data(), &UbuntuScreenObserver::screenAdded,
100 [this](UbuntuScreen *screen) { this->screenAdded(screen); });
101 connect(mScreenObserver.data(), &UbuntuScreenObserver::screenRemoved,
102 this, &UbuntuClientIntegration::destroyScreen);
103
104 Q_FOREACH(auto screen, mScreenObserver->screens()) {
105 screenAdded(screen);
106 }
95107
96 // Initialize input.108 // Initialize input.
97 if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_INPUT")) {109 mInput = new UbuntuInput(this);
98 mInput = new UbuntuInput(this);110 mInputContext = QPlatformInputContextFactory::create();
99 mInputContext = QPlatformInputContextFactory::create();
100 } else {
101 mInput = nullptr;
102 mInputContext = nullptr;
103 }
104111
105 // compute the scale factor112 // compute the scale factor
106 const int defaultGridUnit = 8;113 const int defaultGridUnit = 8;
@@ -120,7 +127,6 @@
120{127{
121 delete mInput;128 delete mInput;
122 delete mInputContext;129 delete mInputContext;
123 delete mScreen;
124 delete mServices;130 delete mServices;
125}131}
126132
@@ -165,8 +171,8 @@
165171
166QPlatformWindow* UbuntuClientIntegration::createPlatformWindow(QWindow* window)172QPlatformWindow* UbuntuClientIntegration::createPlatformWindow(QWindow* window)
167{173{
168 return new UbuntuWindow(window, mClipboard, static_cast<UbuntuScreen*>(mScreen),174 return new UbuntuWindow(window, mClipboard, mInput, mNativeInterface,
169 mInput, u_application_instance_get_mir_connection(mInstance));175 u_application_instance_get_mir_connection(mInstance));
170}176}
171177
172bool UbuntuClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const178bool UbuntuClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -262,3 +268,34 @@
262{268{
263 return new UbuntuOffscreenSurface(surface);269 return new UbuntuOffscreenSurface(surface);
264}270}
271
272void UbuntuClientIntegration::destroyScreen(UbuntuScreen *screen)
273{
274 // FIXME: on deleting a screen while a Window is on it, Qt will automatically
275 // move the window to the primaryScreen(). This will trigger a screenChanged
276 // signal, causing things like QQuickScreenAttached to re-fetch screen properties
277 // like DPI and physical size. However this is crashing, as Qt is calling virtual
278 // functions on QPlatformScreen, for reasons unclear. As workaround, move window
279 // to primaryScreen() before deleting the screen. Might be QTBUG-38650
280
281 QScreen *primaryScreen = QGuiApplication::primaryScreen();
282 if (screen != primaryScreen->handle()) {
283 uint32_t movedWindowCount = 0;
284 Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) {
285 if (w->screen()->handle() == screen) {
286 QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen);
287 ++movedWindowCount;
288 }
289 }
290 if (movedWindowCount > 0) {
291 QWindowSystemInterface::flushWindowSystemEvents();
292 }
293 }
294
295 qDebug() << "Removing Screen with id" << screen->outputId() << "and geometry" << screen->geometry();
296#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
297 delete screen;
298#else
299 this->destroyScreen(screen);
300#endif
301}
265302
=== modified file 'src/ubuntumirclient/integration.h'
--- src/ubuntumirclient/integration.h 2016-01-04 17:18:51 +0000
+++ src/ubuntumirclient/integration.h 2016-04-20 15:51:01 +0000
@@ -21,6 +21,7 @@
21#include <QSharedPointer>21#include <QSharedPointer>
2222
23#include "platformservices.h"23#include "platformservices.h"
24#include "screenobserver.h"
2425
25// platform-api26// platform-api
26#include <ubuntu/application/description.h>27#include <ubuntu/application/description.h>
@@ -31,7 +32,10 @@
31class UbuntuNativeInterface;32class UbuntuNativeInterface;
32class UbuntuScreen;33class UbuntuScreen;
3334
34class UbuntuClientIntegration : public QPlatformIntegration {35class UbuntuClientIntegration : public QObject, public QPlatformIntegration
36{
37 Q_OBJECT
38
35public:39public:
36 UbuntuClientIntegration();40 UbuntuClientIntegration();
37 virtual ~UbuntuClientIntegration();41 virtual ~UbuntuClientIntegration();
@@ -53,10 +57,15 @@
5357
54 QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context);58 QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context);
55 QPlatformWindow* createPlatformWindow(QWindow* window);59 QPlatformWindow* createPlatformWindow(QWindow* window);
56 UbuntuScreen* screen() const { return mScreen; }60 UbuntuScreenObserver *screenObserver() const { return mScreenObserver.data(); }
61
62 void initialize() override;
5763
58 QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;64 QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
5965
66private Q_SLOTS:
67 void destroyScreen(UbuntuScreen *screen);
68
60private:69private:
61 void setupOptions();70 void setupOptions();
62 void setupDescription();71 void setupDescription();
@@ -66,10 +75,10 @@
6675
67 UbuntuPlatformServices* mServices;76 UbuntuPlatformServices* mServices;
6877
69 UbuntuScreen* mScreen;
70 UbuntuInput* mInput;78 UbuntuInput* mInput;
71 QPlatformInputContext* mInputContext;79 QPlatformInputContext* mInputContext;
72 QSharedPointer<UbuntuClipboard> mClipboard;80 QSharedPointer<UbuntuClipboard> mClipboard;
81 QScopedPointer<UbuntuScreenObserver> mScreenObserver;
73 qreal mScaleFactor;82 qreal mScaleFactor;
7483
75 // Platform API stuff84 // Platform API stuff
7685
=== modified file 'src/ubuntumirclient/nativeinterface.cpp'
--- src/ubuntumirclient/nativeinterface.cpp 2015-12-15 16:16:06 +0000
+++ src/ubuntumirclient/nativeinterface.cpp 2016-04-20 15:51:01 +0000
@@ -18,6 +18,7 @@
18#include "nativeinterface.h"18#include "nativeinterface.h"
19#include "screen.h"19#include "screen.h"
20#include "glcontext.h"20#include "glcontext.h"
21#include "window.h"
2122
22// Qt23// Qt
23#include <private/qguiapplication_p.h>24#include <private/qguiapplication_p.h>
@@ -35,6 +36,8 @@
35 insert("nativeorientation", UbuntuNativeInterface::NativeOrientation);36 insert("nativeorientation", UbuntuNativeInterface::NativeOrientation);
36 insert("display", UbuntuNativeInterface::Display);37 insert("display", UbuntuNativeInterface::Display);
37 insert("mirconnection", UbuntuNativeInterface::MirConnection);38 insert("mirconnection", UbuntuNativeInterface::MirConnection);
39 insert("scale", UbuntuNativeInterface::Scale);
40 insert("formfactor", UbuntuNativeInterface::FormFactor);
38 }41 }
39};42};
4043
@@ -123,10 +126,59 @@
123 if (!ubuntuResourceMap()->contains(kLowerCaseResource))126 if (!ubuntuResourceMap()->contains(kLowerCaseResource))
124 return NULL;127 return NULL;
125 const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);128 const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
129 if (!screen)
130 screen = QGuiApplication::primaryScreen();
131 auto ubuntuScreen = static_cast<UbuntuScreen*>(screen->handle());
126 if (kResourceType == UbuntuNativeInterface::Display) {132 if (kResourceType == UbuntuNativeInterface::Display) {
127 if (!screen)133 return ubuntuScreen->eglNativeDisplay();
128 screen = QGuiApplication::primaryScreen();134 // Changes to the following properties are emitted via the UbuntuNativeInterface::screenPropertyChanged
129 return static_cast<UbuntuScreen*>(screen->handle())->eglNativeDisplay();135 // signal fired by UbuntuScreen. Connect to this signal for these properties updates.
136 // WARNING: code highly thread unsafe!
137 } else if (kResourceType == UbuntuNativeInterface::Scale) {
138 // In application code, read with:
139 // float scale = *reinterpret_cast<float*>(nativeResourceForScreen("scale", screen()));
140 return &ubuntuScreen->mScale;
141 } else if (kResourceType == UbuntuNativeInterface::FormFactor) {
142 return &ubuntuScreen->mFormFactor;
130 } else143 } else
131 return NULL;144 return NULL;
132}145}
146
147// Changes to these properties are emitted via the UbuntuNativeInterface::windowPropertyChanged
148// signal fired by UbuntuWindow. Connect to this signal for these properties updates.
149QVariantMap UbuntuNativeInterface::windowProperties(QPlatformWindow *window) const
150{
151 QVariantMap propertyMap;
152 auto w = static_cast<UbuntuWindow*>(window);
153 if (w) {
154 propertyMap.insert("scale", w->scale());
155 propertyMap.insert("formFactor", w->formFactor());
156 }
157 return propertyMap;
158}
159
160QVariant UbuntuNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const
161{
162 auto w = static_cast<UbuntuWindow*>(window);
163 if (!w) {
164 return QVariant();
165 }
166
167 if (name == QStringLiteral("scale")) {
168 return w->scale();
169 } else if (name == QStringLiteral("formFactor")) {
170 return w->formFactor();
171 } else {
172 return QVariant();
173 }
174}
175
176QVariant UbuntuNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const
177{
178 QVariant returnVal = windowProperty(window, name);
179 if (!returnVal.isValid()) {
180 return defaultValue;
181 } else {
182 return returnVal;
183 }
184}
133185
=== modified file 'src/ubuntumirclient/nativeinterface.h'
--- src/ubuntumirclient/nativeinterface.h 2015-08-27 09:41:47 +0000
+++ src/ubuntumirclient/nativeinterface.h 2016-04-20 15:51:01 +0000
@@ -19,9 +19,12 @@
1919
20#include <qpa/qplatformnativeinterface.h>20#include <qpa/qplatformnativeinterface.h>
2121
22class QPlatformScreen;
23
22class UbuntuNativeInterface : public QPlatformNativeInterface {24class UbuntuNativeInterface : public QPlatformNativeInterface {
25 Q_OBJECT
23public:26public:
24 enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection };27 enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection, Scale, FormFactor };
2528
26 UbuntuNativeInterface();29 UbuntuNativeInterface();
27 ~UbuntuNativeInterface();30 ~UbuntuNativeInterface();
@@ -35,10 +38,17 @@
35 void* nativeResourceForScreen(const QByteArray& resourceString,38 void* nativeResourceForScreen(const QByteArray& resourceString,
36 QScreen* screen) override;39 QScreen* screen) override;
3740
41 QVariantMap windowProperties(QPlatformWindow *window) const override;
42 QVariant windowProperty(QPlatformWindow *window, const QString &name) const override;
43 QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override;
44
38 // New methods.45 // New methods.
39 const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; }46 const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; }
40 void setMirConnection(void *mirConnection) { mMirConnection = mirConnection; }47 void setMirConnection(void *mirConnection) { mMirConnection = mirConnection; }
4148
49Q_SIGNALS: // New signals
50 void screenPropertyChanged(QPlatformScreen *screen, const QString &propertyName);
51
42private:52private:
43 const QByteArray mGenericEventFilterType;53 const QByteArray mGenericEventFilterType;
44 Qt::ScreenOrientation* mNativeOrientation;54 Qt::ScreenOrientation* mNativeOrientation;
4555
=== modified file 'src/ubuntumirclient/screen.cpp'
--- src/ubuntumirclient/screen.cpp 2015-12-09 13:01:28 +0000
+++ src/ubuntumirclient/screen.cpp 2016-04-20 15:51:01 +0000
@@ -18,11 +18,13 @@
18#include "screen.h"18#include "screen.h"
19#include "logging.h"19#include "logging.h"
20#include "orientationchangeevent_p.h"20#include "orientationchangeevent_p.h"
21#include "nativeinterface.h"
22#include "utils.h"
2123
22#include <mir_toolkit/mir_client_library.h>24#include <mir_toolkit/mir_client_library.h>
2325
24// Qt26// Qt
25#include <QCoreApplication>27#include <QGuiApplication>
26#include <QtCore/qmath.h>28#include <QtCore/qmath.h>
27#include <QScreen>29#include <QScreen>
28#include <QThread>30#include <QThread>
@@ -101,37 +103,29 @@
101 }103 }
102}104}
103105
106namespace {
107 int qGetEnvIntValue(const char *varName, bool *ok)
108 {
109 return qgetenv(varName).toInt(ok);
110 }
111} // anonymous namespace
112
113
104const QEvent::Type OrientationChangeEvent::mType =114const QEvent::Type OrientationChangeEvent::mType =
105 static_cast<QEvent::Type>(QEvent::registerEventType());115 static_cast<QEvent::Type>(QEvent::registerEventType());
106116
107static const MirDisplayOutput *find_active_output(117
108 const MirDisplayConfiguration *conf)118UbuntuScreen::UbuntuScreen(const MirDisplayOutput &output, MirConnection *connection)
109{119 : mDevicePixelRatio(1.0)
110 const MirDisplayOutput *output = NULL;120 , mFormat(QImage::Format_RGB32)
111 for (uint32_t d = 0; d < conf->num_outputs; d++)
112 {
113 const MirDisplayOutput *out = conf->outputs + d;
114
115 if (out->used &&
116 out->connected &&
117 out->num_modes &&
118 out->current_mode < out->num_modes)
119 {
120 output = out;
121 break;
122 }
123 }
124
125 return output;
126}
127
128UbuntuScreen::UbuntuScreen(MirConnection *connection)
129 : mFormat(QImage::Format_RGB32)
130 , mDepth(32)121 , mDepth(32)
122 , mDpi{0}
123 , mFormFactor{mir_form_factor_unknown}
124 , mScale{1.0}
131 , mOutputId(0)125 , mOutputId(0)
132 , mSurfaceFormat()
133 , mEglDisplay(EGL_NO_DISPLAY)126 , mEglDisplay(EGL_NO_DISPLAY)
134 , mEglConfig(nullptr)127 , mEglConfig(nullptr)
128 , mSurfaceFormat()
135 , mCursor(connection)129 , mCursor(connection)
136{130{
137 // Initialize EGL.131 // Initialize EGL.
@@ -164,45 +158,15 @@
164 }158 }
165159
166 // Set vblank swap interval.160 // Set vblank swap interval.
167 int swapInterval = kSwapInterval;161 bool ok;
168 QByteArray swapIntervalString = qgetenv("QTUBUNTU_SWAPINTERVAL");162 int swapInterval = qGetEnvIntValue("QTUBUNTU_SWAPINTERVAL", &ok);
169 if (!swapIntervalString.isEmpty()) {163 if (!ok)
170 bool ok;164 swapInterval = kSwapInterval;
171 swapInterval = swapIntervalString.toInt(&ok);165
172 if (!ok)166 qCDebug(ubuntumirclient, "Setting swap interval to %d", swapInterval);
173 swapInterval = kSwapInterval;
174 }
175 qCDebug(ubuntumirclient, "setting swap interval to %d", swapInterval);
176 eglSwapInterval(mEglDisplay, swapInterval);167 eglSwapInterval(mEglDisplay, swapInterval);
177168
178 // Get screen resolution.169 setMirDisplayOutput(output);
179 auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); };
180 using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>;
181 configUp displayConfig(mir_connection_create_display_config(connection), configDeleter);
182 ASSERT(displayConfig != nullptr);
183
184 auto const displayOutput = find_active_output(displayConfig.get());
185 ASSERT(displayOutput != nullptr);
186
187 mOutputId = displayOutput->output_id;
188
189 mPhysicalSize = QSizeF(displayOutput->physical_width_mm, displayOutput->physical_height_mm);
190 qCDebug(ubuntumirclient, "screen physical size: %.2fx%.2f", mPhysicalSize.width(), mPhysicalSize.height());
191
192 const MirDisplayMode *mode = &displayOutput->modes[displayOutput->current_mode];
193 const int kScreenWidth = mode->horizontal_resolution;
194 const int kScreenHeight = mode->vertical_resolution;
195 Q_ASSERT(kScreenWidth > 0 && kScreenHeight > 0);
196
197 qCDebug(ubuntumirclient, "screen resolution: %dx%d", kScreenWidth, kScreenHeight);
198
199 mGeometry = QRect(0, 0, kScreenWidth, kScreenHeight);
200
201 // Set the default orientation based on the initial screen dimmensions.
202 mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
203
204 // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
205 mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
206}170}
207171
208UbuntuScreen::~UbuntuScreen()172UbuntuScreen::~UbuntuScreen()
@@ -278,3 +242,77 @@
278 QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);242 QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);
279 }243 }
280}244}
245
246void UbuntuScreen::setMirDisplayOutput(const MirDisplayOutput &output)
247{
248 // Physical screen size
249 mPhysicalSize.setWidth(output.physical_width_mm);
250 mPhysicalSize.setHeight(output.physical_height_mm);
251
252 // Pixel Format
253// mFormat = qImageFormatFromMirPixelFormat(output.current_format); // GERRY: TODO
254
255 // Pixel depth
256 mDepth = 8 * MIR_BYTES_PER_PIXEL(output.current_format);
257
258 // Mode = Resolution & refresh rate
259 MirDisplayMode mode = output.modes[output.current_mode];
260 mNativeGeometry.setX(output.position_x);
261 mNativeGeometry.setY(output.position_y);
262 mNativeGeometry.setWidth(mode.horizontal_resolution);
263 mNativeGeometry.setHeight(mode.vertical_resolution);
264 mRefreshRate = mode.refresh_rate;
265
266 // geometry in device pixels
267 mGeometry.setX(mNativeGeometry.x() / mDevicePixelRatio);
268 mGeometry.setY(mNativeGeometry.y() / mDevicePixelRatio);
269 mGeometry.setWidth(mNativeGeometry.width() / mDevicePixelRatio);
270 mGeometry.setHeight(mNativeGeometry.height() / mDevicePixelRatio);
271
272 // Misc
273// mScale = output.scale; // missing from MirDisplayOutput, wait for later setAdditionalMirDisplayProperties call
274// mFormFactor = output.form_factor; // ditto
275 mOutputId = output.output_id;
276
277 // Set the default orientation based on the initial screen dimmensions.
278 mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
279
280 // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
281 mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
282}
283
284void UbuntuScreen::setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, float dpi)
285{
286 auto nativeInterface = static_cast<UbuntuNativeInterface *>(qGuiApp->platformNativeInterface());
287 if (!qFuzzyCompare(mScale, scale)) {
288 mScale = scale;
289 Q_EMIT nativeInterface->screenPropertyChanged(this, QStringLiteral("scale"));
290 }
291 if (mFormFactor != formFactor) {
292 mFormFactor = formFactor;
293 Q_EMIT nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor"));
294 }
295
296 bool ok;
297 int dpr = qGetEnvIntValue("QT_DEVICE_PIXEL_RATIO", &ok);
298 if (ok && dpr > 0) {
299 qCDebug(ubuntumirclient, "Fixing Device Pixel Ratio to %d", dpr);
300 mDevicePixelRatio = dpr;
301 } else {
302 mDevicePixelRatio = 1.0; //qCeil(scale); // FIXME - unable to announce change in this until can delete/recreate Screen.
303 }
304
305 if (mDpi != dpi) {
306 mDpi = dpi;
307 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), dpi, dpi);
308 }
309}
310
311QDpi UbuntuScreen::logicalDpi() const
312{
313 if (mDpi > 0) {
314 return QDpi(mDpi, mDpi);
315 } else {
316 return QPlatformScreen::logicalDpi();
317 }
318}
281319
=== modified file 'src/ubuntumirclient/screen.h'
--- src/ubuntumirclient/screen.h 2015-11-23 11:10:24 +0000
+++ src/ubuntumirclient/screen.h 2016-04-20 15:51:01 +0000
@@ -19,17 +19,21 @@
1919
20#include <qpa/qplatformscreen.h>20#include <qpa/qplatformscreen.h>
21#include <QSurfaceFormat>21#include <QSurfaceFormat>
22
23#include <mircommon/mir_toolkit/common.h> // just for MirFormFactor enum
24
22#include <EGL/egl.h>25#include <EGL/egl.h>
2326
24#include "cursor.h"27#include "cursor.h"
2528
26struct MirConnection;29struct MirConnection;
30struct MirDisplayOutput;
2731
28class UbuntuScreen : public QObject, public QPlatformScreen32class UbuntuScreen : public QObject, public QPlatformScreen
29{33{
30 Q_OBJECT34 Q_OBJECT
31public:35public:
32 UbuntuScreen(MirConnection *connection);36 UbuntuScreen(const MirDisplayOutput &output, MirConnection *connection);
33 virtual ~UbuntuScreen();37 virtual ~UbuntuScreen();
3438
35 // QPlatformScreen methods.39 // QPlatformScreen methods.
@@ -38,6 +42,8 @@
38 QRect geometry() const override { return mGeometry; }42 QRect geometry() const override { return mGeometry; }
39 QRect availableGeometry() const override { return mGeometry; }43 QRect availableGeometry() const override { return mGeometry; }
40 QSizeF physicalSize() const override { return mPhysicalSize; }44 QSizeF physicalSize() const override { return mPhysicalSize; }
45 qreal devicePixelRatio() const override { return mDevicePixelRatio; }
46 QDpi logicalDpi() const override;
41 Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; }47 Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; }
42 Qt::ScreenOrientation orientation() const override { return mNativeOrientation; }48 Qt::ScreenOrientation orientation() const override { return mNativeOrientation; }
43 QPlatformCursor *cursor() const override { return const_cast<UbuntuCursor*>(&mCursor); }49 QPlatformCursor *cursor() const override { return const_cast<UbuntuCursor*>(&mCursor); }
@@ -47,6 +53,15 @@
47 EGLDisplay eglDisplay() const { return mEglDisplay; }53 EGLDisplay eglDisplay() const { return mEglDisplay; }
48 EGLConfig eglConfig() const { return mEglConfig; }54 EGLConfig eglConfig() const { return mEglConfig; }
49 EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }55 EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
56
57 // Additional Screen properties from Mir
58 uint32_t outputId() const { return mOutputId; }
59 MirFormFactor formFactor() const { return mFormFactor; }
60 float scale() const { return mScale; }
61
62 // Internally used methods
63 void setMirDisplayOutput(const MirDisplayOutput &output);
64 void setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, float dpi);
50 void handleWindowSurfaceResize(int width, int height);65 void handleWindowSurfaceResize(int width, int height);
51 uint32_t mirOutputId() const { return mOutputId; }66 uint32_t mirOutputId() const { return mOutputId; }
5267
@@ -54,18 +69,25 @@
54 void customEvent(QEvent* event) override;69 void customEvent(QEvent* event) override;
5570
56private:71private:
57 QRect mGeometry;72 QRect mGeometry, mNativeGeometry;
58 QSizeF mPhysicalSize;73 QSizeF mPhysicalSize;
74 qreal mDevicePixelRatio;
59 Qt::ScreenOrientation mNativeOrientation;75 Qt::ScreenOrientation mNativeOrientation;
60 Qt::ScreenOrientation mCurrentOrientation;76 Qt::ScreenOrientation mCurrentOrientation;
61 QImage::Format mFormat;77 QImage::Format mFormat;
62 int mDepth;78 int mDepth;
79 int mDpi;
80 qreal mRefreshRate;
81 MirFormFactor mFormFactor;
82 float mScale;
63 uint32_t mOutputId;83 uint32_t mOutputId;
64 QSurfaceFormat mSurfaceFormat;
65 EGLDisplay mEglDisplay;84 EGLDisplay mEglDisplay;
66 EGLConfig mEglConfig;85 EGLConfig mEglConfig;
67 EGLNativeDisplayType mEglNativeDisplay;86 EGLNativeDisplayType mEglNativeDisplay;
68 UbuntuCursor mCursor;87 QSurfaceFormat mSurfaceFormat;
88 UbuntuCursor mCursor; //GERRY try const
89
90 friend class UbuntuNativeInterface;
69};91};
7092
71#endif // UBUNTU_SCREEN_H93#endif // UBUNTU_SCREEN_H
7294
=== added file 'src/ubuntumirclient/screenobserver.cpp'
--- src/ubuntumirclient/screenobserver.cpp 1970-01-01 00:00:00 +0000
+++ src/ubuntumirclient/screenobserver.cpp 2016-04-20 15:51:01 +0000
@@ -0,0 +1,131 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "screenobserver.h"
18#include "screen.h"
19#include "window.h"
20#include "logging.h"
21
22// Qt
23#include <QMetaObject>
24#include <QPointer>
25
26// Mir
27#include <mirclient/mir_toolkit/mir_connection.h>
28
29#include <memory>
30
31namespace {
32 static void displayConfigurationChangedCallback(MirConnection */*connection*/, void* context)
33 {
34 ASSERT(context != NULL);
35 UbuntuScreenObserver *observer = static_cast<UbuntuScreenObserver *>(context);
36 QMetaObject::invokeMethod(observer, "update");
37 }
38} // anonymous namespace
39
40UbuntuScreenObserver::UbuntuScreenObserver(MirConnection *mirConnection)
41 : mMirConnection(mirConnection)
42{
43 mir_connection_set_display_config_change_callback(mirConnection, ::displayConfigurationChangedCallback, this);
44 update();
45}
46
47void UbuntuScreenObserver::update()
48{
49 // Wrap MirDisplayConfiguration to always delete when out of scope
50 auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); };
51 using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>;
52 configUp displayConfig(mir_connection_create_display_config(mMirConnection), configDeleter);
53
54 // Mir only tells us something changed, it is up to us to figure out what.
55 QList<UbuntuScreen*> newScreenList;
56 QList<UbuntuScreen*> oldScreenList = mScreenList;
57 mScreenList.clear();
58
59 for (uint32_t i=0; i<displayConfig->num_outputs; i++) {
60 MirDisplayOutput output = displayConfig->outputs[i];
61 if (output.used && output.connected) {
62 UbuntuScreen *screen = findScreenWithId(oldScreenList, output.output_id);
63 if (screen) { // we've already set up this display before, refresh its internals
64 screen->setMirDisplayOutput(output);
65 oldScreenList.removeAll(screen);
66 } else {
67 // new display, so create UbuntuScreen for it
68 screen = new UbuntuScreen(output, mMirConnection);
69 newScreenList.append(screen);
70 qDebug() << "Added Screen with id" << output.output_id << "and geometry" << screen->geometry();
71 }
72 mScreenList.append(screen);
73 }
74 }
75
76 // Announce old & unused Screens, should be deleted by the slot
77 Q_FOREACH (const auto screen, oldScreenList) {
78 Q_EMIT screenRemoved(screen);
79 }
80
81 /*
82 * Mir's MirDisplayOutput does not include formFactor or scale for some reason, but Qt
83 * will want that information on creating the QScreen. Only way we get that info is when
84 * Mir positions a Window on that Screen. See "handleScreenPropertiesChange" method
85 */
86
87 // Announce new Screens
88 Q_FOREACH (const auto screen, newScreenList) {
89 Q_EMIT screenAdded(screen);
90 }
91
92 qDebug() << "=======================================";
93 for (auto screen: mScreenList) {
94 qDebug() << screen << "- id:" << screen->outputId()
95 << "geometry:" << screen->geometry()
96 << "form factor:" << screen->formFactor()
97 << "scale:" << screen->scale();
98 }
99 qDebug() << "=======================================";
100}
101
102UbuntuScreen *UbuntuScreenObserver::findScreenWithId(uint32_t id)
103{
104 return findScreenWithId(mScreenList, id);
105}
106
107UbuntuScreen *UbuntuScreenObserver::findScreenWithId(const QList<UbuntuScreen *> &list, uint32_t id)
108{
109 Q_FOREACH (const auto screen, list) {
110 if (screen->outputId() == id) {
111 return screen;
112 }
113 }
114 return nullptr;
115}
116
117void UbuntuScreenObserver::handleScreenPropertiesChange(UbuntuScreen *screen, int dpi,
118 MirFormFactor formFactor, float scale)
119{
120 screen->setAdditionalMirDisplayProperties(scale, formFactor, dpi);
121
122 qDebug() << "=======================================";
123 for (auto screen: mScreenList) {
124 qDebug() << screen << "- id:" << screen->outputId()
125 << "geometry:" << screen->geometry()
126 << "form factor:" << screen->formFactor()
127 << "scale:" << screen->scale();
128 }
129 qDebug() << "=======================================";
130}
131
0132
=== added file 'src/ubuntumirclient/screenobserver.h'
--- src/ubuntumirclient/screenobserver.h 1970-01-01 00:00:00 +0000
+++ src/ubuntumirclient/screenobserver.h 2016-04-20 15:51:01 +0000
@@ -0,0 +1,54 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTU_SCREEN_OBSERVER_H
18#define UBUNTU_SCREEN_OBSERVER_H
19
20#include <QObject>
21
22#include <mir_toolkit/mir_connection.h>
23
24class UbuntuScreen;
25
26class UbuntuScreenObserver : public QObject
27{
28 Q_OBJECT
29
30public:
31 UbuntuScreenObserver(MirConnection *connection);
32
33 QList<UbuntuScreen*> screens() const { return mScreenList; }
34 UbuntuScreen *findScreenWithId(uint32_t id);
35
36 void handleScreenPropertiesChange(UbuntuScreen *screen, int dpi,
37 MirFormFactor formFactor, float scale);
38
39Q_SIGNALS:
40 void screenAdded(UbuntuScreen *screen);
41 void screenRemoved(UbuntuScreen *screen);
42
43private Q_SLOTS:
44 void update();
45
46private:
47 UbuntuScreen *findScreenWithId(const QList<UbuntuScreen *> &list, uint32_t id);
48 void removeScreen(UbuntuScreen *screen);
49
50 MirConnection *mMirConnection;
51 QList<UbuntuScreen*> mScreenList;
52};
53
54#endif // UBUNTU_SCREEN_OBSERVER_H
055
=== modified file 'src/ubuntumirclient/ubuntumirclient.pro'
--- src/ubuntumirclient/ubuntumirclient.pro 2016-02-25 21:02:19 +0000
+++ src/ubuntumirclient/ubuntumirclient.pro 2016-04-20 15:51:01 +0000
@@ -26,6 +26,7 @@
26 platformservices.cpp \26 platformservices.cpp \
27 plugin.cpp \27 plugin.cpp \
28 screen.cpp \28 screen.cpp \
29 screenobserver.cpp \
29 theme.cpp \30 theme.cpp \
30 window.cpp31 window.cpp
3132
@@ -42,9 +43,11 @@
42 orientationchangeevent_p.h \43 orientationchangeevent_p.h \
43 platformservices.h \44 platformservices.h \
44 plugin.h \45 plugin.h \
46 screenobserver.h \
45 screen.h \47 screen.h \
46 theme.h \48 theme.h \
47 window.h49 window.h \
50 utils.h
4851
49# Installation path52# Installation path
50target.path += $$[QT_INSTALL_PLUGINS]/platforms53target.path += $$[QT_INSTALL_PLUGINS]/platforms
5154
=== added file 'src/ubuntumirclient/utils.h'
--- src/ubuntumirclient/utils.h 1970-01-01 00:00:00 +0000
+++ src/ubuntumirclient/utils.h 2016-04-20 15:51:01 +0000
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UTILS_H
18#define UTILS_H
19
20#include <QtGlobal>
21
22namespace {
23 inline int divideAndRoundUp(int numerator, qreal denominator)
24 {
25 return ceil((qreal)numerator / denominator);
26 }
27} // anonymous namespace
28
29#endif // UTILS_H
030
=== modified file 'src/ubuntumirclient/window.cpp'
--- src/ubuntumirclient/window.cpp 2016-03-14 17:37:19 +0000
+++ src/ubuntumirclient/window.cpp 2016-04-20 15:51:01 +0000
@@ -17,8 +17,10 @@
17// Local17// Local
18#include "window.h"18#include "window.h"
19#include "clipboard.h"19#include "clipboard.h"
20#include "nativeinterface.h"
20#include "input.h"21#include "input.h"
21#include "screen.h"22#include "screen.h"
23#include "utils.h"
22#include "logging.h"24#include "logging.h"
2325
24#include <mir_toolkit/mir_client_library.h>26#include <mir_toolkit/mir_client_library.h>
@@ -34,6 +36,11 @@
3436
35#include <EGL/egl.h>37#include <EGL/egl.h>
3638
39
40/*
41 * Note: all geometry is in device-independent pixels, except that contained in variables with the
42 * suffix "Px" - whose units are (physical) pixels
43 */
37Q_LOGGING_CATEGORY(ubuntumirclientBufferSwap, "ubuntumirclient.bufferSwap", QtWarningMsg)44Q_LOGGING_CATEGORY(ubuntumirclientBufferSwap, "ubuntumirclient.bufferSwap", QtWarningMsg)
3845
39const Qt::WindowType LowChromeWindowHint = (Qt::WindowType)0x00800000;46const Qt::WindowType LowChromeWindowHint = (Qt::WindowType)0x00800000;
@@ -153,13 +160,14 @@
153Spec makeSurfaceSpec(QWindow *window, UbuntuInput *input, MirConnection *connection)160Spec makeSurfaceSpec(QWindow *window, UbuntuInput *input, MirConnection *connection)
154{161{
155 const auto geom = window->geometry();162 const auto geom = window->geometry();
156 const int width = geom.width() > 0 ? geom.width() : 1;163 const int dpr = int(window->devicePixelRatio());
157 const int height = geom.height() > 0 ? geom.height() : 1;164 const int widthPx = geom.width() > 0 ? geom.width() * dpr : 1;
165 const int heightPx = geom.height() > 0 ? geom.height() * dpr : 1;
158 const auto pixelFormat = defaultPixelFormatFor(connection);166 const auto pixelFormat = defaultPixelFormatFor(connection);
159167
160 if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {168 if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
161 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);169 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating input method surface with size=(%dx%d)px", window, widthPx, heightPx);
162 return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};170 return Spec{mir_connection_create_spec_for_input_method(connection, widthPx, heightPx, pixelFormat)};
163 }171 }
164172
165 const Qt::WindowType type = window->type();173 const Qt::WindowType type = window->type();
@@ -172,13 +180,13 @@
172 parent = input->lastFocusedWindow();180 parent = input->lastFocusedWindow();
173 }181 }
174 if (parent) {182 if (parent) {
175 auto pos = geom.topLeft();183 auto posPx = geom.topLeft() * dpr;
176 pos -= parent->geometry().topLeft();184 posPx -= parent->geometry().topLeft() * dpr;
177 MirRectangle location{pos.x(), pos.y(), 0, 0};185 MirRectangle location{posPx.x(), posPx.y(), 0, 0};
178 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);186 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating menu surface with size=(%dx%d)px", window, widthPx, heightPx);
179 return Spec{mir_connection_create_spec_for_menu(187 return Spec{mir_connection_create_spec_for_menu(
180 connection, width, height, pixelFormat, parent->mirSurface(),188 connection, widthPx, heightPx, pixelFormat, parent->mirSurface(),
181 &location, mir_edge_attachment_any)};189 &location, mir_edge_attachment_any)};
182 } else {190 } else {
183 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);191 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
184 }192 }
@@ -186,37 +194,39 @@
186 auto parent = transientParentFor(window);194 auto parent = transientParentFor(window);
187 if (parent) {195 if (parent) {
188 // Modal dialog196 // Modal dialog
189 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);197 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating modal dialog with size=(%dx%d)px", window, widthPx, heightPx);
190 return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};198 return Spec{mir_connection_create_spec_for_modal_dialog(connection, widthPx, heightPx, pixelFormat, parent->mirSurface())};
191 } else {199 } else {
192 // TODO: do Qt parentless dialogs have the same semantics as mir?200 // TODO: do Qt parentless dialogs have the same semantics as mir?
193 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);201 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating parentless dialog with size=(%dx%d)px", window, widthPx, heightPx);
194 return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};202 return Spec{mir_connection_create_spec_for_dialog(connection, widthPx, heightPx, pixelFormat)};
195 }203 }
196 }204 }
197 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);205 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, with size=(%dx%d)px", window, type, widthPx, heightPx);
198 return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};206 return Spec{mir_connection_create_spec_for_normal_surface(connection, widthPx, heightPx, pixelFormat)};
199}207}
200208
201void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)209void setSizingConstraints(MirSurfaceSpec *spec, const QSize &minSizePx, const QSize &maxSizePx, const QSize &incrementPx)
202{210{
203 mir_surface_spec_set_min_width(spec, minSize.width());211 mir_surface_spec_set_min_width(spec, minSizePx.width());
204 mir_surface_spec_set_min_height(spec, minSize.height());212 mir_surface_spec_set_min_height(spec, minSizePx.height());
205 if (maxSize.width() >= minSize.width()) {213 if (maxSizePx.width() >= minSizePx.width()) {
206 mir_surface_spec_set_max_width(spec, maxSize.width());214 mir_surface_spec_set_max_width(spec, maxSizePx.width());
207 }215 }
208 if (maxSize.height() >= minSize.height()) {216 if (maxSizePx.height() >= minSizePx.height()) {
209 mir_surface_spec_set_max_height(spec, maxSize.height());217 mir_surface_spec_set_max_height(spec, maxSizePx.height());
210 }218 }
211 if (increment.width() > 0) {219 if (incrementPx.width() > 0) {
212 mir_surface_spec_set_width_increment(spec, increment.width());220 mir_surface_spec_set_width_increment(spec, incrementPx.width());
213 }221 }
214 if (increment.height() > 0) {222 if (incrementPx.height() > 0) {
215 mir_surface_spec_set_height_increment(spec, increment.height());223 mir_surface_spec_set_height_increment(spec, incrementPx.height());
216 }224 }
217}225}
218226
219MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)227MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input,
228 MirConnection *connection, mir_surface_event_callback inputCallback,
229 void* inputContext)
220{230{
221 auto spec = makeSurfaceSpec(window, input, connection);231 auto spec = makeSurfaceSpec(window, input, connection);
222 const auto title = window->title().toUtf8();232 const auto title = window->title().toUtf8();
@@ -228,6 +238,8 @@
228 mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());238 mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());
229 }239 }
230240
241 mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext);
242
231 if (window->flags() & LowChromeWindowHint) {243 if (window->flags() & LowChromeWindowHint) {
232 mir_surface_spec_set_shell_chrome(spec.get(), mir_shell_chrome_low);244 mir_surface_spec_set_shell_chrome(spec.get(), mir_shell_chrome_low);
233 }245 }
@@ -256,6 +268,10 @@
256268
257} //namespace269} //namespace
258270
271/*
272 * UbuntuSurface - wraps a MirSurface
273 * All units are in pixels only (no device pixels).
274 */
259class UbuntuSurface275class UbuntuSurface
260{276{
261public:277public:
@@ -264,36 +280,26 @@
264 , mPlatformWindow(platformWindow)280 , mPlatformWindow(platformWindow)
265 , mInput(input)281 , mInput(input)
266 , mConnection(connection)282 , mConnection(connection)
267 , mMirSurface(createMirSurface(mWindow, screen, input, connection))
268 , mEglDisplay(screen->eglDisplay())283 , mEglDisplay(screen->eglDisplay())
269 , mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr))
270 , mNeedsRepaint(false)284 , mNeedsRepaint(false)
271 , mParented(mWindow->transientParent() || mWindow->parent())285 , mParented(mWindow->transientParent() || mWindow->parent())
272 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)286 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
273 {287 {
274 mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this);288 mMirSurface = createMirSurface(mWindow, screen, input, connection, surfaceEventCallback, this);
289 mEglSurface = eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr);
275290
276 // Window manager can give us a final size different from what we asked for291 // Window manager can give us a final size different from what we asked for
277 // so let's check what we ended up getting292 // so let's check what we ended up getting
278 MirSurfaceParameters parameters;293 MirSurfaceParameters parameters;
279 mir_surface_get_parameters(mMirSurface, &parameters);294 mir_surface_get_parameters(mMirSurface, &parameters);
280295
281 auto geom = mWindow->geometry();
282 geom.setWidth(parameters.width);
283 geom.setHeight(parameters.height);
284 if (mWindow->windowState() == Qt::WindowFullScreen) {
285 geom.setY(0);
286 } else {
287 geom.setY(panelHeight());
288 }
289
290 // Assume that the buffer size matches the surface size at creation time296 // Assume that the buffer size matches the surface size at creation time
291 mBufferSize = geom.size();297 mBufferSizePx.rwidth() = parameters.width;
292 platformWindow->QPlatformWindow::setGeometry(geom);298 mBufferSizePx.rheight() = parameters.height;
293 QWindowSystemInterface::handleGeometryChange(mWindow, geom);
294299
295 qCDebug(ubuntumirclient, "created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n",300 qCDebug(ubuntumirclient, "created surface with size=(%dx%d)px, title='%s', role=%d",
296 geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow));301 parameters.width, parameters.height, qPrintable(mWindow->title()), roleFor(mWindow));
302 mPlatformWindow->updateWindowSize(parameters.width, parameters.height);
297 }303 }
298304
299 ~UbuntuSurface()305 ~UbuntuSurface()
@@ -304,15 +310,15 @@
304 mir_surface_release_sync(mMirSurface);310 mir_surface_release_sync(mMirSurface);
305 }311 }
306312
307 UbuntuSurface(UbuntuSurface const&) = delete;313 UbuntuSurface(const UbuntuSurface &) = delete;
308 UbuntuSurface& operator=(UbuntuSurface const&) = delete;314 UbuntuSurface& operator=(const UbuntuSurface &) = delete;
309315
310 void resize(const QSize& newSize);316 void resize(const QSize &newSizePx);
311 void updateTitle(const QString& title);317 void updateTitle(const QString &title);
312 void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);318 void setSizingConstraints(const QSize &minSizePx, const QSize &maxSizePx, const QSize &incrementPx);
313319
314 void onSwapBuffersDone();320 void onSwapBuffersDone();
315 void handleSurfaceResized(int width, int height);321 void handleSurfaceResized(int widthPx, int heightPx);
316 int needsRepaint() const;322 int needsRepaint() const;
317323
318 MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); }324 MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); }
@@ -329,7 +335,7 @@
329 bool hasParent() const { return mParented; }335 bool hasParent() const { return mParented; }
330336
331private:337private:
332 static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context);338 static void surfaceEventCallback(MirSurface *surface, const MirEvent *event, void *context);
333 void postEvent(const MirEvent *event);339 void postEvent(const MirEvent *event);
334340
335 QWindow * const mWindow;341 QWindow * const mWindow;
@@ -337,40 +343,40 @@
337 UbuntuInput * const mInput;343 UbuntuInput * const mInput;
338 MirConnection * const mConnection;344 MirConnection * const mConnection;
339345
340 MirSurface * const mMirSurface;346 MirSurface* mMirSurface;
341 const EGLDisplay mEglDisplay;347 const EGLDisplay mEglDisplay;
342 const EGLSurface mEglSurface;348 EGLSurface mEglSurface;
343349
344 bool mNeedsRepaint;350 bool mNeedsRepaint;
345 bool mParented;351 bool mParented;
346 QSize mBufferSize;352 QSize mBufferSizePx;
347353
348 QMutex mTargetSizeMutex;354 QMutex mTargetSizeMutex;
349 QSize mTargetSize;355 QSize mTargetSizePx;
350 MirShellChrome mShellChrome;356 MirShellChrome mShellChrome;
351};357};
352358
353void UbuntuSurface::resize(const QSize& size)359void UbuntuSurface::resize(const QSize &sizePx)
354{360{
355 qCDebug(ubuntumirclient,"resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());361 qCDebug(ubuntumirclient,"resize(window=%p) to (%dx%d)px", mWindow, sizePx.width(), sizePx.height());
356362
357 if (mWindow->windowState() == Qt::WindowFullScreen || mWindow->windowState() == Qt::WindowMaximized) {363 if (mWindow->windowState() == Qt::WindowFullScreen || mWindow->windowState() == Qt::WindowMaximized) {
358 qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);364 qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
359 return;365 return;
360 }366 }
361367
362 if (size.isEmpty()) {368 if (sizePx.isEmpty()) {
363 qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, size is empty", mWindow);369 qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, size is empty", mWindow);
364 return;370 return;
365 }371 }
366372
367 Spec spec{mir_connection_create_spec_for_changes(mConnection)};373 Spec spec{mir_connection_create_spec_for_changes(mConnection)};
368 mir_surface_spec_set_width(spec.get(), size.width());374 mir_surface_spec_set_width(spec.get(), sizePx.width());
369 mir_surface_spec_set_height(spec.get(), size.height());375 mir_surface_spec_set_height(spec.get(), sizePx.height());
370 mir_surface_apply_spec(mMirSurface, spec.get());376 mir_surface_apply_spec(mMirSurface, spec.get());
371}377}
372378
373void UbuntuSurface::updateTitle(const QString& newTitle)379void UbuntuSurface::updateTitle(const QString &newTitle)
374{380{
375 const auto title = newTitle.toUtf8();381 const auto title = newTitle.toUtf8();
376 Spec spec{mir_connection_create_spec_for_changes(mConnection)};382 Spec spec{mir_connection_create_spec_for_changes(mConnection)};
@@ -378,14 +384,14 @@
378 mir_surface_apply_spec(mMirSurface, spec.get());384 mir_surface_apply_spec(mMirSurface, spec.get());
379}385}
380386
381void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment)387void UbuntuSurface::setSizingConstraints(const QSize &minSizePx, const QSize &maxSizePx, const QSize &incrementPx)
382{388{
383 Spec spec{mir_connection_create_spec_for_changes(mConnection)};389 Spec spec{mir_connection_create_spec_for_changes(mConnection)};
384 ::setSizingConstraints(spec.get(), minSize, maxSize, increment);390 ::setSizingConstraints(spec.get(), minSizePx, maxSizePx, incrementPx);
385 mir_surface_apply_spec(mMirSurface, spec.get());391 mir_surface_apply_spec(mMirSurface, spec.get());
386}392}
387393
388void UbuntuSurface::handleSurfaceResized(int width, int height)394void UbuntuSurface::handleSurfaceResized(int widthPx, int heightPx)
389{395{
390 QMutexLocker lock(&mTargetSizeMutex);396 QMutexLocker lock(&mTargetSizeMutex);
391397
@@ -395,13 +401,13 @@
395 // see TODO in postEvent as the ideal way we should handle this.401 // see TODO in postEvent as the ideal way we should handle this.
396 // The actual buffer size may or may have not changed at this point, so let the rendering402 // The actual buffer size may or may have not changed at this point, so let the rendering
397 // thread drive the window geometry updates.403 // thread drive the window geometry updates.
398 mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height;404 mNeedsRepaint = mTargetSizePx.width() == widthPx && mTargetSizePx.height() == heightPx;
399}405}
400406
401int UbuntuSurface::needsRepaint() const407int UbuntuSurface::needsRepaint() const
402{408{
403 if (mNeedsRepaint) {409 if (mNeedsRepaint) {
404 if (mTargetSize != mBufferSize) {410 if (mTargetSizePx != mBufferSizePx) {
405 //If the buffer hasn't changed yet, we need at least two redraws,411 //If the buffer hasn't changed yet, we need at least two redraws,
406 //once to get the new buffer size and propagate the geometry changes412 //once to get the new buffer size and propagate the geometry changes
407 //and the second to redraw the content at the new size413 //and the second to redraw the content at the new size
@@ -436,29 +442,25 @@
436 static int sFrameNumber = 0;442 static int sFrameNumber = 0;
437 ++sFrameNumber;443 ++sFrameNumber;
438444
439 EGLint eglSurfaceWidth = -1;445 EGLint eglSurfaceWidthPx = -1;
440 EGLint eglSurfaceHeight = -1;446 EGLint eglSurfaceHeightPx = -1;
441 eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth);447 eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidthPx);
442 eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight);448 eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeightPx);
443449
444 const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0;450 const bool validSize = eglSurfaceWidthPx > 0 && eglSurfaceHeightPx > 0;
445451
446 if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {452 if (validSize && (mBufferSizePx.width() != eglSurfaceWidthPx || mBufferSizePx.height() != eglSurfaceHeightPx)) {
447453
448 qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",454 qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size changed (%dx%d)px => (%dx%d)px",
449 mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);455 mWindow, sFrameNumber, mBufferSizePx.width(), mBufferSizePx.height(), eglSurfaceWidthPx, eglSurfaceHeightPx);
450456
451 mBufferSize.rwidth() = eglSurfaceWidth;457 mBufferSizePx.rwidth() = eglSurfaceWidthPx;
452 mBufferSize.rheight() = eglSurfaceHeight;458 mBufferSizePx.rheight() = eglSurfaceHeightPx;
453459
454 QRect newGeometry = mPlatformWindow->geometry();460 mPlatformWindow->updateWindowSize(eglSurfaceWidthPx, eglSurfaceHeightPx);
455 newGeometry.setSize(mBufferSize);
456
457 mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
458 QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
459 } else {461 } else {
460 qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",462 qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size=(%dx%d)px",
461 mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());463 mWindow, sFrameNumber, mBufferSizePx.width(), mBufferSizePx.height());
462 }464 }
463}465}
464466
@@ -479,13 +481,13 @@
479 // As a workaround, we use the width/height as an identifier of this latest event481 // As a workaround, we use the width/height as an identifier of this latest event
480 // so the event handler (handleSurfaceResized) can discard/ignore old ones.482 // so the event handler (handleSurfaceResized) can discard/ignore old ones.
481 const auto resizeEvent = mir_event_get_resize_event(event);483 const auto resizeEvent = mir_event_get_resize_event(event);
482 const auto width = mir_resize_event_get_width(resizeEvent);484 const auto widthPx = mir_resize_event_get_width(resizeEvent);
483 const auto height = mir_resize_event_get_height(resizeEvent);485 const auto heightPx = mir_resize_event_get_height(resizeEvent);
484 qCDebug(ubuntumirclient, "resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);486 qCDebug(ubuntumirclient, "resizeEvent(window=%p, size=(%dx%d)px", mWindow, widthPx, heightPx);
485487
486 QMutexLocker lock(&mTargetSizeMutex);488 QMutexLocker lock(&mTargetSizeMutex);
487 mTargetSize.rwidth() = width;489 mTargetSizePx.rwidth() = widthPx;
488 mTargetSize.rheight() = height;490 mTargetSizePx.rheight() = heightPx;
489 }491 }
490492
491 mInput->postEvent(mPlatformWindow, event);493 mInput->postEvent(mPlatformWindow, event);
@@ -501,8 +503,8 @@
501 mir_surface_apply_spec(mMirSurface, spec.get());503 mir_surface_apply_spec(mMirSurface, spec.get());
502}504}
503505
504UbuntuWindow::UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard, UbuntuScreen *screen,506UbuntuWindow::UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard,
505 UbuntuInput *input, MirConnection *connection)507 UbuntuInput *input, UbuntuNativeInterface *native, MirConnection *connection)
506 : QObject(nullptr)508 : QObject(nullptr)
507 , QPlatformWindow(w)509 , QPlatformWindow(w)
508 , mId(makeId())510 , mId(makeId())
@@ -510,9 +512,16 @@
510 , mWindowState(w->windowState())512 , mWindowState(w->windowState())
511 , mWindowFlags(w->flags())513 , mWindowFlags(w->flags())
512 , mWindowVisible(false)514 , mWindowVisible(false)
513 , mSurface(new UbuntuSurface{this, screen, input, connection})515 , mWindowExposed(true)
516 , mNativeInterface(native)
517 , mSurface(new UbuntuSurface{this, static_cast<UbuntuScreen*>(w->screen()->handle()), input, connection})
518 , mScale(1.0)
519 , mFormFactor(mir_form_factor_unknown)
514{520{
515 qCDebug(ubuntumirclient, "UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());521 qCDebug(ubuntumirclient, "UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p) with title '%s', role: '%d'",
522 w, w->screen()->handle(), input, mSurface.get(), qPrintable(window()->title()), roleFor(window()));
523
524 enablePanelHeightHack(w->windowState() != Qt::WindowFullScreen);
516}525}
517526
518UbuntuWindow::~UbuntuWindow()527UbuntuWindow::~UbuntuWindow()
@@ -520,12 +529,25 @@
520 qCDebug(ubuntumirclient, "~UbuntuWindow(window=%p)", this);529 qCDebug(ubuntumirclient, "~UbuntuWindow(window=%p)", this);
521}530}
522531
523void UbuntuWindow::handleSurfaceResized(int width, int height)532void UbuntuWindow::updateWindowSize(int widthPx, int heightPx) // after when Mir has resized the surface
533{
534 const float dpr = devicePixelRatio();
535 auto geom = geometry();
536 geom.setWidth(divideAndRoundUp(widthPx, dpr));
537 geom.setHeight(divideAndRoundUp(heightPx, dpr));
538
539 QPlatformWindow::setGeometry(geom);
540 QWindowSystemInterface::handleGeometryChange(window(), geom);
541
542 qCDebug(ubuntumirclient) << "Surface geometry updated:" << geom;
543}
544
545void UbuntuWindow::handleSurfaceResized(int widthPx, int heightPx)
524{546{
525 QMutexLocker lock(&mMutex);547 QMutexLocker lock(&mMutex);
526 qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height);548 qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), widthPx, heightPx);
527549
528 mSurface->handleSurfaceResized(width, height);550 mSurface->handleSurfaceResized(widthPx, heightPx);
529551
530 // This resize event could have occurred just after the last buffer swap for this window.552 // This resize event could have occurred just after the last buffer swap for this window.
531 // This means the client may still be holding a buffer with the older size. The first redraw call553 // This means the client may still be holding a buffer with the older size. The first redraw call
@@ -536,11 +558,23 @@
536 lock.unlock();558 lock.unlock();
537 qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);559 qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
538 for (int i = 0; i < numRepaints; i++) {560 for (int i = 0; i < numRepaints; i++) {
539 qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());561 qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) repainting size=(%dx%d)dp", window(), geometry().size().width(), geometry().size().height());
540 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));562 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
541 }563 }
542}564}
543565
566void UbuntuWindow::handleSurfaceExposeChange(bool exposed)
567{
568 QMutexLocker lock(&mMutex);
569 qCDebug(ubuntumirclient, "handleSurfaceExposeChange(window=%p, exposed=%s)", window(), exposed ? "true" : "false");
570
571 if (mWindowExposed == exposed) return;
572 mWindowExposed = exposed;
573
574 lock.unlock();
575 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
576}
577
544void UbuntuWindow::handleSurfaceFocused()578void UbuntuWindow::handleSurfaceFocused()
545{579{
546 qCDebug(ubuntumirclient, "handleSurfaceFocused(window=%p)", window());580 qCDebug(ubuntumirclient, "handleSurfaceFocused(window=%p)", window());
@@ -621,19 +655,19 @@
621 }655 }
622}656}
623657
624void UbuntuWindow::setGeometry(const QRect& rect)658void UbuntuWindow::setGeometry(const QRect &rect)
625{659{
626 QMutexLocker lock(&mMutex);660 QMutexLocker lock(&mMutex);
627 qCDebug(ubuntumirclient, "setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)",661 qCDebug(ubuntumirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)",
628 window(), rect.x(), rect.y(), rect.width(), rect.height());662 window(), rect.x(), rect.y(), rect.width(), rect.height());
629663
630 //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates664 //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates
631 const auto newSize = rect.size();665 const auto newSize = rect.size();
632 auto newGeometry = geometry();666 auto newGeometry = geometry();
633 newGeometry.setSize(newSize);667 newGeometry.setSize(newSize);
634 QPlatformWindow::setGeometry(newGeometry);
635668
636 mSurface->resize(newSize);669 mSurface->resize(newSize * devicePixelRatio());
670 // Note: don't call handleGeometryChange here, wait to see what Mir replies with.
637}671}
638672
639void UbuntuWindow::setVisible(bool visible)673void UbuntuWindow::setVisible(bool visible)
@@ -658,10 +692,9 @@
658 lock.unlock();692 lock.unlock();
659 updateSurfaceState();693 updateSurfaceState();
660 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));694 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
661 QWindowSystemInterface::flushWindowSystemEvents();
662}695}
663696
664void UbuntuWindow::setWindowTitle(const QString& title)697void UbuntuWindow::setWindowTitle(const QString &title)
665{698{
666 QMutexLocker lock(&mMutex);699 QMutexLocker lock(&mMutex);
667 qCDebug(ubuntumirclient, "setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());700 qCDebug(ubuntumirclient, "setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
@@ -672,16 +705,22 @@
672{705{
673 QMutexLocker lock(&mMutex);706 QMutexLocker lock(&mMutex);
674 const auto win = window();707 const auto win = window();
675 qCDebug(ubuntumirclient, "propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",708 const float dpr = devicePixelRatio();
676 win, win->minimumSize().width(), win->minimumSize().height(),709 qCDebug(ubuntumirclient, "propagateSizeHints(window=%p) min(%dx%d)dp; max(%dx%d)dp; increment(%dx%d)dp",
677 win->maximumSize().width(), win->maximumSize().height(),710 win, win->minimumSize().width(), win->minimumSize().height(),
678 win->sizeIncrement().width(), win->sizeIncrement().height());711 win->maximumSize().width(), win->maximumSize().height(),
679 mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement());712 win->sizeIncrement().width(), win->sizeIncrement().height());
713 mSurface->setSizingConstraints(win->minimumSize() * dpr, win->maximumSize() * dpr, win->sizeIncrement() * dpr);
714}
715
716qreal UbuntuWindow::devicePixelRatio() const
717{
718 return screen() ? screen()->devicePixelRatio() : 1.0; // not impossible a Window has no attached Screen
680}719}
681720
682bool UbuntuWindow::isExposed() const721bool UbuntuWindow::isExposed() const
683{722{
684 return mWindowVisible;723 return mWindowVisible && mWindowExposed;
685}724}
686725
687void* UbuntuWindow::eglSurface() const726void* UbuntuWindow::eglSurface() const
@@ -705,6 +744,21 @@
705 mSurface->onSwapBuffersDone();744 mSurface->onSwapBuffersDone();
706}745}
707746
747void UbuntuWindow::handleScreenPropertiesChange(MirFormFactor formFactor, float scale)
748{
749 // Update the scale & form factor native-interface properties for the windows affected
750 // as there is no convenient way to emit signals for those custom properties on a QScreen
751 if (formFactor != mFormFactor) {
752 mFormFactor = formFactor;
753 Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("formFactor"));
754 }
755
756 if (!qFuzzyCompare(scale, mScale)) {
757 mScale = scale;
758 Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("scale"));
759 }
760}
761
708void UbuntuWindow::updateSurfaceState()762void UbuntuWindow::updateSurfaceState()
709{763{
710 QMutexLocker lock(&mMutex);764 QMutexLocker lock(&mMutex);
711765
=== modified file 'src/ubuntumirclient/window.h'
--- src/ubuntumirclient/window.h 2016-02-18 15:45:21 +0000
+++ src/ubuntumirclient/window.h 2016-04-20 15:51:01 +0000
@@ -18,13 +18,15 @@
18#define UBUNTU_WINDOW_H18#define UBUNTU_WINDOW_H
1919
20#include <qpa/qplatformwindow.h>20#include <qpa/qplatformwindow.h>
21#include <QLoggingCategory>
22#include <QSharedPointer>21#include <QSharedPointer>
23#include <QMutex>22#include <QMutex>
2423
24#include <mir_toolkit/common.h> // needed only for MirFormFactor enum
25
25#include <memory>26#include <memory>
2627
27class UbuntuClipboard;28class UbuntuClipboard;
29class UbuntuNativeInterface;
28class UbuntuInput;30class UbuntuInput;
29class UbuntuScreen;31class UbuntuScreen;
30class UbuntuSurface;32class UbuntuSurface;
@@ -35,8 +37,8 @@
35{37{
36 Q_OBJECT38 Q_OBJECT
37public:39public:
38 UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard, UbuntuScreen *screen,40 UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard,
39 UbuntuInput *input, MirConnection *mirConnection);41 UbuntuInput *input, UbuntuNativeInterface* native, MirConnection *mirConnection);
40 virtual ~UbuntuWindow();42 virtual ~UbuntuWindow();
4143
42 // QPlatformWindow methods.44 // QPlatformWindow methods.
@@ -48,28 +50,38 @@
48 void setWindowTitle(const QString &title) override;50 void setWindowTitle(const QString &title) override;
49 void propagateSizeHints() override;51 void propagateSizeHints() override;
50 bool isExposed() const override;52 bool isExposed() const override;
53 qreal devicePixelRatio() const override;
54
55 // Additional Window properties exposed by NativeInterface
56 MirFormFactor formFactor() const { return mFormFactor; }
57 float scale() const { return mScale; }
5158
52 // New methods.59 // New methods.
53 void *eglSurface() const;60 void *eglSurface() const;
54 MirSurface *mirSurface() const;61 MirSurface *mirSurface() const;
55 void handleSurfaceResized(int width, int height);62 void updateWindowSize(int widthPx, int heightPx);
63 void handleSurfaceResized(int widthPx, int heightPx);
64 void handleSurfaceExposeChange(bool exposed);
56 void handleSurfaceFocused();65 void handleSurfaceFocused();
57 void handleSurfaceVisibilityChanged(bool visible);66 void handleSurfaceVisibilityChanged(bool visible);
58 void handleSurfaceStateChanged(Qt::WindowState state);67 void handleSurfaceStateChanged(Qt::WindowState state);
59 void onSwapBuffersDone();68 void onSwapBuffersDone();
69 void handleScreenPropertiesChange(MirFormFactor formFactor, float scale);
6070
61private:71private:
62 void enablePanelHeightHack(bool enable);72 void enablePanelHeightHack(bool enable);
63 void updateSurfaceState();73 void updateSurfaceState();
64
65 mutable QMutex mMutex;74 mutable QMutex mMutex;
66 const WId mId;75 const WId mId;
67 const QSharedPointer<UbuntuClipboard> mClipboard;76 const QSharedPointer<UbuntuClipboard> mClipboard;
68 Qt::WindowState mWindowState;77 Qt::WindowState mWindowState;
69 Qt::WindowFlags mWindowFlags;78 Qt::WindowFlags mWindowFlags;
70 bool mWindowVisible;79 bool mWindowVisible;
7180 bool mWindowExposed;
81 UbuntuNativeInterface *mNativeInterface;
72 std::unique_ptr<UbuntuSurface> mSurface;82 std::unique_ptr<UbuntuSurface> mSurface;
83 float mScale;
84 MirFormFactor mFormFactor;
73};85};
7486
75#endif // UBUNTU_WINDOW_H87#endif // UBUNTU_WINDOW_H

Subscribers

People subscribed via source and target branches