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

Proposed by Michał Sawicz on 2016-02-17
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 on 2016-04-20
Ubuntu Phablet Team 2016-02-17 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.
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 on 2016-04-20

Merge trunk

328. By Nick Dedekind on 2016-02-18

remerge

327. By Nick Dedekind on 2016-02-18

merged with parent

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ubuntumirclient/backingstore.cpp'
2--- src/ubuntumirclient/backingstore.cpp 2014-12-04 12:29:39 +0000
3+++ src/ubuntumirclient/backingstore.cpp 2016-04-20 15:51:01 +0000
4@@ -1,5 +1,5 @@
5 /*
6- * Copyright (C) 2014 Canonical, Ltd.
7+ * Copyright (C) 2014-2015 Canonical, Ltd.
8 *
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU Lesser General Public License version 3, as published by
11@@ -43,8 +43,10 @@
12 {
13 Q_UNUSED(region);
14 Q_UNUSED(offset);
15+ const int dpr = int(window->devicePixelRatio());
16+
17 mContext->makeCurrent(window);
18- glViewport(0, 0, window->width(), window->height());
19+ glViewport(0, 0, window->width() * dpr, window->height() * dpr);
20
21 updateTexture();
22
23@@ -75,12 +77,14 @@
24
25 QRegion fixed;
26 QRect imageRect = mImage.rect();
27+ const int dpr = int(window()->devicePixelRatio());
28
29- /* Following code taken from QEGLPlatformBackingStore under the terms of the Lesser GPL v2.1 licence
30+ /* Following code a modified form of that in QEGLPlatformBackingStore, used under the terms of the Lesser GPL v2.1 licence
31 * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). */
32 Q_FOREACH (const QRect &rect, mDirty.rects()) {
33+ QRect scaledRect(rect.topLeft() * dpr, rect.size() * dpr);
34 // intersect with image rect to be sure
35- QRect r = imageRect & rect;
36+ QRect r = imageRect & scaledRect;
37
38 // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy
39 if (r.width() >= imageRect.width() / 2) {
40@@ -115,7 +119,9 @@
41
42 void UbuntuBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/)
43 {
44- mImage = QImage(size, QImage::Format_RGB32);
45+ const int dpr = int(window()->devicePixelRatio());
46+ mImage = QImage(size * dpr, QImage::Format_RGB32);
47+ mImage.setDevicePixelRatio(dpr);
48
49 if (mTexture->isCreated())
50 mTexture->destroy();
51
52=== modified file 'src/ubuntumirclient/input.cpp'
53--- src/ubuntumirclient/input.cpp 2016-03-22 08:49:43 +0000
54+++ src/ubuntumirclient/input.cpp 2016-04-20 15:51:01 +0000
55@@ -224,6 +224,8 @@
56 return "mir_event_type_close_surface";
57 case mir_event_type_input:
58 return "mir_event_type_input";
59+ case mir_event_type_surface_output:
60+ return "mir_event_type_surface_output";
61 default:
62 return "invalid";
63 }
64@@ -259,55 +261,26 @@
65 break;
66 case mir_event_type_resize:
67 {
68- Q_ASSERT(ubuntuEvent->window->screen() == mIntegration->screen());
69-
70 auto resizeEvent = mir_event_get_resize_event(nativeEvent);
71
72- mIntegration->screen()->handleWindowSurfaceResize(
73- mir_resize_event_get_width(resizeEvent),
74- mir_resize_event_get_height(resizeEvent));
75+ // Enable workaround for Screen rotation
76+ auto screen = static_cast<UbuntuScreen*>(ubuntuEvent->window->screen());
77+ if (screen) {
78+ screen->handleWindowSurfaceResize(
79+ mir_resize_event_get_width(resizeEvent),
80+ mir_resize_event_get_height(resizeEvent));
81+ }
82
83 ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent),
84 mir_resize_event_get_height(resizeEvent));
85 break;
86 }
87 case mir_event_type_surface:
88- {
89- auto surfaceEvent = mir_event_get_surface_event(nativeEvent);
90- auto surfaceEventAttribute = mir_surface_event_get_attribute(surfaceEvent);
91-
92- if (surfaceEventAttribute == mir_surface_attrib_focus) {
93- const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
94- // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
95- // so that we don't deactivate windows prematurely.
96- if (focused) {
97- mPendingFocusGainedEvents--;
98- ubuntuEvent->window->handleSurfaceFocused();
99- QWindowSystemInterface::handleWindowActivated(ubuntuEvent->window->window(), Qt::ActiveWindowFocusReason);
100-
101- // NB: Since processing of system events is queued, never check qGuiApp->applicationState()
102- // as it might be outdated. Always call handleApplicationStateChanged() with the latest
103- // state regardless.
104- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
105-
106- } else if(!mPendingFocusGainedEvents) {
107- qCDebug(ubuntumirclient, "No windows have focus");
108- QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
109- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
110- }
111- } else if (surfaceEventAttribute == mir_surface_attrib_state) {
112- MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(surfaceEvent));
113-
114- if (state == mir_surface_state_hidden) {
115- ubuntuEvent->window->handleSurfaceVisibilityChanged(false);
116- } else {
117- // it's visible!
118- ubuntuEvent->window->handleSurfaceVisibilityChanged(true);
119- ubuntuEvent->window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state));
120- }
121- }
122- break;
123- }
124+ handleSurfaceEvent(ubuntuEvent->window, mir_event_get_surface_event(nativeEvent));
125+ break;
126+ case mir_event_type_surface_output:
127+ handleSurfaceOutputEvent(ubuntuEvent->window, mir_event_get_surface_output_event(nativeEvent));
128+ break;
129 case mir_event_type_orientation:
130 dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent));
131 break;
132@@ -372,6 +345,7 @@
133 const QRect kWindowGeometry = window->geometry();
134 QList<QWindowSystemInterface::TouchPoint> touchPoints;
135
136+ const int dpr = int(window->devicePixelRatio());
137
138 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
139 // as Qt::TouchPointMoved
140@@ -379,10 +353,10 @@
141 for (unsigned int i = 0; i < kPointerCount; ++i) {
142 QWindowSystemInterface::TouchPoint touchPoint;
143
144- const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) + kWindowGeometry.x();
145- const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere
146- const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);
147- const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);
148+ const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) / dpr + kWindowGeometry.x();
149+ const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) / dpr + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere
150+ const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major) / dpr;
151+ const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor) / dpr;
152 const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);
153 touchPoint.id = mir_touch_event_id(tev, i);
154 touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());
155@@ -525,14 +499,16 @@
156
157 void UbuntuInput::dispatchPointerEvent(UbuntuWindow *platformWindow, const MirInputEvent *ev)
158 {
159- auto window = platformWindow->window();
160- auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
161-
162- auto pev = mir_input_event_get_pointer_event(ev);
163- auto action = mir_pointer_event_action(pev);
164- auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
165- mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
166- auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
167+ const int dpr = int(platformWindow->devicePixelRatio());
168+ const auto window = platformWindow->window();
169+ const auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
170+
171+ const auto pev = mir_input_event_get_pointer_event(ev);
172+ const auto action = mir_pointer_event_action(pev);
173+
174+ const auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
175+ const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x) / dpr,
176+ mir_pointer_event_axis_value(pev, mir_pointer_axis_y) / dpr);
177
178 switch (action) {
179 case mir_pointer_action_button_up:
180@@ -620,3 +596,75 @@
181 new OrientationChangeEvent(OrientationChangeEvent::mType, orientation));
182 }
183
184+void UbuntuInput::handleSurfaceEvent(const QPointer<UbuntuWindow> &window, const MirSurfaceEvent *event)
185+{
186+ auto surfaceEventAttribute = mir_surface_event_get_attribute(event);
187+
188+ switch (surfaceEventAttribute) {
189+ case mir_surface_attrib_focus: {
190+ const bool focused = mir_surface_event_get_attribute_value(event) == mir_surface_focused;
191+ // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
192+ // so that we don't deactivate windows prematurely.
193+ if (focused) {
194+ mPendingFocusGainedEvents--;
195+ window->handleSurfaceFocused();
196+ QWindowSystemInterface::handleWindowActivated(window->window(), Qt::ActiveWindowFocusReason);
197+
198+ // NB: Since processing of system events is queued, never check qGuiApp->applicationState()
199+ // as it might be outdated. Always call handleApplicationStateChanged() with the latest
200+ // state regardless.
201+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
202+
203+ } else if(!mPendingFocusGainedEvents) {
204+ qCDebug(ubuntumirclient, "No windows have focus");
205+ QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
206+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
207+ }
208+ break;
209+ }
210+ case mir_surface_attrib_visibility:
211+ window->handleSurfaceExposeChange(
212+ mir_surface_event_get_attribute_value(event) == mir_surface_visibility_exposed);
213+ break;
214+ // Remaining attributes are ones client sets for server, and server should not override them
215+ case mir_surface_attrib_state: {
216+ MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(event));
217+ if (state == mir_surface_state_hidden) {
218+ window->handleSurfaceVisibilityChanged(false);
219+ } else {
220+ // it's visible!
221+ window->handleSurfaceVisibilityChanged(true);
222+ window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state));
223+ }
224+ break;
225+ }
226+ case mir_surface_attrib_type:
227+ case mir_surface_attrib_swapinterval:
228+ case mir_surface_attrib_dpi:
229+ case mir_surface_attrib_preferred_orientation:
230+ case mir_surface_attribs:
231+ break;
232+ }
233+}
234+
235+void UbuntuInput::handleSurfaceOutputEvent(const QPointer<UbuntuWindow> &window, const MirSurfaceOutputEvent *event)
236+{
237+ const uint32_t outputId = mir_surface_output_event_get_output_id(event);
238+ const int dpi = mir_surface_output_event_get_dpi(event);
239+ const MirFormFactor formFactor = mir_surface_output_event_get_form_factor(event);
240+ const float scale = mir_surface_output_event_get_scale(event);
241+
242+ const auto screenObserver = mIntegration->screenObserver();
243+ UbuntuScreen *screen = screenObserver->findScreenWithId(outputId);
244+ if (!screen) {
245+ qWarning() << "Mir notified window" << window->window() << "on an unknown screen with id" << outputId;
246+ return;
247+ }
248+
249+ screenObserver->handleScreenPropertiesChange(screen, dpi, formFactor, scale);
250+ window->handleScreenPropertiesChange(formFactor, scale);
251+
252+ if (window->screen() != screen) {
253+ QWindowSystemInterface::handleWindowScreenChanged(window->window(), screen->screen());
254+ }
255+}
256
257=== modified file 'src/ubuntumirclient/input.h'
258--- src/ubuntumirclient/input.h 2015-12-09 13:02:07 +0000
259+++ src/ubuntumirclient/input.h 2016-04-20 15:51:01 +0000
260@@ -49,6 +49,8 @@
261 void dispatchInputEvent(UbuntuWindow *window, const MirInputEvent *event);
262
263 void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event);
264+ void handleSurfaceEvent(const QPointer<UbuntuWindow> &window, const MirSurfaceEvent *event);
265+ void handleSurfaceOutputEvent(const QPointer<UbuntuWindow> &window, const MirSurfaceOutputEvent *event);
266
267 private:
268 UbuntuClientIntegration* mIntegration;
269
270=== modified file 'src/ubuntumirclient/integration.cpp'
271--- src/ubuntumirclient/integration.cpp 2016-01-04 17:18:51 +0000
272+++ src/ubuntumirclient/integration.cpp 2016-04-20 15:51:01 +0000
273@@ -88,19 +88,26 @@
274 "rejected the incoming connection, so check its log file");
275
276 mNativeInterface->setMirConnection(u_application_instance_get_mir_connection(mInstance));
277-
278- // Create default screen.
279- mScreen = new UbuntuScreen(u_application_instance_get_mir_connection(mInstance));
280- screenAdded(mScreen);
281+}
282+
283+void UbuntuClientIntegration::initialize()
284+{
285+ MirConnection *mirConnection = u_application_instance_get_mir_connection(mInstance);
286+
287+ // Init the ScreenObserver
288+ mScreenObserver.reset(new UbuntuScreenObserver(mirConnection));
289+ connect(mScreenObserver.data(), &UbuntuScreenObserver::screenAdded,
290+ [this](UbuntuScreen *screen) { this->screenAdded(screen); });
291+ connect(mScreenObserver.data(), &UbuntuScreenObserver::screenRemoved,
292+ this, &UbuntuClientIntegration::destroyScreen);
293+
294+ Q_FOREACH(auto screen, mScreenObserver->screens()) {
295+ screenAdded(screen);
296+ }
297
298 // Initialize input.
299- if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_INPUT")) {
300- mInput = new UbuntuInput(this);
301- mInputContext = QPlatformInputContextFactory::create();
302- } else {
303- mInput = nullptr;
304- mInputContext = nullptr;
305- }
306+ mInput = new UbuntuInput(this);
307+ mInputContext = QPlatformInputContextFactory::create();
308
309 // compute the scale factor
310 const int defaultGridUnit = 8;
311@@ -120,7 +127,6 @@
312 {
313 delete mInput;
314 delete mInputContext;
315- delete mScreen;
316 delete mServices;
317 }
318
319@@ -165,8 +171,8 @@
320
321 QPlatformWindow* UbuntuClientIntegration::createPlatformWindow(QWindow* window)
322 {
323- return new UbuntuWindow(window, mClipboard, static_cast<UbuntuScreen*>(mScreen),
324- mInput, u_application_instance_get_mir_connection(mInstance));
325+ return new UbuntuWindow(window, mClipboard, mInput, mNativeInterface,
326+ u_application_instance_get_mir_connection(mInstance));
327 }
328
329 bool UbuntuClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const
330@@ -262,3 +268,34 @@
331 {
332 return new UbuntuOffscreenSurface(surface);
333 }
334+
335+void UbuntuClientIntegration::destroyScreen(UbuntuScreen *screen)
336+{
337+ // FIXME: on deleting a screen while a Window is on it, Qt will automatically
338+ // move the window to the primaryScreen(). This will trigger a screenChanged
339+ // signal, causing things like QQuickScreenAttached to re-fetch screen properties
340+ // like DPI and physical size. However this is crashing, as Qt is calling virtual
341+ // functions on QPlatformScreen, for reasons unclear. As workaround, move window
342+ // to primaryScreen() before deleting the screen. Might be QTBUG-38650
343+
344+ QScreen *primaryScreen = QGuiApplication::primaryScreen();
345+ if (screen != primaryScreen->handle()) {
346+ uint32_t movedWindowCount = 0;
347+ Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) {
348+ if (w->screen()->handle() == screen) {
349+ QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen);
350+ ++movedWindowCount;
351+ }
352+ }
353+ if (movedWindowCount > 0) {
354+ QWindowSystemInterface::flushWindowSystemEvents();
355+ }
356+ }
357+
358+ qDebug() << "Removing Screen with id" << screen->outputId() << "and geometry" << screen->geometry();
359+#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
360+ delete screen;
361+#else
362+ this->destroyScreen(screen);
363+#endif
364+}
365
366=== modified file 'src/ubuntumirclient/integration.h'
367--- src/ubuntumirclient/integration.h 2016-01-04 17:18:51 +0000
368+++ src/ubuntumirclient/integration.h 2016-04-20 15:51:01 +0000
369@@ -21,6 +21,7 @@
370 #include <QSharedPointer>
371
372 #include "platformservices.h"
373+#include "screenobserver.h"
374
375 // platform-api
376 #include <ubuntu/application/description.h>
377@@ -31,7 +32,10 @@
378 class UbuntuNativeInterface;
379 class UbuntuScreen;
380
381-class UbuntuClientIntegration : public QPlatformIntegration {
382+class UbuntuClientIntegration : public QObject, public QPlatformIntegration
383+{
384+ Q_OBJECT
385+
386 public:
387 UbuntuClientIntegration();
388 virtual ~UbuntuClientIntegration();
389@@ -53,10 +57,15 @@
390
391 QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context);
392 QPlatformWindow* createPlatformWindow(QWindow* window);
393- UbuntuScreen* screen() const { return mScreen; }
394+ UbuntuScreenObserver *screenObserver() const { return mScreenObserver.data(); }
395+
396+ void initialize() override;
397
398 QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
399
400+private Q_SLOTS:
401+ void destroyScreen(UbuntuScreen *screen);
402+
403 private:
404 void setupOptions();
405 void setupDescription();
406@@ -66,10 +75,10 @@
407
408 UbuntuPlatformServices* mServices;
409
410- UbuntuScreen* mScreen;
411 UbuntuInput* mInput;
412 QPlatformInputContext* mInputContext;
413 QSharedPointer<UbuntuClipboard> mClipboard;
414+ QScopedPointer<UbuntuScreenObserver> mScreenObserver;
415 qreal mScaleFactor;
416
417 // Platform API stuff
418
419=== modified file 'src/ubuntumirclient/nativeinterface.cpp'
420--- src/ubuntumirclient/nativeinterface.cpp 2015-12-15 16:16:06 +0000
421+++ src/ubuntumirclient/nativeinterface.cpp 2016-04-20 15:51:01 +0000
422@@ -18,6 +18,7 @@
423 #include "nativeinterface.h"
424 #include "screen.h"
425 #include "glcontext.h"
426+#include "window.h"
427
428 // Qt
429 #include <private/qguiapplication_p.h>
430@@ -35,6 +36,8 @@
431 insert("nativeorientation", UbuntuNativeInterface::NativeOrientation);
432 insert("display", UbuntuNativeInterface::Display);
433 insert("mirconnection", UbuntuNativeInterface::MirConnection);
434+ insert("scale", UbuntuNativeInterface::Scale);
435+ insert("formfactor", UbuntuNativeInterface::FormFactor);
436 }
437 };
438
439@@ -123,10 +126,59 @@
440 if (!ubuntuResourceMap()->contains(kLowerCaseResource))
441 return NULL;
442 const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
443+ if (!screen)
444+ screen = QGuiApplication::primaryScreen();
445+ auto ubuntuScreen = static_cast<UbuntuScreen*>(screen->handle());
446 if (kResourceType == UbuntuNativeInterface::Display) {
447- if (!screen)
448- screen = QGuiApplication::primaryScreen();
449- return static_cast<UbuntuScreen*>(screen->handle())->eglNativeDisplay();
450+ return ubuntuScreen->eglNativeDisplay();
451+ // Changes to the following properties are emitted via the UbuntuNativeInterface::screenPropertyChanged
452+ // signal fired by UbuntuScreen. Connect to this signal for these properties updates.
453+ // WARNING: code highly thread unsafe!
454+ } else if (kResourceType == UbuntuNativeInterface::Scale) {
455+ // In application code, read with:
456+ // float scale = *reinterpret_cast<float*>(nativeResourceForScreen("scale", screen()));
457+ return &ubuntuScreen->mScale;
458+ } else if (kResourceType == UbuntuNativeInterface::FormFactor) {
459+ return &ubuntuScreen->mFormFactor;
460 } else
461 return NULL;
462 }
463+
464+// Changes to these properties are emitted via the UbuntuNativeInterface::windowPropertyChanged
465+// signal fired by UbuntuWindow. Connect to this signal for these properties updates.
466+QVariantMap UbuntuNativeInterface::windowProperties(QPlatformWindow *window) const
467+{
468+ QVariantMap propertyMap;
469+ auto w = static_cast<UbuntuWindow*>(window);
470+ if (w) {
471+ propertyMap.insert("scale", w->scale());
472+ propertyMap.insert("formFactor", w->formFactor());
473+ }
474+ return propertyMap;
475+}
476+
477+QVariant UbuntuNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const
478+{
479+ auto w = static_cast<UbuntuWindow*>(window);
480+ if (!w) {
481+ return QVariant();
482+ }
483+
484+ if (name == QStringLiteral("scale")) {
485+ return w->scale();
486+ } else if (name == QStringLiteral("formFactor")) {
487+ return w->formFactor();
488+ } else {
489+ return QVariant();
490+ }
491+}
492+
493+QVariant UbuntuNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const
494+{
495+ QVariant returnVal = windowProperty(window, name);
496+ if (!returnVal.isValid()) {
497+ return defaultValue;
498+ } else {
499+ return returnVal;
500+ }
501+}
502
503=== modified file 'src/ubuntumirclient/nativeinterface.h'
504--- src/ubuntumirclient/nativeinterface.h 2015-08-27 09:41:47 +0000
505+++ src/ubuntumirclient/nativeinterface.h 2016-04-20 15:51:01 +0000
506@@ -19,9 +19,12 @@
507
508 #include <qpa/qplatformnativeinterface.h>
509
510+class QPlatformScreen;
511+
512 class UbuntuNativeInterface : public QPlatformNativeInterface {
513+ Q_OBJECT
514 public:
515- enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection };
516+ enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection, Scale, FormFactor };
517
518 UbuntuNativeInterface();
519 ~UbuntuNativeInterface();
520@@ -35,10 +38,17 @@
521 void* nativeResourceForScreen(const QByteArray& resourceString,
522 QScreen* screen) override;
523
524+ QVariantMap windowProperties(QPlatformWindow *window) const override;
525+ QVariant windowProperty(QPlatformWindow *window, const QString &name) const override;
526+ QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override;
527+
528 // New methods.
529 const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; }
530 void setMirConnection(void *mirConnection) { mMirConnection = mirConnection; }
531
532+Q_SIGNALS: // New signals
533+ void screenPropertyChanged(QPlatformScreen *screen, const QString &propertyName);
534+
535 private:
536 const QByteArray mGenericEventFilterType;
537 Qt::ScreenOrientation* mNativeOrientation;
538
539=== modified file 'src/ubuntumirclient/screen.cpp'
540--- src/ubuntumirclient/screen.cpp 2015-12-09 13:01:28 +0000
541+++ src/ubuntumirclient/screen.cpp 2016-04-20 15:51:01 +0000
542@@ -18,11 +18,13 @@
543 #include "screen.h"
544 #include "logging.h"
545 #include "orientationchangeevent_p.h"
546+#include "nativeinterface.h"
547+#include "utils.h"
548
549 #include <mir_toolkit/mir_client_library.h>
550
551 // Qt
552-#include <QCoreApplication>
553+#include <QGuiApplication>
554 #include <QtCore/qmath.h>
555 #include <QScreen>
556 #include <QThread>
557@@ -101,37 +103,29 @@
558 }
559 }
560
561+namespace {
562+ int qGetEnvIntValue(const char *varName, bool *ok)
563+ {
564+ return qgetenv(varName).toInt(ok);
565+ }
566+} // anonymous namespace
567+
568+
569 const QEvent::Type OrientationChangeEvent::mType =
570 static_cast<QEvent::Type>(QEvent::registerEventType());
571
572-static const MirDisplayOutput *find_active_output(
573- const MirDisplayConfiguration *conf)
574-{
575- const MirDisplayOutput *output = NULL;
576- for (uint32_t d = 0; d < conf->num_outputs; d++)
577- {
578- const MirDisplayOutput *out = conf->outputs + d;
579-
580- if (out->used &&
581- out->connected &&
582- out->num_modes &&
583- out->current_mode < out->num_modes)
584- {
585- output = out;
586- break;
587- }
588- }
589-
590- return output;
591-}
592-
593-UbuntuScreen::UbuntuScreen(MirConnection *connection)
594- : mFormat(QImage::Format_RGB32)
595+
596+UbuntuScreen::UbuntuScreen(const MirDisplayOutput &output, MirConnection *connection)
597+ : mDevicePixelRatio(1.0)
598+ , mFormat(QImage::Format_RGB32)
599 , mDepth(32)
600+ , mDpi{0}
601+ , mFormFactor{mir_form_factor_unknown}
602+ , mScale{1.0}
603 , mOutputId(0)
604- , mSurfaceFormat()
605 , mEglDisplay(EGL_NO_DISPLAY)
606 , mEglConfig(nullptr)
607+ , mSurfaceFormat()
608 , mCursor(connection)
609 {
610 // Initialize EGL.
611@@ -164,45 +158,15 @@
612 }
613
614 // Set vblank swap interval.
615- int swapInterval = kSwapInterval;
616- QByteArray swapIntervalString = qgetenv("QTUBUNTU_SWAPINTERVAL");
617- if (!swapIntervalString.isEmpty()) {
618- bool ok;
619- swapInterval = swapIntervalString.toInt(&ok);
620- if (!ok)
621- swapInterval = kSwapInterval;
622- }
623- qCDebug(ubuntumirclient, "setting swap interval to %d", swapInterval);
624+ bool ok;
625+ int swapInterval = qGetEnvIntValue("QTUBUNTU_SWAPINTERVAL", &ok);
626+ if (!ok)
627+ swapInterval = kSwapInterval;
628+
629+ qCDebug(ubuntumirclient, "Setting swap interval to %d", swapInterval);
630 eglSwapInterval(mEglDisplay, swapInterval);
631
632- // Get screen resolution.
633- auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); };
634- using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>;
635- configUp displayConfig(mir_connection_create_display_config(connection), configDeleter);
636- ASSERT(displayConfig != nullptr);
637-
638- auto const displayOutput = find_active_output(displayConfig.get());
639- ASSERT(displayOutput != nullptr);
640-
641- mOutputId = displayOutput->output_id;
642-
643- mPhysicalSize = QSizeF(displayOutput->physical_width_mm, displayOutput->physical_height_mm);
644- qCDebug(ubuntumirclient, "screen physical size: %.2fx%.2f", mPhysicalSize.width(), mPhysicalSize.height());
645-
646- const MirDisplayMode *mode = &displayOutput->modes[displayOutput->current_mode];
647- const int kScreenWidth = mode->horizontal_resolution;
648- const int kScreenHeight = mode->vertical_resolution;
649- Q_ASSERT(kScreenWidth > 0 && kScreenHeight > 0);
650-
651- qCDebug(ubuntumirclient, "screen resolution: %dx%d", kScreenWidth, kScreenHeight);
652-
653- mGeometry = QRect(0, 0, kScreenWidth, kScreenHeight);
654-
655- // Set the default orientation based on the initial screen dimmensions.
656- mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
657-
658- // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
659- mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
660+ setMirDisplayOutput(output);
661 }
662
663 UbuntuScreen::~UbuntuScreen()
664@@ -278,3 +242,77 @@
665 QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);
666 }
667 }
668+
669+void UbuntuScreen::setMirDisplayOutput(const MirDisplayOutput &output)
670+{
671+ // Physical screen size
672+ mPhysicalSize.setWidth(output.physical_width_mm);
673+ mPhysicalSize.setHeight(output.physical_height_mm);
674+
675+ // Pixel Format
676+// mFormat = qImageFormatFromMirPixelFormat(output.current_format); // GERRY: TODO
677+
678+ // Pixel depth
679+ mDepth = 8 * MIR_BYTES_PER_PIXEL(output.current_format);
680+
681+ // Mode = Resolution & refresh rate
682+ MirDisplayMode mode = output.modes[output.current_mode];
683+ mNativeGeometry.setX(output.position_x);
684+ mNativeGeometry.setY(output.position_y);
685+ mNativeGeometry.setWidth(mode.horizontal_resolution);
686+ mNativeGeometry.setHeight(mode.vertical_resolution);
687+ mRefreshRate = mode.refresh_rate;
688+
689+ // geometry in device pixels
690+ mGeometry.setX(mNativeGeometry.x() / mDevicePixelRatio);
691+ mGeometry.setY(mNativeGeometry.y() / mDevicePixelRatio);
692+ mGeometry.setWidth(mNativeGeometry.width() / mDevicePixelRatio);
693+ mGeometry.setHeight(mNativeGeometry.height() / mDevicePixelRatio);
694+
695+ // Misc
696+// mScale = output.scale; // missing from MirDisplayOutput, wait for later setAdditionalMirDisplayProperties call
697+// mFormFactor = output.form_factor; // ditto
698+ mOutputId = output.output_id;
699+
700+ // Set the default orientation based on the initial screen dimmensions.
701+ mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
702+
703+ // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
704+ mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
705+}
706+
707+void UbuntuScreen::setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, float dpi)
708+{
709+ auto nativeInterface = static_cast<UbuntuNativeInterface *>(qGuiApp->platformNativeInterface());
710+ if (!qFuzzyCompare(mScale, scale)) {
711+ mScale = scale;
712+ Q_EMIT nativeInterface->screenPropertyChanged(this, QStringLiteral("scale"));
713+ }
714+ if (mFormFactor != formFactor) {
715+ mFormFactor = formFactor;
716+ Q_EMIT nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor"));
717+ }
718+
719+ bool ok;
720+ int dpr = qGetEnvIntValue("QT_DEVICE_PIXEL_RATIO", &ok);
721+ if (ok && dpr > 0) {
722+ qCDebug(ubuntumirclient, "Fixing Device Pixel Ratio to %d", dpr);
723+ mDevicePixelRatio = dpr;
724+ } else {
725+ mDevicePixelRatio = 1.0; //qCeil(scale); // FIXME - unable to announce change in this until can delete/recreate Screen.
726+ }
727+
728+ if (mDpi != dpi) {
729+ mDpi = dpi;
730+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), dpi, dpi);
731+ }
732+}
733+
734+QDpi UbuntuScreen::logicalDpi() const
735+{
736+ if (mDpi > 0) {
737+ return QDpi(mDpi, mDpi);
738+ } else {
739+ return QPlatformScreen::logicalDpi();
740+ }
741+}
742
743=== modified file 'src/ubuntumirclient/screen.h'
744--- src/ubuntumirclient/screen.h 2015-11-23 11:10:24 +0000
745+++ src/ubuntumirclient/screen.h 2016-04-20 15:51:01 +0000
746@@ -19,17 +19,21 @@
747
748 #include <qpa/qplatformscreen.h>
749 #include <QSurfaceFormat>
750+
751+#include <mircommon/mir_toolkit/common.h> // just for MirFormFactor enum
752+
753 #include <EGL/egl.h>
754
755 #include "cursor.h"
756
757 struct MirConnection;
758+struct MirDisplayOutput;
759
760 class UbuntuScreen : public QObject, public QPlatformScreen
761 {
762 Q_OBJECT
763 public:
764- UbuntuScreen(MirConnection *connection);
765+ UbuntuScreen(const MirDisplayOutput &output, MirConnection *connection);
766 virtual ~UbuntuScreen();
767
768 // QPlatformScreen methods.
769@@ -38,6 +42,8 @@
770 QRect geometry() const override { return mGeometry; }
771 QRect availableGeometry() const override { return mGeometry; }
772 QSizeF physicalSize() const override { return mPhysicalSize; }
773+ qreal devicePixelRatio() const override { return mDevicePixelRatio; }
774+ QDpi logicalDpi() const override;
775 Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; }
776 Qt::ScreenOrientation orientation() const override { return mNativeOrientation; }
777 QPlatformCursor *cursor() const override { return const_cast<UbuntuCursor*>(&mCursor); }
778@@ -47,6 +53,15 @@
779 EGLDisplay eglDisplay() const { return mEglDisplay; }
780 EGLConfig eglConfig() const { return mEglConfig; }
781 EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
782+
783+ // Additional Screen properties from Mir
784+ uint32_t outputId() const { return mOutputId; }
785+ MirFormFactor formFactor() const { return mFormFactor; }
786+ float scale() const { return mScale; }
787+
788+ // Internally used methods
789+ void setMirDisplayOutput(const MirDisplayOutput &output);
790+ void setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, float dpi);
791 void handleWindowSurfaceResize(int width, int height);
792 uint32_t mirOutputId() const { return mOutputId; }
793
794@@ -54,18 +69,25 @@
795 void customEvent(QEvent* event) override;
796
797 private:
798- QRect mGeometry;
799+ QRect mGeometry, mNativeGeometry;
800 QSizeF mPhysicalSize;
801+ qreal mDevicePixelRatio;
802 Qt::ScreenOrientation mNativeOrientation;
803 Qt::ScreenOrientation mCurrentOrientation;
804 QImage::Format mFormat;
805 int mDepth;
806+ int mDpi;
807+ qreal mRefreshRate;
808+ MirFormFactor mFormFactor;
809+ float mScale;
810 uint32_t mOutputId;
811- QSurfaceFormat mSurfaceFormat;
812 EGLDisplay mEglDisplay;
813 EGLConfig mEglConfig;
814 EGLNativeDisplayType mEglNativeDisplay;
815- UbuntuCursor mCursor;
816+ QSurfaceFormat mSurfaceFormat;
817+ UbuntuCursor mCursor; //GERRY try const
818+
819+ friend class UbuntuNativeInterface;
820 };
821
822 #endif // UBUNTU_SCREEN_H
823
824=== added file 'src/ubuntumirclient/screenobserver.cpp'
825--- src/ubuntumirclient/screenobserver.cpp 1970-01-01 00:00:00 +0000
826+++ src/ubuntumirclient/screenobserver.cpp 2016-04-20 15:51:01 +0000
827@@ -0,0 +1,131 @@
828+/*
829+ * Copyright (C) 2015 Canonical, Ltd.
830+ *
831+ * This program is free software: you can redistribute it and/or modify it under
832+ * the terms of the GNU Lesser General Public License version 3, as published by
833+ * the Free Software Foundation.
834+ *
835+ * This program is distributed in the hope that it will be useful, but WITHOUT
836+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
837+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
838+ * Lesser General Public License for more details.
839+ *
840+ * You should have received a copy of the GNU Lesser General Public License
841+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
842+ */
843+
844+#include "screenobserver.h"
845+#include "screen.h"
846+#include "window.h"
847+#include "logging.h"
848+
849+// Qt
850+#include <QMetaObject>
851+#include <QPointer>
852+
853+// Mir
854+#include <mirclient/mir_toolkit/mir_connection.h>
855+
856+#include <memory>
857+
858+namespace {
859+ static void displayConfigurationChangedCallback(MirConnection */*connection*/, void* context)
860+ {
861+ ASSERT(context != NULL);
862+ UbuntuScreenObserver *observer = static_cast<UbuntuScreenObserver *>(context);
863+ QMetaObject::invokeMethod(observer, "update");
864+ }
865+} // anonymous namespace
866+
867+UbuntuScreenObserver::UbuntuScreenObserver(MirConnection *mirConnection)
868+ : mMirConnection(mirConnection)
869+{
870+ mir_connection_set_display_config_change_callback(mirConnection, ::displayConfigurationChangedCallback, this);
871+ update();
872+}
873+
874+void UbuntuScreenObserver::update()
875+{
876+ // Wrap MirDisplayConfiguration to always delete when out of scope
877+ auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); };
878+ using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>;
879+ configUp displayConfig(mir_connection_create_display_config(mMirConnection), configDeleter);
880+
881+ // Mir only tells us something changed, it is up to us to figure out what.
882+ QList<UbuntuScreen*> newScreenList;
883+ QList<UbuntuScreen*> oldScreenList = mScreenList;
884+ mScreenList.clear();
885+
886+ for (uint32_t i=0; i<displayConfig->num_outputs; i++) {
887+ MirDisplayOutput output = displayConfig->outputs[i];
888+ if (output.used && output.connected) {
889+ UbuntuScreen *screen = findScreenWithId(oldScreenList, output.output_id);
890+ if (screen) { // we've already set up this display before, refresh its internals
891+ screen->setMirDisplayOutput(output);
892+ oldScreenList.removeAll(screen);
893+ } else {
894+ // new display, so create UbuntuScreen for it
895+ screen = new UbuntuScreen(output, mMirConnection);
896+ newScreenList.append(screen);
897+ qDebug() << "Added Screen with id" << output.output_id << "and geometry" << screen->geometry();
898+ }
899+ mScreenList.append(screen);
900+ }
901+ }
902+
903+ // Announce old & unused Screens, should be deleted by the slot
904+ Q_FOREACH (const auto screen, oldScreenList) {
905+ Q_EMIT screenRemoved(screen);
906+ }
907+
908+ /*
909+ * Mir's MirDisplayOutput does not include formFactor or scale for some reason, but Qt
910+ * will want that information on creating the QScreen. Only way we get that info is when
911+ * Mir positions a Window on that Screen. See "handleScreenPropertiesChange" method
912+ */
913+
914+ // Announce new Screens
915+ Q_FOREACH (const auto screen, newScreenList) {
916+ Q_EMIT screenAdded(screen);
917+ }
918+
919+ qDebug() << "=======================================";
920+ for (auto screen: mScreenList) {
921+ qDebug() << screen << "- id:" << screen->outputId()
922+ << "geometry:" << screen->geometry()
923+ << "form factor:" << screen->formFactor()
924+ << "scale:" << screen->scale();
925+ }
926+ qDebug() << "=======================================";
927+}
928+
929+UbuntuScreen *UbuntuScreenObserver::findScreenWithId(uint32_t id)
930+{
931+ return findScreenWithId(mScreenList, id);
932+}
933+
934+UbuntuScreen *UbuntuScreenObserver::findScreenWithId(const QList<UbuntuScreen *> &list, uint32_t id)
935+{
936+ Q_FOREACH (const auto screen, list) {
937+ if (screen->outputId() == id) {
938+ return screen;
939+ }
940+ }
941+ return nullptr;
942+}
943+
944+void UbuntuScreenObserver::handleScreenPropertiesChange(UbuntuScreen *screen, int dpi,
945+ MirFormFactor formFactor, float scale)
946+{
947+ screen->setAdditionalMirDisplayProperties(scale, formFactor, dpi);
948+
949+ qDebug() << "=======================================";
950+ for (auto screen: mScreenList) {
951+ qDebug() << screen << "- id:" << screen->outputId()
952+ << "geometry:" << screen->geometry()
953+ << "form factor:" << screen->formFactor()
954+ << "scale:" << screen->scale();
955+ }
956+ qDebug() << "=======================================";
957+}
958+
959
960=== added file 'src/ubuntumirclient/screenobserver.h'
961--- src/ubuntumirclient/screenobserver.h 1970-01-01 00:00:00 +0000
962+++ src/ubuntumirclient/screenobserver.h 2016-04-20 15:51:01 +0000
963@@ -0,0 +1,54 @@
964+/*
965+ * Copyright (C) 2015 Canonical, Ltd.
966+ *
967+ * This program is free software: you can redistribute it and/or modify it under
968+ * the terms of the GNU Lesser General Public License version 3, as published by
969+ * the Free Software Foundation.
970+ *
971+ * This program is distributed in the hope that it will be useful, but WITHOUT
972+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
973+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
974+ * Lesser General Public License for more details.
975+ *
976+ * You should have received a copy of the GNU Lesser General Public License
977+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
978+ */
979+
980+#ifndef UBUNTU_SCREEN_OBSERVER_H
981+#define UBUNTU_SCREEN_OBSERVER_H
982+
983+#include <QObject>
984+
985+#include <mir_toolkit/mir_connection.h>
986+
987+class UbuntuScreen;
988+
989+class UbuntuScreenObserver : public QObject
990+{
991+ Q_OBJECT
992+
993+public:
994+ UbuntuScreenObserver(MirConnection *connection);
995+
996+ QList<UbuntuScreen*> screens() const { return mScreenList; }
997+ UbuntuScreen *findScreenWithId(uint32_t id);
998+
999+ void handleScreenPropertiesChange(UbuntuScreen *screen, int dpi,
1000+ MirFormFactor formFactor, float scale);
1001+
1002+Q_SIGNALS:
1003+ void screenAdded(UbuntuScreen *screen);
1004+ void screenRemoved(UbuntuScreen *screen);
1005+
1006+private Q_SLOTS:
1007+ void update();
1008+
1009+private:
1010+ UbuntuScreen *findScreenWithId(const QList<UbuntuScreen *> &list, uint32_t id);
1011+ void removeScreen(UbuntuScreen *screen);
1012+
1013+ MirConnection *mMirConnection;
1014+ QList<UbuntuScreen*> mScreenList;
1015+};
1016+
1017+#endif // UBUNTU_SCREEN_OBSERVER_H
1018
1019=== modified file 'src/ubuntumirclient/ubuntumirclient.pro'
1020--- src/ubuntumirclient/ubuntumirclient.pro 2016-02-25 21:02:19 +0000
1021+++ src/ubuntumirclient/ubuntumirclient.pro 2016-04-20 15:51:01 +0000
1022@@ -26,6 +26,7 @@
1023 platformservices.cpp \
1024 plugin.cpp \
1025 screen.cpp \
1026+ screenobserver.cpp \
1027 theme.cpp \
1028 window.cpp
1029
1030@@ -42,9 +43,11 @@
1031 orientationchangeevent_p.h \
1032 platformservices.h \
1033 plugin.h \
1034+ screenobserver.h \
1035 screen.h \
1036 theme.h \
1037- window.h
1038+ window.h \
1039+ utils.h
1040
1041 # Installation path
1042 target.path += $$[QT_INSTALL_PLUGINS]/platforms
1043
1044=== added file 'src/ubuntumirclient/utils.h'
1045--- src/ubuntumirclient/utils.h 1970-01-01 00:00:00 +0000
1046+++ src/ubuntumirclient/utils.h 2016-04-20 15:51:01 +0000
1047@@ -0,0 +1,29 @@
1048+/*
1049+ * Copyright (C) 2015 Canonical, Ltd.
1050+ *
1051+ * This program is free software: you can redistribute it and/or modify it under
1052+ * the terms of the GNU Lesser General Public License version 3, as published by
1053+ * the Free Software Foundation.
1054+ *
1055+ * This program is distributed in the hope that it will be useful, but WITHOUT
1056+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1057+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1058+ * Lesser General Public License for more details.
1059+ *
1060+ * You should have received a copy of the GNU Lesser General Public License
1061+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1062+ */
1063+
1064+#ifndef UTILS_H
1065+#define UTILS_H
1066+
1067+#include <QtGlobal>
1068+
1069+namespace {
1070+ inline int divideAndRoundUp(int numerator, qreal denominator)
1071+ {
1072+ return ceil((qreal)numerator / denominator);
1073+ }
1074+} // anonymous namespace
1075+
1076+#endif // UTILS_H
1077
1078=== modified file 'src/ubuntumirclient/window.cpp'
1079--- src/ubuntumirclient/window.cpp 2016-03-14 17:37:19 +0000
1080+++ src/ubuntumirclient/window.cpp 2016-04-20 15:51:01 +0000
1081@@ -17,8 +17,10 @@
1082 // Local
1083 #include "window.h"
1084 #include "clipboard.h"
1085+#include "nativeinterface.h"
1086 #include "input.h"
1087 #include "screen.h"
1088+#include "utils.h"
1089 #include "logging.h"
1090
1091 #include <mir_toolkit/mir_client_library.h>
1092@@ -34,6 +36,11 @@
1093
1094 #include <EGL/egl.h>
1095
1096+
1097+/*
1098+ * Note: all geometry is in device-independent pixels, except that contained in variables with the
1099+ * suffix "Px" - whose units are (physical) pixels
1100+ */
1101 Q_LOGGING_CATEGORY(ubuntumirclientBufferSwap, "ubuntumirclient.bufferSwap", QtWarningMsg)
1102
1103 const Qt::WindowType LowChromeWindowHint = (Qt::WindowType)0x00800000;
1104@@ -153,13 +160,14 @@
1105 Spec makeSurfaceSpec(QWindow *window, UbuntuInput *input, MirConnection *connection)
1106 {
1107 const auto geom = window->geometry();
1108- const int width = geom.width() > 0 ? geom.width() : 1;
1109- const int height = geom.height() > 0 ? geom.height() : 1;
1110+ const int dpr = int(window->devicePixelRatio());
1111+ const int widthPx = geom.width() > 0 ? geom.width() * dpr : 1;
1112+ const int heightPx = geom.height() > 0 ? geom.height() * dpr : 1;
1113 const auto pixelFormat = defaultPixelFormatFor(connection);
1114
1115 if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
1116- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);
1117- return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
1118+ qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating input method surface with size=(%dx%d)px", window, widthPx, heightPx);
1119+ return Spec{mir_connection_create_spec_for_input_method(connection, widthPx, heightPx, pixelFormat)};
1120 }
1121
1122 const Qt::WindowType type = window->type();
1123@@ -172,13 +180,13 @@
1124 parent = input->lastFocusedWindow();
1125 }
1126 if (parent) {
1127- auto pos = geom.topLeft();
1128- pos -= parent->geometry().topLeft();
1129- MirRectangle location{pos.x(), pos.y(), 0, 0};
1130- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);
1131+ auto posPx = geom.topLeft() * dpr;
1132+ posPx -= parent->geometry().topLeft() * dpr;
1133+ MirRectangle location{posPx.x(), posPx.y(), 0, 0};
1134+ qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating menu surface with size=(%dx%d)px", window, widthPx, heightPx);
1135 return Spec{mir_connection_create_spec_for_menu(
1136- connection, width, height, pixelFormat, parent->mirSurface(),
1137- &location, mir_edge_attachment_any)};
1138+ connection, widthPx, heightPx, pixelFormat, parent->mirSurface(),
1139+ &location, mir_edge_attachment_any)};
1140 } else {
1141 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
1142 }
1143@@ -186,37 +194,39 @@
1144 auto parent = transientParentFor(window);
1145 if (parent) {
1146 // Modal dialog
1147- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);
1148- return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};
1149+ qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating modal dialog with size=(%dx%d)px", window, widthPx, heightPx);
1150+ return Spec{mir_connection_create_spec_for_modal_dialog(connection, widthPx, heightPx, pixelFormat, parent->mirSurface())};
1151 } else {
1152 // TODO: do Qt parentless dialogs have the same semantics as mir?
1153- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);
1154- return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
1155+ qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating parentless dialog with size=(%dx%d)px", window, widthPx, heightPx);
1156+ return Spec{mir_connection_create_spec_for_dialog(connection, widthPx, heightPx, pixelFormat)};
1157 }
1158 }
1159- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);
1160- return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
1161+ qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, with size=(%dx%d)px", window, type, widthPx, heightPx);
1162+ return Spec{mir_connection_create_spec_for_normal_surface(connection, widthPx, heightPx, pixelFormat)};
1163 }
1164
1165-void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)
1166+void setSizingConstraints(MirSurfaceSpec *spec, const QSize &minSizePx, const QSize &maxSizePx, const QSize &incrementPx)
1167 {
1168- mir_surface_spec_set_min_width(spec, minSize.width());
1169- mir_surface_spec_set_min_height(spec, minSize.height());
1170- if (maxSize.width() >= minSize.width()) {
1171- mir_surface_spec_set_max_width(spec, maxSize.width());
1172- }
1173- if (maxSize.height() >= minSize.height()) {
1174- mir_surface_spec_set_max_height(spec, maxSize.height());
1175- }
1176- if (increment.width() > 0) {
1177- mir_surface_spec_set_width_increment(spec, increment.width());
1178- }
1179- if (increment.height() > 0) {
1180- mir_surface_spec_set_height_increment(spec, increment.height());
1181+ mir_surface_spec_set_min_width(spec, minSizePx.width());
1182+ mir_surface_spec_set_min_height(spec, minSizePx.height());
1183+ if (maxSizePx.width() >= minSizePx.width()) {
1184+ mir_surface_spec_set_max_width(spec, maxSizePx.width());
1185+ }
1186+ if (maxSizePx.height() >= minSizePx.height()) {
1187+ mir_surface_spec_set_max_height(spec, maxSizePx.height());
1188+ }
1189+ if (incrementPx.width() > 0) {
1190+ mir_surface_spec_set_width_increment(spec, incrementPx.width());
1191+ }
1192+ if (incrementPx.height() > 0) {
1193+ mir_surface_spec_set_height_increment(spec, incrementPx.height());
1194 }
1195 }
1196
1197-MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)
1198+MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input,
1199+ MirConnection *connection, mir_surface_event_callback inputCallback,
1200+ void* inputContext)
1201 {
1202 auto spec = makeSurfaceSpec(window, input, connection);
1203 const auto title = window->title().toUtf8();
1204@@ -228,6 +238,8 @@
1205 mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());
1206 }
1207
1208+ mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext);
1209+
1210 if (window->flags() & LowChromeWindowHint) {
1211 mir_surface_spec_set_shell_chrome(spec.get(), mir_shell_chrome_low);
1212 }
1213@@ -256,6 +268,10 @@
1214
1215 } //namespace
1216
1217+/*
1218+ * UbuntuSurface - wraps a MirSurface
1219+ * All units are in pixels only (no device pixels).
1220+ */
1221 class UbuntuSurface
1222 {
1223 public:
1224@@ -264,36 +280,26 @@
1225 , mPlatformWindow(platformWindow)
1226 , mInput(input)
1227 , mConnection(connection)
1228- , mMirSurface(createMirSurface(mWindow, screen, input, connection))
1229 , mEglDisplay(screen->eglDisplay())
1230- , mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr))
1231 , mNeedsRepaint(false)
1232 , mParented(mWindow->transientParent() || mWindow->parent())
1233 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
1234 {
1235- mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this);
1236+ mMirSurface = createMirSurface(mWindow, screen, input, connection, surfaceEventCallback, this);
1237+ mEglSurface = eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr);
1238
1239 // Window manager can give us a final size different from what we asked for
1240 // so let's check what we ended up getting
1241 MirSurfaceParameters parameters;
1242 mir_surface_get_parameters(mMirSurface, &parameters);
1243
1244- auto geom = mWindow->geometry();
1245- geom.setWidth(parameters.width);
1246- geom.setHeight(parameters.height);
1247- if (mWindow->windowState() == Qt::WindowFullScreen) {
1248- geom.setY(0);
1249- } else {
1250- geom.setY(panelHeight());
1251- }
1252-
1253 // Assume that the buffer size matches the surface size at creation time
1254- mBufferSize = geom.size();
1255- platformWindow->QPlatformWindow::setGeometry(geom);
1256- QWindowSystemInterface::handleGeometryChange(mWindow, geom);
1257+ mBufferSizePx.rwidth() = parameters.width;
1258+ mBufferSizePx.rheight() = parameters.height;
1259
1260- qCDebug(ubuntumirclient, "created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n",
1261- geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow));
1262+ qCDebug(ubuntumirclient, "created surface with size=(%dx%d)px, title='%s', role=%d",
1263+ parameters.width, parameters.height, qPrintable(mWindow->title()), roleFor(mWindow));
1264+ mPlatformWindow->updateWindowSize(parameters.width, parameters.height);
1265 }
1266
1267 ~UbuntuSurface()
1268@@ -304,15 +310,15 @@
1269 mir_surface_release_sync(mMirSurface);
1270 }
1271
1272- UbuntuSurface(UbuntuSurface const&) = delete;
1273- UbuntuSurface& operator=(UbuntuSurface const&) = delete;
1274+ UbuntuSurface(const UbuntuSurface &) = delete;
1275+ UbuntuSurface& operator=(const UbuntuSurface &) = delete;
1276
1277- void resize(const QSize& newSize);
1278- void updateTitle(const QString& title);
1279- void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
1280+ void resize(const QSize &newSizePx);
1281+ void updateTitle(const QString &title);
1282+ void setSizingConstraints(const QSize &minSizePx, const QSize &maxSizePx, const QSize &incrementPx);
1283
1284 void onSwapBuffersDone();
1285- void handleSurfaceResized(int width, int height);
1286+ void handleSurfaceResized(int widthPx, int heightPx);
1287 int needsRepaint() const;
1288
1289 MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); }
1290@@ -329,7 +335,7 @@
1291 bool hasParent() const { return mParented; }
1292
1293 private:
1294- static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context);
1295+ static void surfaceEventCallback(MirSurface *surface, const MirEvent *event, void *context);
1296 void postEvent(const MirEvent *event);
1297
1298 QWindow * const mWindow;
1299@@ -337,40 +343,40 @@
1300 UbuntuInput * const mInput;
1301 MirConnection * const mConnection;
1302
1303- MirSurface * const mMirSurface;
1304+ MirSurface* mMirSurface;
1305 const EGLDisplay mEglDisplay;
1306- const EGLSurface mEglSurface;
1307+ EGLSurface mEglSurface;
1308
1309 bool mNeedsRepaint;
1310 bool mParented;
1311- QSize mBufferSize;
1312+ QSize mBufferSizePx;
1313
1314 QMutex mTargetSizeMutex;
1315- QSize mTargetSize;
1316+ QSize mTargetSizePx;
1317 MirShellChrome mShellChrome;
1318 };
1319
1320-void UbuntuSurface::resize(const QSize& size)
1321+void UbuntuSurface::resize(const QSize &sizePx)
1322 {
1323- qCDebug(ubuntumirclient,"resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
1324+ qCDebug(ubuntumirclient,"resize(window=%p) to (%dx%d)px", mWindow, sizePx.width(), sizePx.height());
1325
1326 if (mWindow->windowState() == Qt::WindowFullScreen || mWindow->windowState() == Qt::WindowMaximized) {
1327 qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
1328 return;
1329 }
1330
1331- if (size.isEmpty()) {
1332+ if (sizePx.isEmpty()) {
1333 qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, size is empty", mWindow);
1334 return;
1335 }
1336
1337 Spec spec{mir_connection_create_spec_for_changes(mConnection)};
1338- mir_surface_spec_set_width(spec.get(), size.width());
1339- mir_surface_spec_set_height(spec.get(), size.height());
1340+ mir_surface_spec_set_width(spec.get(), sizePx.width());
1341+ mir_surface_spec_set_height(spec.get(), sizePx.height());
1342 mir_surface_apply_spec(mMirSurface, spec.get());
1343 }
1344
1345-void UbuntuSurface::updateTitle(const QString& newTitle)
1346+void UbuntuSurface::updateTitle(const QString &newTitle)
1347 {
1348 const auto title = newTitle.toUtf8();
1349 Spec spec{mir_connection_create_spec_for_changes(mConnection)};
1350@@ -378,14 +384,14 @@
1351 mir_surface_apply_spec(mMirSurface, spec.get());
1352 }
1353
1354-void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment)
1355+void UbuntuSurface::setSizingConstraints(const QSize &minSizePx, const QSize &maxSizePx, const QSize &incrementPx)
1356 {
1357 Spec spec{mir_connection_create_spec_for_changes(mConnection)};
1358- ::setSizingConstraints(spec.get(), minSize, maxSize, increment);
1359+ ::setSizingConstraints(spec.get(), minSizePx, maxSizePx, incrementPx);
1360 mir_surface_apply_spec(mMirSurface, spec.get());
1361 }
1362
1363-void UbuntuSurface::handleSurfaceResized(int width, int height)
1364+void UbuntuSurface::handleSurfaceResized(int widthPx, int heightPx)
1365 {
1366 QMutexLocker lock(&mTargetSizeMutex);
1367
1368@@ -395,13 +401,13 @@
1369 // see TODO in postEvent as the ideal way we should handle this.
1370 // The actual buffer size may or may have not changed at this point, so let the rendering
1371 // thread drive the window geometry updates.
1372- mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height;
1373+ mNeedsRepaint = mTargetSizePx.width() == widthPx && mTargetSizePx.height() == heightPx;
1374 }
1375
1376 int UbuntuSurface::needsRepaint() const
1377 {
1378 if (mNeedsRepaint) {
1379- if (mTargetSize != mBufferSize) {
1380+ if (mTargetSizePx != mBufferSizePx) {
1381 //If the buffer hasn't changed yet, we need at least two redraws,
1382 //once to get the new buffer size and propagate the geometry changes
1383 //and the second to redraw the content at the new size
1384@@ -436,29 +442,25 @@
1385 static int sFrameNumber = 0;
1386 ++sFrameNumber;
1387
1388- EGLint eglSurfaceWidth = -1;
1389- EGLint eglSurfaceHeight = -1;
1390- eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth);
1391- eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight);
1392-
1393- const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0;
1394-
1395- if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {
1396-
1397- qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
1398- mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);
1399-
1400- mBufferSize.rwidth() = eglSurfaceWidth;
1401- mBufferSize.rheight() = eglSurfaceHeight;
1402-
1403- QRect newGeometry = mPlatformWindow->geometry();
1404- newGeometry.setSize(mBufferSize);
1405-
1406- mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
1407- QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
1408+ EGLint eglSurfaceWidthPx = -1;
1409+ EGLint eglSurfaceHeightPx = -1;
1410+ eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidthPx);
1411+ eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeightPx);
1412+
1413+ const bool validSize = eglSurfaceWidthPx > 0 && eglSurfaceHeightPx > 0;
1414+
1415+ if (validSize && (mBufferSizePx.width() != eglSurfaceWidthPx || mBufferSizePx.height() != eglSurfaceHeightPx)) {
1416+
1417+ qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size changed (%dx%d)px => (%dx%d)px",
1418+ mWindow, sFrameNumber, mBufferSizePx.width(), mBufferSizePx.height(), eglSurfaceWidthPx, eglSurfaceHeightPx);
1419+
1420+ mBufferSizePx.rwidth() = eglSurfaceWidthPx;
1421+ mBufferSizePx.rheight() = eglSurfaceHeightPx;
1422+
1423+ mPlatformWindow->updateWindowSize(eglSurfaceWidthPx, eglSurfaceHeightPx);
1424 } else {
1425- qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
1426- mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());
1427+ qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size=(%dx%d)px",
1428+ mWindow, sFrameNumber, mBufferSizePx.width(), mBufferSizePx.height());
1429 }
1430 }
1431
1432@@ -479,13 +481,13 @@
1433 // As a workaround, we use the width/height as an identifier of this latest event
1434 // so the event handler (handleSurfaceResized) can discard/ignore old ones.
1435 const auto resizeEvent = mir_event_get_resize_event(event);
1436- const auto width = mir_resize_event_get_width(resizeEvent);
1437- const auto height = mir_resize_event_get_height(resizeEvent);
1438- qCDebug(ubuntumirclient, "resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);
1439+ const auto widthPx = mir_resize_event_get_width(resizeEvent);
1440+ const auto heightPx = mir_resize_event_get_height(resizeEvent);
1441+ qCDebug(ubuntumirclient, "resizeEvent(window=%p, size=(%dx%d)px", mWindow, widthPx, heightPx);
1442
1443 QMutexLocker lock(&mTargetSizeMutex);
1444- mTargetSize.rwidth() = width;
1445- mTargetSize.rheight() = height;
1446+ mTargetSizePx.rwidth() = widthPx;
1447+ mTargetSizePx.rheight() = heightPx;
1448 }
1449
1450 mInput->postEvent(mPlatformWindow, event);
1451@@ -501,8 +503,8 @@
1452 mir_surface_apply_spec(mMirSurface, spec.get());
1453 }
1454
1455-UbuntuWindow::UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard, UbuntuScreen *screen,
1456- UbuntuInput *input, MirConnection *connection)
1457+UbuntuWindow::UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard,
1458+ UbuntuInput *input, UbuntuNativeInterface *native, MirConnection *connection)
1459 : QObject(nullptr)
1460 , QPlatformWindow(w)
1461 , mId(makeId())
1462@@ -510,9 +512,16 @@
1463 , mWindowState(w->windowState())
1464 , mWindowFlags(w->flags())
1465 , mWindowVisible(false)
1466- , mSurface(new UbuntuSurface{this, screen, input, connection})
1467+ , mWindowExposed(true)
1468+ , mNativeInterface(native)
1469+ , mSurface(new UbuntuSurface{this, static_cast<UbuntuScreen*>(w->screen()->handle()), input, connection})
1470+ , mScale(1.0)
1471+ , mFormFactor(mir_form_factor_unknown)
1472 {
1473- qCDebug(ubuntumirclient, "UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());
1474+ qCDebug(ubuntumirclient, "UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p) with title '%s', role: '%d'",
1475+ w, w->screen()->handle(), input, mSurface.get(), qPrintable(window()->title()), roleFor(window()));
1476+
1477+ enablePanelHeightHack(w->windowState() != Qt::WindowFullScreen);
1478 }
1479
1480 UbuntuWindow::~UbuntuWindow()
1481@@ -520,12 +529,25 @@
1482 qCDebug(ubuntumirclient, "~UbuntuWindow(window=%p)", this);
1483 }
1484
1485-void UbuntuWindow::handleSurfaceResized(int width, int height)
1486+void UbuntuWindow::updateWindowSize(int widthPx, int heightPx) // after when Mir has resized the surface
1487+{
1488+ const float dpr = devicePixelRatio();
1489+ auto geom = geometry();
1490+ geom.setWidth(divideAndRoundUp(widthPx, dpr));
1491+ geom.setHeight(divideAndRoundUp(heightPx, dpr));
1492+
1493+ QPlatformWindow::setGeometry(geom);
1494+ QWindowSystemInterface::handleGeometryChange(window(), geom);
1495+
1496+ qCDebug(ubuntumirclient) << "Surface geometry updated:" << geom;
1497+}
1498+
1499+void UbuntuWindow::handleSurfaceResized(int widthPx, int heightPx)
1500 {
1501 QMutexLocker lock(&mMutex);
1502- qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height);
1503+ qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), widthPx, heightPx);
1504
1505- mSurface->handleSurfaceResized(width, height);
1506+ mSurface->handleSurfaceResized(widthPx, heightPx);
1507
1508 // This resize event could have occurred just after the last buffer swap for this window.
1509 // This means the client may still be holding a buffer with the older size. The first redraw call
1510@@ -536,11 +558,23 @@
1511 lock.unlock();
1512 qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
1513 for (int i = 0; i < numRepaints; i++) {
1514- qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());
1515+ qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) repainting size=(%dx%d)dp", window(), geometry().size().width(), geometry().size().height());
1516 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
1517 }
1518 }
1519
1520+void UbuntuWindow::handleSurfaceExposeChange(bool exposed)
1521+{
1522+ QMutexLocker lock(&mMutex);
1523+ qCDebug(ubuntumirclient, "handleSurfaceExposeChange(window=%p, exposed=%s)", window(), exposed ? "true" : "false");
1524+
1525+ if (mWindowExposed == exposed) return;
1526+ mWindowExposed = exposed;
1527+
1528+ lock.unlock();
1529+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
1530+}
1531+
1532 void UbuntuWindow::handleSurfaceFocused()
1533 {
1534 qCDebug(ubuntumirclient, "handleSurfaceFocused(window=%p)", window());
1535@@ -621,19 +655,19 @@
1536 }
1537 }
1538
1539-void UbuntuWindow::setGeometry(const QRect& rect)
1540+void UbuntuWindow::setGeometry(const QRect &rect)
1541 {
1542 QMutexLocker lock(&mMutex);
1543- qCDebug(ubuntumirclient, "setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)",
1544- window(), rect.x(), rect.y(), rect.width(), rect.height());
1545+ qCDebug(ubuntumirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)",
1546+ window(), rect.x(), rect.y(), rect.width(), rect.height());
1547
1548 //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates
1549 const auto newSize = rect.size();
1550 auto newGeometry = geometry();
1551 newGeometry.setSize(newSize);
1552- QPlatformWindow::setGeometry(newGeometry);
1553
1554- mSurface->resize(newSize);
1555+ mSurface->resize(newSize * devicePixelRatio());
1556+ // Note: don't call handleGeometryChange here, wait to see what Mir replies with.
1557 }
1558
1559 void UbuntuWindow::setVisible(bool visible)
1560@@ -658,10 +692,9 @@
1561 lock.unlock();
1562 updateSurfaceState();
1563 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
1564- QWindowSystemInterface::flushWindowSystemEvents();
1565 }
1566
1567-void UbuntuWindow::setWindowTitle(const QString& title)
1568+void UbuntuWindow::setWindowTitle(const QString &title)
1569 {
1570 QMutexLocker lock(&mMutex);
1571 qCDebug(ubuntumirclient, "setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
1572@@ -672,16 +705,22 @@
1573 {
1574 QMutexLocker lock(&mMutex);
1575 const auto win = window();
1576- qCDebug(ubuntumirclient, "propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",
1577- win, win->minimumSize().width(), win->minimumSize().height(),
1578- win->maximumSize().width(), win->maximumSize().height(),
1579- win->sizeIncrement().width(), win->sizeIncrement().height());
1580- mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement());
1581+ const float dpr = devicePixelRatio();
1582+ qCDebug(ubuntumirclient, "propagateSizeHints(window=%p) min(%dx%d)dp; max(%dx%d)dp; increment(%dx%d)dp",
1583+ win, win->minimumSize().width(), win->minimumSize().height(),
1584+ win->maximumSize().width(), win->maximumSize().height(),
1585+ win->sizeIncrement().width(), win->sizeIncrement().height());
1586+ mSurface->setSizingConstraints(win->minimumSize() * dpr, win->maximumSize() * dpr, win->sizeIncrement() * dpr);
1587+}
1588+
1589+qreal UbuntuWindow::devicePixelRatio() const
1590+{
1591+ return screen() ? screen()->devicePixelRatio() : 1.0; // not impossible a Window has no attached Screen
1592 }
1593
1594 bool UbuntuWindow::isExposed() const
1595 {
1596- return mWindowVisible;
1597+ return mWindowVisible && mWindowExposed;
1598 }
1599
1600 void* UbuntuWindow::eglSurface() const
1601@@ -705,6 +744,21 @@
1602 mSurface->onSwapBuffersDone();
1603 }
1604
1605+void UbuntuWindow::handleScreenPropertiesChange(MirFormFactor formFactor, float scale)
1606+{
1607+ // Update the scale & form factor native-interface properties for the windows affected
1608+ // as there is no convenient way to emit signals for those custom properties on a QScreen
1609+ if (formFactor != mFormFactor) {
1610+ mFormFactor = formFactor;
1611+ Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("formFactor"));
1612+ }
1613+
1614+ if (!qFuzzyCompare(scale, mScale)) {
1615+ mScale = scale;
1616+ Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("scale"));
1617+ }
1618+}
1619+
1620 void UbuntuWindow::updateSurfaceState()
1621 {
1622 QMutexLocker lock(&mMutex);
1623
1624=== modified file 'src/ubuntumirclient/window.h'
1625--- src/ubuntumirclient/window.h 2016-02-18 15:45:21 +0000
1626+++ src/ubuntumirclient/window.h 2016-04-20 15:51:01 +0000
1627@@ -18,13 +18,15 @@
1628 #define UBUNTU_WINDOW_H
1629
1630 #include <qpa/qplatformwindow.h>
1631-#include <QLoggingCategory>
1632 #include <QSharedPointer>
1633 #include <QMutex>
1634
1635+#include <mir_toolkit/common.h> // needed only for MirFormFactor enum
1636+
1637 #include <memory>
1638
1639 class UbuntuClipboard;
1640+class UbuntuNativeInterface;
1641 class UbuntuInput;
1642 class UbuntuScreen;
1643 class UbuntuSurface;
1644@@ -35,8 +37,8 @@
1645 {
1646 Q_OBJECT
1647 public:
1648- UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard, UbuntuScreen *screen,
1649- UbuntuInput *input, MirConnection *mirConnection);
1650+ UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard,
1651+ UbuntuInput *input, UbuntuNativeInterface* native, MirConnection *mirConnection);
1652 virtual ~UbuntuWindow();
1653
1654 // QPlatformWindow methods.
1655@@ -48,28 +50,38 @@
1656 void setWindowTitle(const QString &title) override;
1657 void propagateSizeHints() override;
1658 bool isExposed() const override;
1659+ qreal devicePixelRatio() const override;
1660+
1661+ // Additional Window properties exposed by NativeInterface
1662+ MirFormFactor formFactor() const { return mFormFactor; }
1663+ float scale() const { return mScale; }
1664
1665 // New methods.
1666 void *eglSurface() const;
1667 MirSurface *mirSurface() const;
1668- void handleSurfaceResized(int width, int height);
1669+ void updateWindowSize(int widthPx, int heightPx);
1670+ void handleSurfaceResized(int widthPx, int heightPx);
1671+ void handleSurfaceExposeChange(bool exposed);
1672 void handleSurfaceFocused();
1673 void handleSurfaceVisibilityChanged(bool visible);
1674 void handleSurfaceStateChanged(Qt::WindowState state);
1675 void onSwapBuffersDone();
1676+ void handleScreenPropertiesChange(MirFormFactor formFactor, float scale);
1677
1678 private:
1679 void enablePanelHeightHack(bool enable);
1680 void updateSurfaceState();
1681-
1682 mutable QMutex mMutex;
1683 const WId mId;
1684 const QSharedPointer<UbuntuClipboard> mClipboard;
1685 Qt::WindowState mWindowState;
1686 Qt::WindowFlags mWindowFlags;
1687 bool mWindowVisible;
1688-
1689+ bool mWindowExposed;
1690+ UbuntuNativeInterface *mNativeInterface;
1691 std::unique_ptr<UbuntuSurface> mSurface;
1692+ float mScale;
1693+ MirFormFactor mFormFactor;
1694 };
1695
1696 #endif // UBUNTU_WINDOW_H

Subscribers

People subscribed via source and target branches