Merge lp:~aacid/qtubuntu/clazy_fixes into lp:qtubuntu

Proposed by Albert Astals Cid on 2015-09-29
Status: Superseded
Proposed branch: lp:~aacid/qtubuntu/clazy_fixes
Merge into: lp:qtubuntu
Diff against target: 1506 lines (+609/-441)
12 files modified
src/ubuntumirclient/clipboard.cpp (+16/-15)
src/ubuntumirclient/glcontext.cpp (+1/-13)
src/ubuntumirclient/glcontext.h (+1/-1)
src/ubuntumirclient/input.cpp (+37/-10)
src/ubuntumirclient/input.h (+10/-5)
src/ubuntumirclient/integration.cpp (+16/-19)
src/ubuntumirclient/nativeinterface.cpp (+5/-5)
src/ubuntumirclient/plugin.cpp (+2/-2)
src/ubuntumirclient/screen.cpp (+9/-6)
src/ubuntumirclient/screen.h (+3/-1)
src/ubuntumirclient/window.cpp (+492/-350)
src/ubuntumirclient/window.h (+17/-14)
To merge this branch: bzr merge lp:~aacid/qtubuntu/clazy_fixes
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve on 2015-09-29
Gerry Boland code 2015-09-29 Approve on 2015-09-29
Review via email: mp+272747@code.launchpad.net

This proposal has been superseded by a proposal from 2015-11-17.

Commit Message

Improvements from running clazy over the code

* Add some missing overrides
* Wrap const char * into QStringLiteral
* Use new connect syntax
* Don't call data() on temporary QByteArray as it detaches

clazy: https://quickgit.kde.org/?p=clazy.git

To post a comment you must log in.
lp:~aacid/qtubuntu/clazy_fixes updated on 2015-09-29
282. By Albert Astals Cid on 2015-09-29

const &

PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Gerry Boland (gerboland) wrote :

Looks ok to me, will let CI check it out

review: Approve (code)
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~aacid/qtubuntu/clazy_fixes updated on 2015-11-17
283. By Albert Astals Cid on 2015-11-17

Merge lp:~albaguirre/qtubuntu/use-mir-surface-apis

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ubuntumirclient/clipboard.cpp'
2--- src/ubuntumirclient/clipboard.cpp 2015-08-20 15:37:29 +0000
3+++ src/ubuntumirclient/clipboard.cpp 2015-11-17 13:42:51 +0000
4@@ -66,12 +66,12 @@
5 if (!mPendingGetContentsCall.isNull())
6 return;
7
8- QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("GetContents");
9+ QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("GetContents"));
10
11 mPendingGetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
12
13- QObject::connect(mPendingGetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)),
14- this, SLOT(onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*)));
15+ QObject::connect(mPendingGetContentsCall.data(), &QDBusPendingCallWatcher::finished,
16+ this, &UbuntuClipboard::onDBusClipboardGetContentsFinished);
17 }
18
19 void UbuntuClipboard::onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher* call)
20@@ -122,18 +122,18 @@
21 QDBusConnection dbusConnection = QDBusConnection::sessionBus();
22
23 bool ok = dbusConnection.connect(
24- "com.canonical.QtMir",
25- "/com/canonical/QtMir/Clipboard",
26- "com.canonical.QtMir.Clipboard",
27- "ContentsChanged",
28+ QStringLiteral("com.canonical.QtMir"),
29+ QStringLiteral("/com/canonical/QtMir/Clipboard"),
30+ QStringLiteral("com.canonical.QtMir.Clipboard"),
31+ QStringLiteral("ContentsChanged"),
32 this, SLOT(updateMimeData(QByteArray)));
33 if (!ok) {
34 qCritical("UbuntuClipboard - Failed to connect to ContentsChanged signal form the D-Bus system clipboard.");
35 }
36
37- mDBusClipboard = new QDBusInterface("com.canonical.QtMir",
38- "/com/canonical/QtMir/Clipboard",
39- "com.canonical.QtMir.Clipboard",
40+ mDBusClipboard = new QDBusInterface(QStringLiteral("com.canonical.QtMir"),
41+ QStringLiteral("/com/canonical/QtMir/Clipboard"),
42+ QStringLiteral("com.canonical.QtMir.Clipboard"),
43 dbusConnection);
44
45 mDBusSetupDone = true;
46@@ -159,12 +159,13 @@
47 int offset = headerSize;
48 header[0] = formatCount;
49 for (int i = 0; i < formatCount; i++) {
50+ const QByteArray data = mimeData->data(formats[i]);
51 const int formatOffset = offset;
52 const int formatSize = formats[i].size();
53 const int dataOffset = offset + formatSize;
54- const int dataSize = mimeData->data(formats[i]).size();
55+ const int dataSize = data.size();
56 memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize);
57- memcpy(&buffer[dataOffset], mimeData->data(formats[i]).data(), dataSize);
58+ memcpy(&buffer[dataOffset], data.data(), dataSize);
59 header[i*4+1] = formatOffset;
60 header[i*4+2] = formatSize;
61 header[i*4+3] = dataOffset;
62@@ -279,10 +280,10 @@
63 delete mPendingSetContentsCall.data();
64 }
65
66- QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("SetContents", clipboardContents);
67+ QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("SetContents"), clipboardContents);
68
69 mPendingSetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
70
71- QObject::connect(mPendingSetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)),
72- this, SLOT(onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*)));
73+ QObject::connect(mPendingSetContentsCall.data(), &QDBusPendingCallWatcher::finished,
74+ this, &UbuntuClipboard::onDBusClipboardSetContentsFinished);
75 }
76
77=== modified file 'src/ubuntumirclient/glcontext.cpp'
78--- src/ubuntumirclient/glcontext.cpp 2014-06-18 23:10:00 +0000
79+++ src/ubuntumirclient/glcontext.cpp 2015-11-17 13:42:51 +0000
80@@ -109,19 +109,7 @@
81 ASSERT(eglSwapBuffers(mEglDisplay, eglSurface) == EGL_TRUE);
82 #endif
83
84- // "Technique" copied from mir, in examples/eglapp.c around line 96
85- EGLint newBufferWidth = -1;
86- EGLint newBufferHeight = -1;
87- /*
88- * Querying the surface (actually the current buffer) dimensions here is
89- * the only truly safe way to be sure that the dimensions we think we
90- * have are those of the buffer being rendered to. But this should be
91- * improved in future; https://bugs.launchpad.net/mir/+bug/1194384
92- */
93- eglQuerySurface(mEglDisplay, eglSurface, EGL_WIDTH, &newBufferWidth);
94- eglQuerySurface(mEglDisplay, eglSurface, EGL_HEIGHT, &newBufferHeight);
95-
96- ubuntuWindow->onBuffersSwapped_threadSafe(newBufferWidth, newBufferHeight);
97+ ubuntuWindow->onSwapBuffersDone();
98 }
99
100 void (*UbuntuOpenGLContext::getProcAddress(const QByteArray& procName)) ()
101
102=== modified file 'src/ubuntumirclient/glcontext.h'
103--- src/ubuntumirclient/glcontext.h 2014-06-18 23:10:00 +0000
104+++ src/ubuntumirclient/glcontext.h 2015-11-17 13:42:51 +0000
105@@ -32,7 +32,7 @@
106 bool makeCurrent(QPlatformSurface* surface) override;
107 void doneCurrent() override;
108 bool isValid() const override { return mEglContext != EGL_NO_CONTEXT; }
109- void (*getProcAddress(const QByteArray& procName)) ();
110+ void (*getProcAddress(const QByteArray& procName)) () override;
111
112 EGLContext eglContext() const { return mEglContext; }
113
114
115=== modified file 'src/ubuntumirclient/input.cpp'
116--- src/ubuntumirclient/input.cpp 2015-11-09 19:26:55 +0000
117+++ src/ubuntumirclient/input.cpp 2015-11-17 13:42:51 +0000
118@@ -142,6 +142,7 @@
119 , mEventFilterType(static_cast<UbuntuNativeInterface*>(
120 integration->nativeInterface())->genericEventFilterType())
121 , mEventType(static_cast<QEvent::Type>(QEvent::registerEventType()))
122+ , mLastFocusedWindow(nullptr)
123 {
124 // Initialize touch device.
125 mTouchDevice = new QTouchDevice;
126@@ -213,7 +214,7 @@
127 switch (mir_event_get_type(nativeEvent))
128 {
129 case mir_event_type_input:
130- dispatchInputEvent(ubuntuEvent->window->window(), mir_event_get_input_event(nativeEvent));
131+ dispatchInputEvent(ubuntuEvent->window, mir_event_get_input_event(nativeEvent));
132 break;
133 case mir_event_type_resize:
134 {
135@@ -225,7 +226,7 @@
136 mir_resize_event_get_width(resizeEvent),
137 mir_resize_event_get_height(resizeEvent));
138
139- ubuntuEvent->window->handleSurfaceResize(mir_resize_event_get_width(resizeEvent),
140+ ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent),
141 mir_resize_event_get_height(resizeEvent));
142 break;
143 }
144@@ -233,8 +234,16 @@
145 {
146 auto surfaceEvent = mir_event_get_surface_event(nativeEvent);
147 if (mir_surface_event_get_attribute(surfaceEvent) == mir_surface_attrib_focus) {
148- ubuntuEvent->window->handleSurfaceFocusChange(mir_surface_event_get_attribute_value(surfaceEvent) ==
149- mir_surface_focused);
150+ const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
151+ // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
152+ // so that we don't deactivate windows prematurely.
153+ if (focused) {
154+ mPendingFocusGainedEvents--;
155+ ubuntuEvent->window->handleSurfaceFocused();
156+ } else if(!mPendingFocusGainedEvents) {
157+ DLOG("[ubuntumirclient QPA] No windows have focus");
158+ QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
159+ }
160 }
161 break;
162 }
163@@ -253,6 +262,17 @@
164 {
165 QWindow *window = platformWindow->window();
166
167+ const auto eventType = mir_event_get_type(event);
168+ if (mir_event_type_surface == eventType) {
169+ auto surfaceEvent = mir_event_get_surface_event(event);
170+ if (mir_surface_attrib_focus == mir_surface_event_get_attribute(surfaceEvent)) {
171+ const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
172+ if (focused) {
173+ mPendingFocusGainedEvents++;
174+ }
175+ }
176+ }
177+
178 QCoreApplication::postEvent(this, new UbuntuEvent(
179 platformWindow, event, mEventType));
180
181@@ -263,7 +283,7 @@
182 }
183 }
184
185-void UbuntuInput::dispatchInputEvent(QWindow *window, const MirInputEvent *ev)
186+void UbuntuInput::dispatchInputEvent(UbuntuWindow *window, const MirInputEvent *ev)
187 {
188 switch (mir_input_event_get_type(ev))
189 {
190@@ -281,7 +301,7 @@
191 }
192 }
193
194-void UbuntuInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *ev)
195+void UbuntuInput::dispatchTouchEvent(UbuntuWindow *window, const MirInputEvent *ev)
196 {
197 const MirTouchEvent *tev = mir_input_event_get_touch_event(ev);
198
199@@ -312,6 +332,7 @@
200 switch (touch_action)
201 {
202 case mir_touch_action_down:
203+ mLastFocusedWindow = window;
204 touchPoint.state = Qt::TouchPointPressed;
205 break;
206 case mir_touch_action_up:
207@@ -326,7 +347,7 @@
208 }
209
210 ulong timestamp = mir_input_event_get_event_time(ev) / 1000000;
211- QWindowSystemInterface::handleTouchEvent(window, timestamp,
212+ QWindowSystemInterface::handleTouchEvent(window->window(), timestamp,
213 mTouchDevice, touchPoints);
214 }
215
216@@ -369,7 +390,7 @@
217 }
218 }
219
220-void UbuntuInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *event)
221+void UbuntuInput::dispatchKeyEvent(UbuntuWindow *window, const MirInputEvent *event)
222 {
223 const MirKeyboardEvent *key_event = mir_input_event_get_keyboard_event(event);
224
225@@ -383,6 +404,9 @@
226 QEvent::Type keyType = action == mir_keyboard_action_up
227 ? QEvent::KeyRelease : QEvent::KeyPress;
228
229+ if (action == mir_keyboard_action_down)
230+ mLastFocusedWindow = window;
231+
232 char s[2];
233 int sym = translateKeysym(xk_sym, s, sizeof(s));
234 QString text = QString::fromLatin1(s);
235@@ -399,7 +423,7 @@
236 }
237 }
238
239- QWindowSystemInterface::handleKeyEvent(window, timestamp, keyType, sym, modifiers, text, is_auto_rep);
240+ QWindowSystemInterface::handleKeyEvent(window->window(), timestamp, keyType, sym, modifiers, text, is_auto_rep);
241 }
242
243 namespace
244@@ -422,8 +446,9 @@
245 }
246 }
247
248-void UbuntuInput::dispatchPointerEvent(QWindow *window, const MirInputEvent *ev)
249+void UbuntuInput::dispatchPointerEvent(UbuntuWindow *platformWindow, const MirInputEvent *ev)
250 {
251+ auto window = platformWindow->window();
252 auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
253
254 auto pev = mir_input_event_get_pointer_event(ev);
255@@ -446,6 +471,8 @@
256 QPoint(), angleDelta, modifiers, Qt::ScrollUpdate);
257 } else {
258 auto buttons = extract_buttons(pev);
259+ if (buttons != Qt::NoButton)
260+ mLastFocusedWindow = platformWindow;
261 QWindowSystemInterface::handleMouseEvent(window, timestamp, localPoint, localPoint /* Should we omit global point instead? */,
262 buttons, modifiers);
263 }
264
265=== modified file 'src/ubuntumirclient/input.h'
266--- src/ubuntumirclient/input.h 2015-02-11 20:41:17 +0000
267+++ src/ubuntumirclient/input.h 2015-11-17 13:42:51 +0000
268@@ -19,6 +19,7 @@
269
270 // Qt
271 #include <qpa/qwindowsysteminterface.h>
272+#include <QAtomicInt>
273
274 #include <mir_toolkit/mir_client_library.h>
275
276@@ -38,13 +39,14 @@
277
278 void postEvent(UbuntuWindow* window, const MirEvent *event);
279 UbuntuClientIntegration* integration() const { return mIntegration; }
280+ UbuntuWindow *lastFocusedWindow() const {return mLastFocusedWindow; }
281
282 protected:
283- void dispatchKeyEvent(QWindow *window, const MirInputEvent *event);
284- void dispatchPointerEvent(QWindow *window, const MirInputEvent *event);
285- void dispatchTouchEvent(QWindow *window, const MirInputEvent *event);
286- void dispatchInputEvent(QWindow *window, const MirInputEvent *event);
287-
288+ void dispatchKeyEvent(UbuntuWindow *window, const MirInputEvent *event);
289+ void dispatchPointerEvent(UbuntuWindow *window, const MirInputEvent *event);
290+ void dispatchTouchEvent(UbuntuWindow *window, const MirInputEvent *event);
291+ void dispatchInputEvent(UbuntuWindow *window, const MirInputEvent *event);
292+
293 void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event);
294
295 private:
296@@ -52,6 +54,9 @@
297 QTouchDevice* mTouchDevice;
298 const QByteArray mEventFilterType;
299 const QEvent::Type mEventType;
300+
301+ UbuntuWindow *mLastFocusedWindow;
302+ QAtomicInt mPendingFocusGainedEvents;
303 };
304
305 #endif // UBUNTU_INPUT_H
306
307=== modified file 'src/ubuntumirclient/integration.cpp'
308--- src/ubuntumirclient/integration.cpp 2015-09-14 13:12:16 +0000
309+++ src/ubuntumirclient/integration.cpp 2015-11-17 13:42:51 +0000
310@@ -14,28 +14,28 @@
311 * along with this program. If not, see <http://www.gnu.org/licenses/>.
312 */
313
314-// Qt
315-#include <QGuiApplication>
316-#include <private/qguiapplication_p.h>
317-#include <qpa/qplatformnativeinterface.h>
318-#include <qpa/qplatforminputcontextfactory_p.h>
319-#include <qpa/qplatforminputcontext.h>
320-#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
321-#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
322-#include <QOpenGLContext>
323-
324 // Local
325+#include "integration.h"
326 #include "backingstore.h"
327 #include "clipboard.h"
328 #include "glcontext.h"
329 #include "input.h"
330-#include "integration.h"
331 #include "logging.h"
332 #include "nativeinterface.h"
333 #include "screen.h"
334 #include "theme.h"
335 #include "window.h"
336
337+// Qt
338+#include <QGuiApplication>
339+#include <private/qguiapplication_p.h>
340+#include <qpa/qplatformnativeinterface.h>
341+#include <qpa/qplatforminputcontextfactory_p.h>
342+#include <qpa/qplatforminputcontext.h>
343+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
344+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
345+#include <QOpenGLContext>
346+
347 // platform-api
348 #include <ubuntu/application/lifecycle_delegate.h>
349 #include <ubuntu/application/id.h>
350@@ -162,10 +162,8 @@
351
352 QPlatformWindow* UbuntuClientIntegration::createPlatformWindow(QWindow* window)
353 {
354- QPlatformWindow* platformWindow = new UbuntuWindow(
355- window, mClipboard, static_cast<UbuntuScreen*>(mScreen), mInput, u_application_instance_get_mir_connection(mInstance));
356- platformWindow->requestActivateWindow();
357- return platformWindow;
358+ return new UbuntuWindow(window, mClipboard, static_cast<UbuntuScreen*>(mScreen),
359+ mInput, u_application_instance_get_mir_connection(mInstance));
360 }
361
362 bool UbuntuClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const
363@@ -173,11 +171,9 @@
364 switch (cap) {
365 case ThreadedPixmaps:
366 return true;
367- break;
368
369 case OpenGL:
370 return true;
371- break;
372
373 case ThreadedOpenGL:
374 if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) {
375@@ -186,8 +182,9 @@
376 DLOG("ubuntumirclient: disabled threaded OpenGL");
377 return false;
378 }
379- break;
380-
381+ case MultipleWindows:
382+ case NonFullScreenWindows:
383+ return true;
384 default:
385 return QPlatformIntegration::hasCapability(cap);
386 }
387
388=== modified file 'src/ubuntumirclient/nativeinterface.cpp'
389--- src/ubuntumirclient/nativeinterface.cpp 2015-08-27 09:41:47 +0000
390+++ src/ubuntumirclient/nativeinterface.cpp 2015-11-17 13:42:51 +0000
391@@ -14,17 +14,17 @@
392 * along with this program. If not, see <http://www.gnu.org/licenses/>.
393 */
394
395+// Local
396+#include "nativeinterface.h"
397+#include "screen.h"
398+#include "glcontext.h"
399+
400 // Qt
401 #include <private/qguiapplication_p.h>
402 #include <QtGui/qopenglcontext.h>
403 #include <QtGui/qscreen.h>
404 #include <QtCore/QMap>
405
406-// Local
407-#include "nativeinterface.h"
408-#include "screen.h"
409-#include "glcontext.h"
410-
411 class UbuntuResourceMap : public QMap<QByteArray, UbuntuNativeInterface::ResourceType>
412 {
413 public:
414
415=== modified file 'src/ubuntumirclient/plugin.cpp'
416--- src/ubuntumirclient/plugin.cpp 2014-06-18 23:10:00 +0000
417+++ src/ubuntumirclient/plugin.cpp 2015-11-17 13:42:51 +0000
418@@ -20,14 +20,14 @@
419 QStringList UbuntuMirClientIntegrationPlugin::keys() const
420 {
421 QStringList list;
422- list << "ubuntumirclient";
423+ list << QStringLiteral("ubuntumirclient");
424 return list;
425 }
426
427 QPlatformIntegration* UbuntuMirClientIntegrationPlugin::create(const QString &system,
428 const QStringList &)
429 {
430- if (system.toLower() == "ubuntumirclient") {
431+ if (system.toLower() == QLatin1String("ubuntumirclient")) {
432 #ifdef PLATFORM_API_TOUCH
433 setenv("UBUNTU_PLATFORM_API_BACKEND", "touch_mirclient", 1);
434 #else
435
436=== modified file 'src/ubuntumirclient/screen.cpp'
437--- src/ubuntumirclient/screen.cpp 2015-10-09 10:57:03 +0000
438+++ src/ubuntumirclient/screen.cpp 2015-11-17 13:42:51 +0000
439@@ -14,6 +14,11 @@
440 * along with this program. If not, see <http://www.gnu.org/licenses/>.
441 */
442
443+// local
444+#include "screen.h"
445+#include "logging.h"
446+#include "orientationchangeevent_p.h"
447+
448 #include <mir_toolkit/mir_client_library.h>
449
450 // Qt
451@@ -24,12 +29,7 @@
452 #include <qpa/qwindowsysteminterface.h>
453 #include <QtPlatformSupport/private/qeglconvenience_p.h>
454
455-// local
456-#include "screen.h"
457-#include "logging.h"
458-#include "orientationchangeevent_p.h"
459-
460-#include "memory"
461+#include <memory>
462
463 static const int kSwapInterval = 1;
464
465@@ -128,6 +128,7 @@
466 UbuntuScreen::UbuntuScreen(MirConnection *connection)
467 : mFormat(QImage::Format_RGB32)
468 , mDepth(32)
469+ , mOutputId(0)
470 , mSurfaceFormat()
471 , mEglDisplay(EGL_NO_DISPLAY)
472 , mEglConfig(nullptr)
473@@ -182,6 +183,8 @@
474 auto const displayOutput = find_active_output(displayConfig.get());
475 ASSERT(displayOutput != nullptr);
476
477+ mOutputId = displayOutput->output_id;
478+
479 mPhysicalSize = QSizeF(displayOutput->physical_width_mm, displayOutput->physical_height_mm);
480 DLOG("ubuntumirclient: screen physical size: %.2fx%.2f", mPhysicalSize.width(), mPhysicalSize.height());
481
482
483=== modified file 'src/ubuntumirclient/screen.h'
484--- src/ubuntumirclient/screen.h 2015-10-09 10:57:03 +0000
485+++ src/ubuntumirclient/screen.h 2015-11-17 13:42:51 +0000
486@@ -45,9 +45,10 @@
487 EGLConfig eglConfig() const { return mEglConfig; }
488 EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
489 void handleWindowSurfaceResize(int width, int height);
490+ uint32_t mirOutputId() const { return mOutputId; }
491
492 // QObject methods.
493- void customEvent(QEvent* event);
494+ void customEvent(QEvent* event) override;
495
496 private:
497 QRect mGeometry;
498@@ -56,6 +57,7 @@
499 Qt::ScreenOrientation mCurrentOrientation;
500 QImage::Format mFormat;
501 int mDepth;
502+ uint32_t mOutputId;
503 QSurfaceFormat mSurfaceFormat;
504 EGLDisplay mEglDisplay;
505 EGLConfig mEglConfig;
506
507=== modified file 'src/ubuntumirclient/window.cpp'
508--- src/ubuntumirclient/window.cpp 2015-11-09 19:26:55 +0000
509+++ src/ubuntumirclient/window.cpp 2015-11-17 13:42:51 +0000
510@@ -15,15 +15,16 @@
511 */
512
513 // Local
514+#include "window.h"
515 #include "clipboard.h"
516 #include "input.h"
517-#include "window.h"
518 #include "screen.h"
519 #include "logging.h"
520
521+#include <mir_toolkit/mir_client_library.h>
522+
523 // Qt
524 #include <qpa/qwindowsysteminterface.h>
525-#include <QMutex>
526 #include <QMutexLocker>
527 #include <QSize>
528 #include <QtMath>
529@@ -33,25 +34,46 @@
530
531 #include <EGL/egl.h>
532
533-#define IS_OPAQUE_FLAG 1
534-
535 namespace
536 {
537+
538+// FIXME: this used to be defined by platform-api, but it's been removed in v3. Change ubuntu-keyboard to use
539+// a different enum for window roles.
540+enum UAUiWindowRole {
541+ U_MAIN_ROLE = 1,
542+ U_DASH_ROLE,
543+ U_INDICATOR_ROLE,
544+ U_NOTIFICATIONS_ROLE,
545+ U_GREETER_ROLE,
546+ U_LAUNCHER_ROLE,
547+ U_ON_SCREEN_KEYBOARD_ROLE,
548+ U_SHUTDOWN_DIALOG_ROLE,
549+};
550+
551+struct MirSpecDeleter
552+{
553+ void operator()(MirSurfaceSpec *spec) { mir_surface_spec_release(spec); }
554+};
555+
556+using Spec = std::unique_ptr<MirSurfaceSpec, MirSpecDeleter>;
557+
558+EGLNativeWindowType nativeWindowFor(MirSurface *surf)
559+{
560+ auto stream = mir_surface_get_buffer_stream(surf);
561+ return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream));
562+}
563+
564 MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
565 {
566 switch (state) {
567 case Qt::WindowNoState:
568 return mir_surface_state_restored;
569-
570 case Qt::WindowFullScreen:
571 return mir_surface_state_fullscreen;
572-
573 case Qt::WindowMaximized:
574 return mir_surface_state_maximized;
575-
576 case Qt::WindowMinimized:
577 return mir_surface_state_minimized;
578-
579 default:
580 LOG("Unexpected Qt::WindowState: %d", state);
581 return mir_surface_state_restored;
582@@ -64,126 +86,137 @@
583 switch (state) {
584 case Qt::WindowNoState:
585 return "NoState";
586-
587 case Qt::WindowFullScreen:
588 return "FullScreen";
589-
590 case Qt::WindowMaximized:
591 return "Maximized";
592-
593 case Qt::WindowMinimized:
594 return "Minimized";
595-
596 default:
597 return "!?";
598 }
599 }
600 #endif
601
602-} // anonymous namespace
603-
604-class UbuntuWindowPrivate
605-{
606-public:
607- void createEGLSurface(EGLNativeWindowType nativeWindow);
608- void destroyEGLSurface();
609- int panelHeight();
610-
611- UbuntuScreen* screen;
612- EGLSurface eglSurface;
613- WId id;
614- UbuntuInput* input;
615- Qt::WindowState state;
616- MirConnection *connection;
617- MirSurface* surface;
618- QSize bufferSize;
619- QMutex mutex;
620- QSharedPointer<UbuntuClipboard> clipboard;
621- int resizeCatchUpAttempts;
622-#if !defined(QT_NO_DEBUG)
623- int frameNumber;
624-#endif
625-};
626-
627-static void eventCallback(MirSurface* surface, const MirEvent *event, void* context)
628-{
629- (void) surface;
630- DASSERT(context != NULL);
631- UbuntuWindow* platformWindow = static_cast<UbuntuWindow*>(context);
632- platformWindow->priv()->input->postEvent(platformWindow, event);
633-}
634-
635-static void surfaceCreateCallback(MirSurface* surface, void* context)
636-{
637- DASSERT(context != NULL);
638- UbuntuWindow* platformWindow = static_cast<UbuntuWindow*>(context);
639- platformWindow->priv()->surface = surface;
640-
641- mir_surface_set_event_handler(surface, eventCallback, context);
642-}
643-
644-UbuntuWindow::UbuntuWindow(QWindow* w, QSharedPointer<UbuntuClipboard> clipboard, UbuntuScreen* screen,
645- UbuntuInput* input, MirConnection* connection)
646- : QObject(nullptr), QPlatformWindow(w)
647-{
648- DASSERT(screen != NULL);
649-
650- d = new UbuntuWindowPrivate;
651- d->screen = screen;
652- d->eglSurface = EGL_NO_SURFACE;
653- d->input = input;
654- d->state = window()->windowState();
655- d->connection = connection;
656- d->clipboard = clipboard;
657- d->resizeCatchUpAttempts = 0;
658-
659+WId makeId()
660+{
661 static int id = 1;
662- d->id = id++;
663-
664-#if !defined(QT_NO_DEBUG)
665- d->frameNumber = 0;
666-#endif
667-
668- // Use client geometry if set explicitly, use available screen geometry otherwise.
669- QPlatformWindow::setGeometry(window()->geometry() != screen->geometry() ?
670- window()->geometry() : screen->availableGeometry());
671- createWindow();
672- DLOG("UbuntuWindow::UbuntuWindow (this=%p, w=%p, screen=%p, input=%p)", this, w, screen, input);
673-}
674-
675-UbuntuWindow::~UbuntuWindow()
676-{
677- DLOG("UbuntuWindow::~UbuntuWindow");
678- d->destroyEGLSurface();
679-
680- mir_surface_release_sync(d->surface);
681-
682- delete d;
683-}
684-
685-void UbuntuWindowPrivate::createEGLSurface(EGLNativeWindowType nativeWindow)
686-{
687- DLOG("UbuntuWindowPrivate::createEGLSurface (this=%p, nativeWindow=%p)",
688- this, reinterpret_cast<void*>(nativeWindow));
689-
690- eglSurface = eglCreateWindowSurface(screen->eglDisplay(), screen->eglConfig(),
691- nativeWindow, nullptr);
692-
693- DASSERT(eglSurface != EGL_NO_SURFACE);
694-}
695-
696-void UbuntuWindowPrivate::destroyEGLSurface()
697-{
698- DLOG("UbuntuWindowPrivate::destroyEGLSurface (this=%p)", this);
699- if (eglSurface != EGL_NO_SURFACE) {
700- eglDestroySurface(screen->eglDisplay(), eglSurface);
701- eglSurface = EGL_NO_SURFACE;
702- }
703+ return id++;
704+}
705+
706+MirPixelFormat defaultPixelFormatFor(MirConnection *connection)
707+{
708+ MirPixelFormat format;
709+ unsigned int nformats;
710+ mir_connection_get_available_surface_formats(connection, &format, 1, &nformats);
711+ return format;
712+}
713+
714+UAUiWindowRole roleFor(QWindow *window)
715+{
716+ QVariant roleVariant = window->property("role");
717+ if (!roleVariant.isValid())
718+ return U_MAIN_ROLE;
719+
720+ uint role = roleVariant.toUInt();
721+ if (role < U_MAIN_ROLE || role > U_SHUTDOWN_DIALOG_ROLE)
722+ return U_MAIN_ROLE;
723+
724+ return static_cast<UAUiWindowRole>(role);
725+}
726+
727+UbuntuWindow *transientParentFor(QWindow *window)
728+{
729+ QWindow *parent = window->transientParent();
730+ return parent ? static_cast<UbuntuWindow *>(parent->handle()) : nullptr;
731+}
732+
733+Spec makeSurfaceSpec(QWindow *window, UbuntuInput *input, MirConnection *connection)
734+{
735+ const auto geom = window->geometry();
736+ const int width = geom.width() > 0 ? geom.width() : 1;
737+ const int height = geom.height() > 0 ? geom.height() : 1;
738+ const auto pixelFormat = defaultPixelFormatFor(connection);
739+
740+ if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
741+ DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);
742+ return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
743+ }
744+
745+ const Qt::WindowType type = window->type();
746+ if (type == Qt::Popup) {
747+ auto parent = transientParentFor(window);
748+ if (parent == nullptr) {
749+ //NOTE: We cannot have a parentless popup -
750+ //try using the last surface to receive input as that will most likely be
751+ //the one that caused this popup to be created
752+ parent = input->lastFocusedWindow();
753+ }
754+ if (parent) {
755+ auto pos = geom.topLeft();
756+ pos -= parent->geometry().topLeft();
757+ MirRectangle location{pos.x(), pos.y(), 0, 0};
758+ DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);
759+ return Spec{mir_connection_create_spec_for_menu(
760+ connection, width, height, pixelFormat, parent->mirSurface(),
761+ &location, mir_edge_attachment_any)};
762+ } else {
763+ DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
764+ }
765+ } else if (type == Qt::Dialog) {
766+ auto parent = transientParentFor(window);
767+ if (parent) {
768+ // Modal dialog
769+ DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);
770+ return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};
771+ } else {
772+ // TODO: do Qt parentless dialogs have the same semantics as mir?
773+ DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);
774+ return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
775+ }
776+ }
777+ DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);
778+ return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
779+}
780+
781+void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)
782+{
783+ mir_surface_spec_set_min_width(spec, minSize.width());
784+ mir_surface_spec_set_min_height(spec, minSize.height());
785+ if (maxSize.width() >= minSize.width()) {
786+ mir_surface_spec_set_max_width(spec, maxSize.width());
787+ }
788+ if (maxSize.height() >= minSize.height()) {
789+ mir_surface_spec_set_max_height(spec, maxSize.height());
790+ }
791+ if (increment.width() > 0) {
792+ mir_surface_spec_set_width_increment(spec, increment.width());
793+ }
794+ if (increment.height() > 0) {
795+ mir_surface_spec_set_height_increment(spec, increment.height());
796+ }
797+}
798+
799+MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)
800+{
801+ auto spec = makeSurfaceSpec(window, input, connection);
802+ const auto title = window->title().toUtf8();
803+ mir_surface_spec_set_name(spec.get(), title.constData());
804+
805+ setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement());
806+
807+ if (window->windowState() == Qt::WindowFullScreen) {
808+ mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());
809+ }
810+
811+ auto surface = mir_surface_create_sync(spec.get());
812+ Q_ASSERT(mir_surface_is_valid(surface));
813+ return surface;
814 }
815
816 // FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
817 // we need to guess the panel height (3GU + 2DP)
818-int UbuntuWindowPrivate::panelHeight()
819+int panelHeight()
820 {
821 const int defaultGridUnit = 8;
822 int gridUnit = defaultGridUnit;
823@@ -199,272 +232,381 @@
824 return gridUnit * 3 + qFloor(densityPixelRatio) * 2;
825 }
826
827-namespace
828-{
829-static MirPixelFormat
830-mir_choose_default_pixel_format(MirConnection *connection)
831-{
832- MirPixelFormat format[mir_pixel_formats];
833- unsigned int nformats;
834-
835- mir_connection_get_available_surface_formats(connection,
836- format, mir_pixel_formats, &nformats);
837-
838- return format[0];
839-}
840-}
841-
842-void UbuntuWindow::createWindow()
843-{
844- DLOG("UbuntuWindow::createWindow (this=%p)", this);
845-
846- // FIXME: remove this remnant of an old platform-api enum - needs ubuntu-keyboard update
847- const int SCREEN_KEYBOARD_ROLE = 7;
848- // Get surface role and flags.
849- QVariant roleVariant = window()->property("role");
850- int role = roleVariant.isValid() ? roleVariant.toUInt() : 1; // 1 is the default role for apps.
851- QVariant opaqueVariant = window()->property("opaque");
852- uint flags = opaqueVariant.isValid() ?
853- opaqueVariant.toUInt() ? static_cast<uint>(IS_OPAQUE_FLAG) : 0 : 0;
854-
855- // FIXME(loicm) Opaque flag is forced for now for non-system sessions (applications) for
856- // performance reasons.
857- flags |= static_cast<uint>(IS_OPAQUE_FLAG);
858-
859- const QByteArray title = (!window()->title().isNull()) ? window()->title().toUtf8() : "Window 1"; // legacy title
860- const int panelHeight = d->panelHeight();
861-
862-#if !defined(QT_NO_DEBUG)
863- LOG("panelHeight: '%d'", panelHeight);
864- LOG("role: '%d'", role);
865- LOG("flags: '%s'", (flags & static_cast<uint>(1)) ? "Opaque" : "NotOpaque");
866- LOG("title: '%s'", title.constData());
867-#endif
868-
869- // Get surface geometry.
870- QRect geometry;
871- if (d->state == Qt::WindowFullScreen) {
872- printf("UbuntuWindow - fullscreen geometry\n");
873- geometry = screen()->geometry();
874- } else if (d->state == Qt::WindowMaximized) {
875- printf("UbuntuWindow - maximized geometry\n");
876- geometry = screen()->availableGeometry();
877- /*
878- * FIXME: Autopilot relies on being able to convert coordinates relative of the window
879- * into absolute screen coordinates. Mir does not allow this, see bug lp:1346633
880- * Until there's a correct way to perform this transformation agreed, this horrible hack
881- * guesses the transformation heuristically.
882- *
883- * Assumption: this method only used on phone devices!
884- */
885- geometry.setY(panelHeight);
886- } else {
887- printf("UbuntuWindow - regular geometry\n");
888- geometry = this->geometry();
889- geometry.setY(panelHeight);
890- }
891-
892- DLOG("[ubuntumirclient QPA] creating surface at (%d, %d) with size (%d, %d) with title '%s'\n",
893- geometry.x(), geometry.y(), geometry.width(), geometry.height(), title.data());
894-
895- MirSurfaceSpec *spec;
896- if (role == SCREEN_KEYBOARD_ROLE)
897- {
898- spec = mir_connection_create_spec_for_input_method(d->connection, geometry.width(),
899- geometry.height(), mir_choose_default_pixel_format(d->connection));
900- }
901- else
902- {
903- spec = mir_connection_create_spec_for_normal_surface(d->connection, geometry.width(),
904- geometry.height(), mir_choose_default_pixel_format(d->connection));
905- }
906- mir_surface_spec_set_name(spec, title.data());
907-
908- // Create platform window
909- mir_wait_for(mir_surface_create(spec, surfaceCreateCallback, this));
910- mir_surface_spec_release(spec);
911-
912- DASSERT(d->surface != NULL);
913- d->createEGLSurface((EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(d->surface)));
914-
915- if (d->state == Qt::WindowFullScreen) {
916- // TODO: We could set this on creation once surface spec supports it (mps already up)
917- mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_fullscreen));
918- }
919-
920- // Window manager can give us a final size different from what we asked for
921- // so let's check what we ended up getting
922- {
923+} //namespace
924+
925+class UbuntuSurface
926+{
927+public:
928+ UbuntuSurface(UbuntuWindow *platformWindow, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)
929+ : mWindow(platformWindow->window())
930+ , mPlatformWindow(platformWindow)
931+ , mInput(input)
932+ , mConnection(connection)
933+ , mMirSurface(createMirSurface(mWindow, screen, input, connection))
934+ , mEglDisplay(screen->eglDisplay())
935+ , mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr))
936+ , mVisible(false)
937+ , mNeedsRepaint(false)
938+ , mParented(mWindow->transientParent() || mWindow->parent())
939+ , mWindowState(mWindow->windowState())
940+
941+ {
942+ mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this);
943+
944+ // Window manager can give us a final size different from what we asked for
945+ // so let's check what we ended up getting
946 MirSurfaceParameters parameters;
947- mir_surface_get_parameters(d->surface, &parameters);
948-
949- geometry.setWidth(parameters.width);
950- geometry.setHeight(parameters.height);
951- }
952-
953- DLOG("[ubuntumirclient QPA] created surface has size (%d, %d)",
954- geometry.width(), geometry.height());
955-
956- // Assume that the buffer size matches the surface size at creation time
957- d->bufferSize = geometry.size();
958-
959- // Tell Qt about the geometry.
960- QWindowSystemInterface::handleGeometryChange(window(), geometry);
961- QPlatformWindow::setGeometry(geometry);
962-}
963-
964-void UbuntuWindow::moveResize(const QRect& rect)
965-{
966- (void) rect;
967- // TODO: Not yet supported by mir.
968-}
969-
970-void UbuntuWindow::handleSurfaceResize(int width, int height)
971-{
972- QMutexLocker(&d->mutex);
973- DLOG("UbuntuWindow::handleSurfaceResize(width=%d, height=%d) [%d]", width, height,
974- d->frameNumber);
975-
976- // The current buffer size hasn't actually changed. so just render on it and swap
977- // buffers in the hope that the next buffer will match the surface size advertised
978- // in this event.
979- // But since this event is processed by a thread different from the one that swaps
980- // buffers, you can never know if this information is already outdated as there's
981- // no synchronicity whatsoever between the processing of resize events and the
982- // consumption of buffers.
983- if (d->bufferSize.width() != width || d->bufferSize.height() != height) {
984- // if the next buffer doesn't have a different size, try some
985- // more
986- // FIXME: This is working around a mir bug! We really shound't have to
987- // swap more than once to get a buffer with the new size!
988- d->resizeCatchUpAttempts = 2;
989-
990- QWindowSystemInterface::handleExposeEvent(window(), geometry());
991- QWindowSystemInterface::flushWindowSystemEvents();
992- }
993-}
994-
995-void UbuntuWindow::handleSurfaceFocusChange(bool focused)
996-{
997- LOG("UbuntuWindow::handleSurfaceFocusChange(focused=%s)", focused ? "true" : "false");
998- QWindow *activatedWindow = focused ? window() : nullptr;
999-
1000- // System clipboard contents might have changed while this window was unfocused and wihtout
1001+ mir_surface_get_parameters(mMirSurface, &parameters);
1002+
1003+ auto geom = mWindow->geometry();
1004+ geom.setWidth(parameters.width);
1005+ geom.setHeight(parameters.height);
1006+ geom.setY(panelHeight());
1007+
1008+ // Assume that the buffer size matches the surface size at creation time
1009+ mBufferSize = geom.size();
1010+ platformWindow->QPlatformWindow::setGeometry(geom);
1011+ QWindowSystemInterface::handleGeometryChange(mWindow, geom);
1012+
1013+ DLOG("[ubuntumirclient QPA] created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n",
1014+ geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow));
1015+ }
1016+
1017+ ~UbuntuSurface()
1018+ {
1019+ if (mEglSurface != EGL_NO_SURFACE)
1020+ eglDestroySurface(mEglDisplay, mEglSurface);
1021+ if (mMirSurface)
1022+ mir_surface_release_sync(mMirSurface);
1023+ }
1024+
1025+ UbuntuSurface(UbuntuSurface const&) = delete;
1026+ UbuntuSurface& operator=(UbuntuSurface const&) = delete;
1027+
1028+ void resize(const QSize& newSize);
1029+ void setState(Qt::WindowState newState);
1030+ void setVisible(bool state);
1031+ void updateTitle(const QString& title);
1032+ void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
1033+
1034+ void onSwapBuffersDone();
1035+ void handleSurfaceResized(int width, int height);
1036+ int needsRepaint() const;
1037+
1038+ EGLSurface eglSurface() const { return mEglSurface; }
1039+ MirSurface *mirSurface() const { return mMirSurface; }
1040+
1041+private:
1042+ static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context);
1043+ void postEvent(const MirEvent *event);
1044+ void updateSurface();
1045+
1046+ QWindow * const mWindow;
1047+ UbuntuWindow * const mPlatformWindow;
1048+ UbuntuInput * const mInput;
1049+ MirConnection * const mConnection;
1050+
1051+ MirSurface * const mMirSurface;
1052+ const EGLDisplay mEglDisplay;
1053+ const EGLSurface mEglSurface;
1054+
1055+ bool mVisible;
1056+ bool mNeedsRepaint;
1057+ bool mParented;
1058+ Qt::WindowState mWindowState;
1059+ QSize mBufferSize;
1060+
1061+ QMutex mTargetSizeMutex;
1062+ QSize mTargetSize;
1063+};
1064+
1065+void UbuntuSurface::resize(const QSize& size)
1066+{
1067+ DLOG("[ubuntumirclient QPA] resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
1068+
1069+ if (mWindowState == Qt::WindowFullScreen || mWindowState == Qt::WindowMaximized) {
1070+ DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
1071+ return;
1072+ }
1073+
1074+ if (size.isEmpty()) {
1075+ DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, size is empty", mWindow);
1076+ return;
1077+ }
1078+
1079+ Spec spec{mir_connection_create_spec_for_changes(mConnection)};
1080+ mir_surface_spec_set_width(spec.get(), size.width());
1081+ mir_surface_spec_set_height(spec.get(), size.height());
1082+ mir_surface_apply_spec(mMirSurface, spec.get());
1083+}
1084+
1085+void UbuntuSurface::setState(Qt::WindowState newState)
1086+{
1087+ mir_wait_for(mir_surface_set_state(mMirSurface, qtWindowStateToMirSurfaceState(newState)));
1088+ mWindowState = newState;
1089+}
1090+
1091+void UbuntuSurface::setVisible(bool visible)
1092+{
1093+ if (mVisible == visible)
1094+ return;
1095+
1096+ mVisible = visible;
1097+
1098+ if (mVisible)
1099+ updateSurface();
1100+
1101+ // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
1102+ // Will have to change qtmir and unity8 for that.
1103+ const auto newState = visible ? qtWindowStateToMirSurfaceState(mWindowState) : mir_surface_state_minimized;
1104+ mir_wait_for(mir_surface_set_state(mMirSurface, newState));
1105+}
1106+
1107+void UbuntuSurface::updateTitle(const QString& newTitle)
1108+{
1109+ const auto title = newTitle.toUtf8();
1110+ Spec spec{mir_connection_create_spec_for_changes(mConnection)};
1111+ mir_surface_spec_set_name(spec.get(), title.constData());
1112+ mir_surface_apply_spec(mMirSurface, spec.get());
1113+}
1114+
1115+void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment)
1116+{
1117+ Spec spec{mir_connection_create_spec_for_changes(mConnection)};
1118+ ::setSizingConstraints(spec.get(), minSize, maxSize, increment);
1119+ mir_surface_apply_spec(mMirSurface, spec.get());
1120+}
1121+
1122+void UbuntuSurface::handleSurfaceResized(int width, int height)
1123+{
1124+ QMutexLocker lock(&mTargetSizeMutex);
1125+
1126+ // mir's resize event is mainly a signal that we need to redraw our content. We use the
1127+ // width/height as identifiers to figure out if this is the latest surface resize event
1128+ // that has posted, discarding any old ones. This avoids issuing too many redraw events.
1129+ // see TODO in postEvent as the ideal way we should handle this.
1130+ // The actual buffer size may or may have not changed at this point, so let the rendering
1131+ // thread drive the window geometry updates.
1132+ mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height;
1133+}
1134+
1135+int UbuntuSurface::needsRepaint() const
1136+{
1137+ if (mNeedsRepaint) {
1138+ if (mTargetSize != mBufferSize) {
1139+ //If the buffer hasn't changed yet, we need at least two redraws,
1140+ //once to get the new buffer size and propagate the geometry changes
1141+ //and the second to redraw the content at the new size
1142+ return 2;
1143+ } else {
1144+ // The buffer size has already been updated so we only need one redraw
1145+ // to render at the new size
1146+ return 1;
1147+ }
1148+ }
1149+ return 0;
1150+}
1151+
1152+void UbuntuSurface::onSwapBuffersDone()
1153+{
1154+#if !defined(QT_NO_DEBUG)
1155+ static int sFrameNumber = 0;
1156+ ++sFrameNumber;
1157+#endif
1158+
1159+ EGLint eglSurfaceWidth = -1;
1160+ EGLint eglSurfaceHeight = -1;
1161+ eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth);
1162+ eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight);
1163+
1164+ const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0;
1165+
1166+ if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {
1167+
1168+ DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
1169+ mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);
1170+
1171+ mBufferSize.rwidth() = eglSurfaceWidth;
1172+ mBufferSize.rheight() = eglSurfaceHeight;
1173+
1174+ QRect newGeometry = mPlatformWindow->geometry();
1175+ newGeometry.setSize(mBufferSize);
1176+
1177+ mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
1178+ QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
1179+ } else {
1180+ DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
1181+ mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());
1182+ }
1183+}
1184+
1185+void UbuntuSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context)
1186+{
1187+ Q_UNUSED(surface);
1188+ Q_ASSERT(context != nullptr);
1189+
1190+ auto s = static_cast<UbuntuSurface *>(context);
1191+ s->postEvent(event);
1192+}
1193+
1194+void UbuntuSurface::postEvent(const MirEvent *event)
1195+{
1196+ if (mir_event_type_resize == mir_event_get_type(event)) {
1197+ // TODO: The current event queue just accumulates all resize events;
1198+ // It would be nicer if we could update just one event if that event has not been dispatched.
1199+ // As a workaround, we use the width/height as an identifier of this latest event
1200+ // so the event handler (handleSurfaceResized) can discard/ignore old ones.
1201+ const auto resizeEvent = mir_event_get_resize_event(event);
1202+ const auto width = mir_resize_event_get_width(resizeEvent);
1203+ const auto height = mir_resize_event_get_height(resizeEvent);
1204+ DLOG("[ubuntumirclient QPA] resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);
1205+
1206+ QMutexLocker lock(&mTargetSizeMutex);
1207+ mTargetSize.rwidth() = width;
1208+ mTargetSize.rheight() = height;
1209+ }
1210+
1211+ mInput->postEvent(mPlatformWindow, event);
1212+}
1213+
1214+void UbuntuSurface::updateSurface()
1215+{
1216+ DLOG("[ubuntumirclient QPA] updateSurface(window=%p)", mWindow);
1217+
1218+ if (!mParented && mWindow->type() == Qt::Dialog) {
1219+ // The dialog may have been parented after creation time
1220+ // so morph it into a modal dialog
1221+ auto parent = transientParentFor(mWindow);
1222+ if (parent) {
1223+ DLOG("[ubuntumirclient QPA] updateSurface(window=%p) dialog now parented", mWindow);
1224+ mParented = true;
1225+ Spec spec{mir_connection_create_spec_for_changes(mConnection)};
1226+ mir_surface_spec_set_parent(spec.get(), parent->mirSurface());
1227+ mir_surface_apply_spec(mMirSurface, spec.get());
1228+ }
1229+ }
1230+}
1231+
1232+UbuntuWindow::UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard, UbuntuScreen *screen,
1233+ UbuntuInput *input, MirConnection *connection)
1234+ : QObject(nullptr)
1235+ , QPlatformWindow(w)
1236+ , mId(makeId())
1237+ , mClipboard(clipboard)
1238+ , mSurface(new UbuntuSurface{this, screen, input, connection})
1239+{
1240+ DLOG("[ubuntumirclient QPA] UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());
1241+}
1242+
1243+UbuntuWindow::~UbuntuWindow()
1244+{
1245+ DLOG("[ubuntumirclient QPA] ~UbuntuWindow(window=%p)", this);
1246+}
1247+
1248+void UbuntuWindow::handleSurfaceResized(int width, int height)
1249+{
1250+ QMutexLocker lock(&mMutex);
1251+ DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height);
1252+
1253+ mSurface->handleSurfaceResized(width, height);
1254+
1255+ // This resize event could have occurred just after the last buffer swap for this window.
1256+ // This means the client may still be holding a buffer with the older size. The first redraw call
1257+ // will then render at the old size. After swapping the client now will get a new buffer with the
1258+ // updated size but it still needs re-rendering so another redraw may be needed.
1259+ // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice
1260+ auto const numRepaints = mSurface->needsRepaint();
1261+ DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
1262+ for (int i = 0; i < numRepaints; i++) {
1263+ DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());
1264+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
1265+ }
1266+}
1267+
1268+void UbuntuWindow::handleSurfaceFocused()
1269+{
1270+ DLOG("[ubuntumirclient QPA] handleSurfaceFocused(window=%p)", window());
1271+
1272+ // System clipboard contents might have changed while this window was unfocused and without
1273 // this process getting notified about it because it might have been suspended (due to
1274 // application lifecycle policies), thus unable to listen to any changes notified through
1275 // D-Bus.
1276 // Therefore let's ensure we are up to date with the system clipboard now that we are getting
1277 // focused again.
1278- if (focused) {
1279- d->clipboard->requestDBusClipboardContents();
1280- }
1281-
1282- QWindowSystemInterface::handleWindowActivated(activatedWindow, Qt::ActiveWindowFocusReason);
1283+ mClipboard->requestDBusClipboardContents();
1284+ QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
1285 }
1286
1287 void UbuntuWindow::setWindowState(Qt::WindowState state)
1288 {
1289- QMutexLocker(&d->mutex);
1290- DLOG("UbuntuWindow::setWindowState (this=%p, %s)", this, qtWindowStateToStr(state));
1291-
1292- if (state == d->state)
1293- return;
1294-
1295- // TODO: Perhaps we should check if the states are applied?
1296- mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(state)));
1297- d->state = state;
1298+ QMutexLocker lock(&mMutex);
1299+ DLOG("[ubuntumirclient QPA] setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
1300+ mSurface->setState(state);
1301 }
1302
1303 void UbuntuWindow::setGeometry(const QRect& rect)
1304 {
1305- DLOG("UbuntuWindow::setGeometry (this=%p)", this);
1306-
1307- bool doMoveResize;
1308-
1309- {
1310- QMutexLocker(&d->mutex);
1311- QPlatformWindow::setGeometry(rect);
1312- doMoveResize = d->state != Qt::WindowFullScreen && d->state != Qt::WindowMaximized;
1313- }
1314-
1315- if (doMoveResize) {
1316- moveResize(rect);
1317- }
1318+ QMutexLocker lock(&mMutex);
1319+ DLOG("[ubuntumirclient QPA] setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)",
1320+ window(), rect.x(), rect.y(), rect.width(), rect.height());
1321+
1322+ //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates
1323+ const auto newSize = rect.size();
1324+ auto newGeometry = geometry();
1325+ newGeometry.setSize(newSize);
1326+ QPlatformWindow::setGeometry(newGeometry);
1327+
1328+ mSurface->resize(newSize);
1329 }
1330
1331 void UbuntuWindow::setVisible(bool visible)
1332 {
1333- QMutexLocker(&d->mutex);
1334- DLOG("UbuntuWindow::setVisible (this=%p, visible=%s)", this, visible ? "true" : "false");
1335-
1336- if (visible) {
1337- mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(d->state)));
1338-
1339- QWindowSystemInterface::handleExposeEvent(window(), QRect());
1340- QWindowSystemInterface::flushWindowSystemEvents();
1341- } else {
1342- // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
1343- // Will have to change qtmir and unity8 for that.
1344- mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_minimized));
1345- }
1346-}
1347-
1348-void UbuntuWindow::setWindowTitle(const QString &title)
1349-{
1350- MirSurfaceSpec *spec = mir_connection_create_spec_for_changes(d->connection);
1351- mir_surface_spec_set_name(spec, title.toUtf8().constData());
1352- mir_surface_apply_spec(d->surface, spec);
1353- mir_surface_spec_release(spec);
1354+ QMutexLocker lock(&mMutex);
1355+ DLOG("[ubuntumirclient QPA] setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false");
1356+
1357+ mSurface->setVisible(visible);
1358+ const QRect& exposeRect = visible ? QRect(QPoint(), geometry().size()) : QRect();
1359+
1360+ lock.unlock();
1361+ QWindowSystemInterface::handleExposeEvent(window(), exposeRect);
1362+ QWindowSystemInterface::flushWindowSystemEvents();
1363+}
1364+
1365+void UbuntuWindow::setWindowTitle(const QString& title)
1366+{
1367+ QMutexLocker lock(&mMutex);
1368+ DLOG("[ubuntumirclient QPA] setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
1369+ mSurface->updateTitle(title);
1370+}
1371+
1372+void UbuntuWindow::propagateSizeHints()
1373+{
1374+ QMutexLocker lock(&mMutex);
1375+ const auto win = window();
1376+ DLOG("[ubuntumirclient QPA] propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",
1377+ win, win->minimumSize().width(), win->minimumSize().height(),
1378+ win->maximumSize().width(), win->maximumSize().height(),
1379+ win->sizeIncrement().width(), win->sizeIncrement().height());
1380+ mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement());
1381 }
1382
1383 void* UbuntuWindow::eglSurface() const
1384 {
1385- return d->eglSurface;
1386+ return mSurface->eglSurface();
1387+}
1388+
1389+MirSurface *UbuntuWindow::mirSurface() const
1390+{
1391+ return mSurface->mirSurface();
1392 }
1393
1394 WId UbuntuWindow::winId() const
1395 {
1396- return d->id;
1397+ return mId;
1398 }
1399
1400-void UbuntuWindow::onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight)
1401+void UbuntuWindow::onSwapBuffersDone()
1402 {
1403- QMutexLocker(&d->mutex);
1404-
1405- bool sizeKnown = newBufferWidth > 0 && newBufferHeight > 0;
1406-
1407-#if !defined(QT_NO_DEBUG)
1408- ++d->frameNumber;
1409-#endif
1410-
1411- if (sizeKnown && (d->bufferSize.width() != newBufferWidth ||
1412- d->bufferSize.height() != newBufferHeight)) {
1413- d->resizeCatchUpAttempts = 0;
1414-
1415- DLOG("UbuntuWindow::onBuffersSwapped_threadSafe [%d] - buffer size changed from (%d,%d) to (%d,%d)"
1416- " resizeCatchUpAttempts=%d",
1417- d->frameNumber, d->bufferSize.width(), d->bufferSize.height(), newBufferWidth, newBufferHeight,
1418- d->resizeCatchUpAttempts);
1419-
1420- d->bufferSize.rwidth() = newBufferWidth;
1421- d->bufferSize.rheight() = newBufferHeight;
1422-
1423- QRect newGeometry;
1424-
1425- newGeometry = geometry();
1426- newGeometry.setWidth(d->bufferSize.width());
1427- newGeometry.setHeight(d->bufferSize.height());
1428-
1429- QPlatformWindow::setGeometry(newGeometry);
1430- QWindowSystemInterface::handleGeometryChange(window(), newGeometry, QRect());
1431- } else if (d->resizeCatchUpAttempts > 0) {
1432- --d->resizeCatchUpAttempts;
1433- DLOG("UbuntuWindow::onBuffersSwapped_threadSafe [%d] - buffer size (%d,%d). Redrawing to catch up a resized buffer."
1434- " resizeCatchUpAttempts=%d",
1435- d->frameNumber, d->bufferSize.width(), d->bufferSize.height(), d->resizeCatchUpAttempts);
1436- QWindowSystemInterface::handleExposeEvent(window(), geometry());
1437- } else {
1438- DLOG("UbuntuWindow::onBuffersSwapped_threadSafe [%d] - buffer size (%d,%d). resizeCatchUpAttempts=%d",
1439- d->frameNumber, d->bufferSize.width(), d->bufferSize.height(), d->resizeCatchUpAttempts);
1440- }
1441+ QMutexLocker lock(&mMutex);
1442+ mSurface->onSwapBuffersDone();
1443 }
1444
1445=== modified file 'src/ubuntumirclient/window.h'
1446--- src/ubuntumirclient/window.h 2015-11-09 19:26:55 +0000
1447+++ src/ubuntumirclient/window.h 2015-11-17 13:42:51 +0000
1448@@ -19,20 +19,23 @@
1449
1450 #include <qpa/qplatformwindow.h>
1451 #include <QSharedPointer>
1452+#include <QMutex>
1453
1454-#include <mir_toolkit/mir_client_library.h>
1455+#include <memory>
1456
1457 class UbuntuClipboard;
1458 class UbuntuInput;
1459 class UbuntuScreen;
1460-class UbuntuWindowPrivate;
1461+class UbuntuSurface;
1462+struct MirConnection;
1463+struct MirSurface;
1464
1465 class UbuntuWindow : public QObject, public QPlatformWindow
1466 {
1467 Q_OBJECT
1468 public:
1469- UbuntuWindow(QWindow *w, QSharedPointer<UbuntuClipboard> clipboard, UbuntuScreen *screen,
1470- UbuntuInput *input, MirConnection *mir_connection);
1471+ UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard, UbuntuScreen *screen,
1472+ UbuntuInput *input, MirConnection *mirConnection);
1473 virtual ~UbuntuWindow();
1474
1475 // QPlatformWindow methods.
1476@@ -41,20 +44,20 @@
1477 void setWindowState(Qt::WindowState state) override;
1478 void setVisible(bool visible) override;
1479 void setWindowTitle(const QString &title) override;
1480+ void propagateSizeHints() override;
1481
1482 // New methods.
1483- void* eglSurface() const;
1484- void handleSurfaceResize(int width, int height);
1485- void handleSurfaceFocusChange(bool focused);
1486- void onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight);
1487-
1488- UbuntuWindowPrivate* priv() { return d; }
1489+ void *eglSurface() const;
1490+ MirSurface *mirSurface() const;
1491+ void handleSurfaceResized(int width, int height);
1492+ void handleSurfaceFocused();
1493+ void onSwapBuffersDone();
1494
1495 private:
1496- void createWindow();
1497- void moveResize(const QRect& rect);
1498-
1499- UbuntuWindowPrivate *d;
1500+ mutable QMutex mMutex;
1501+ const WId mId;
1502+ const QSharedPointer<UbuntuClipboard> mClipboard;
1503+ std::unique_ptr<UbuntuSurface> mSurface;
1504 };
1505
1506 #endif // UBUNTU_WINDOW_H

Subscribers

People subscribed via source and target branches