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

Proposed by Gerry Boland
Status: Superseded
Proposed branch: lp:~unity-team/qtubuntu/screen-info
Merge into: lp:qtubuntu
Diff against target: 1938 lines (+931/-314)
15 files modified
src/ubuntumirclient/backingstore.cpp (+11/-5)
src/ubuntumirclient/input.cpp (+117/-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 (+303/-175)
src/ubuntumirclient/window.h (+25/-5)
To merge this branch: bzr merge lp:~unity-team/qtubuntu/screen-info
Reviewer Review Type Date Requested Status
Ubuntu Phablet Team Pending
Review via email: mp+284830@code.launchpad.net

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

Commit message

Dynamic scaling support

To post a comment you must log in.
lp:~unity-team/qtubuntu/screen-info updated
312. By Gerry Boland

Merge trunk

313. By Gerry Boland

Drop the new changelog entry

314. By Gerry Boland

Fix comment, resolve build error

315. By Gerry Boland

Bad weave merge, fix duplicate line

316. By Gerry Boland

Fix another compile error, type mistake

317. By Gerry Boland

Do not flush window system events in QPlatformWindow::setVisible, can crash during screen changes

318. By Gerry Boland

Experimental refactor, to keep ScreenObserver isolated from Qt state handling

319. By Gerry Boland

Add per-Screen property change signal and getter for the custom properties scale & formfactor

320. By Gerry Boland

Safer float to void* casting

321. By Gerry Boland

Change getter of custom Screen properties, return pointer to float, instead of shoving float into pointer. Nicer for apps

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

Fix for build fail

326. By Nick Dedekind

fixed crash from event handling before constructor completed.

327. By Nick Dedekind

merged with parent

328. By Nick Dedekind

remerge

329. By Michał Sawicz

Merge trunk

Unmerged revisions

329. By Michał Sawicz

Merge trunk

328. By Nick Dedekind

remerge

327. By Nick Dedekind

merged with parent

Preview Diff

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

Subscribers

People subscribed via source and target branches