Merge lp:~gerboland/qtubuntu/screen-info-drop-panel-hack into lp:qtubuntu

Proposed by Gerry Boland
Status: Superseded
Proposed branch: lp:~gerboland/qtubuntu/screen-info-drop-panel-hack
Merge into: lp:qtubuntu
Diff against target: 1689 lines (+759/-297)
15 files modified
src/ubuntumirclient/backingstore.cpp (+11/-5)
src/ubuntumirclient/input.cpp (+91/-41)
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 (+165/-158)
src/ubuntumirclient/window.h (+17/-5)
To merge this branch: bzr merge lp:~gerboland/qtubuntu/screen-info-drop-panel-hack
Reviewer Review Type Date Requested Status
Ubuntu Phablet Team Pending
Review via email: mp+286312@code.launchpad.net

This proposal has been superseded by a proposal from 2016-02-17.

Commit message

Remove the panel hack

To post a comment you must log in.
322. By MichaƂ Sawicz

Merge lp:~nick-dedekind/qtubuntu/shell_chrome

323. By Nick Dedekind

merge bugs

324. By Nick Dedekind

dont update on expose

325. By Gerry Boland

Merge screen-info

326. By Gerry Boland

Remove panel hack

Unmerged revisions

326. By Gerry Boland

Remove panel hack

325. By Gerry Boland

Merge screen-info

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

Subscribers

People subscribed via source and target branches