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

Proposed by Alberto Aguirre on 2015-06-17
Status: Superseded
Proposed branch: lp:~albaguirre/qtubuntu/use-mir-surface-apis
Merge into: lp:qtubuntu
Diff against target: 892 lines (+369/-277)
5 files modified
src/ubuntumirclient/integration.cpp (+14/-15)
src/ubuntumirclient/nativeinterface.cpp (+5/-5)
src/ubuntumirclient/screen.cpp (+6/-6)
src/ubuntumirclient/window.cpp (+338/-243)
src/ubuntumirclient/window.h (+6/-8)
To merge this branch: bzr merge lp:~albaguirre/qtubuntu/use-mir-surface-apis
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve on 2015-07-31
Gerry Boland 2015-06-17 Needs Fixing on 2015-07-29
Review via email: mp+262257@code.launchpad.net

This proposal has been superseded by a proposal from 2015-08-06.

Commit Message

Use apis provided by mir to translate some QT window types into mir surface types.

Description of the Change

Use apis provided by mir to translate some QT window types into mir surface types.

Some refactoring and cleanup.
Support geometry size changes.

To post a comment you must log in.
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
270. By Alberto Aguirre on 2015-07-01

merge lp:qtubuntu, fix conflicts

271. By Alberto Aguirre on 2015-07-01

Fix conflict resolution

PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
272. By Alberto Aguirre on 2015-07-08

merge lp:~albaguirre/qtubuntu/migrate-to-papi3

273. By Alberto Aguirre on 2015-07-08

merge lp:qtubuntu

PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
274. By Alberto Aguirre on 2015-07-28

merge lp:qtubuntu

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

+++ src/ubuntumirclient/window.cpp
+ MirSurface * const mirSurface_;
+ EGLSurface eglSurface_;
Class members are named mSomething in qtubuntu, please adopt that naming scheme.

+MirPixelFormat defaultPixelFormat(MirConnection *connection)
....
+ return format;
+}
+}
That last brace is the end of the namespace, would you please stick a comment like "// namespace" after it, helps me see the namespace end more clearly.

+ if (state == Qt::WindowFullScreen) {
+ auto displayConfig = mir_connection_create_display_config(connection);
+ if (displayConfig->num_outputs > 0) {
+ auto outputId = displayConfig->outputs[0].output_id;
Think we should add a FIXME here, as we're guessing there's only 1 display at the moment.

+void UbuntuWindowPrivate::setSurfaceState(Qt::WindowState new_state)
+{
+ mir_wait_for(mir_surface_set_state(surface->mirSurface(), qtWindowStateToMirSurfaceState(new_state)));
Does this need to be sync?

+ geom.setY(panelHeight);
/me wants to kill this so badly! :)

#if !defined(QT_NO_DEBUG)
- LOG("panelHeight: '%d'", panelHeight);
+ DLOG("[ubuntumirclient QPA] panelHeight: '%d'", panelHeight);
The QT_NO_DEBUG should do the same things as DLOG - only print when compiled in debug mode. So can probably drop the !defined(QT_NO_DEBUG)

The fun part is testing, I'll be at that soon. While I know we're missing the window management side of things, should I give some real apps a try? What would you consider fair testing?

review: Needs Fixing
Alberto Aguirre (albaguirre) wrote :

@Gerry, yeah any real apps. I tried QtCreator in the desktop and mir_demo_server. It's not quite there yet - the big one is the relative positioning for the embedded window.

Alberto Aguirre (albaguirre) wrote :

>+ geom.setY(panelHeight);
>/me wants to kill this so badly! :)

Can we? We added a debug mirclient library to support autopilot testing a while back (mir_toolkit/debug/surface.h - mir_debug_surface_coords_to_screen(...))

275. By Alberto Aguirre on 2015-07-30

Address feedback comments.

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
276. By Alberto Aguirre on 2015-07-31

More hungarian notation

Alberto Aguirre (albaguirre) wrote :

>+void UbuntuWindowPrivate::setSurfaceState(Qt::WindowState new_state)
>+{
>+ mir_wait_for(mir_surface_set_state(surface->mirSurface(), >qtWindowStateToMirSurfaceState(new_state)));
>Does this need to be sync?

As in does the call really need to wait for the wait handle? or call a mir_surface_set_state_sync api? (which does not exist in any case)

In any case the wait for set_state is pre-existing, so I didn't change it.

The rest should be fixed now.

PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
277. By Alberto Aguirre on 2015-08-06

merge lp:~dandrader/qtubuntu/busySwap-lp1473720

278. By Alberto Aguirre on 2015-08-10

Fix typo made during camel case renaming.

279. By Alberto Aguirre on 2015-08-25

Separate visibility from mir surface state

280. By Alberto Aguirre on 2015-10-15

merge lp:qtubuntu, fix conflict

281. By Alberto Aguirre on 2015-10-16

Ignore unfocusing events

282. By Alberto Aguirre on 2015-10-21

Remove tab chars

283. By Alberto Aguirre on 2015-10-21

Do not remove framenumber debug logs

284. By Alberto Aguirre on 2015-10-21

Restore TODO to use mir_surface_state_hidden

285. By Alberto Aguirre on 2015-10-21

Send expose event if Qt resizes a window after its visible.

Some window types created in QML are made visible before their final geometry is set. If the content of the window does not update, the first frame will be grey unless we inform Qt of the new exposed size.

286. By Alberto Aguirre on 2015-10-21

When a window is made visible expose the correct region in local coordinates.

287. By Alberto Aguirre on 2015-10-22

Track the last surface to receive input.

The last surface to receive input can be used as a parent when QT decides to create popups without parent information (such as the menubar menus in qtcreator).

288. By Alberto Aguirre on 2015-10-22

More cleanup.

Go back to creating surfaces at window creation time. On older QT releases, some menu surfaces
did not have transientParent information at create time.

289. By Alberto Aguirre on 2015-10-22

Fix usage of mutex to protect private state.

Previously "QMutexLocker(&d->mMutex)" was used which is just a temporary that gets immedietely deleted so there was no mutex protection.

290. By Alberto Aguirre on 2015-10-22

Initialize egl surface at construction time.

Windows are created at construction time again, so eglsurfaces are safe to be constructed there too.

291. By Alberto Aguirre on 2015-10-23

More cleanup

292. By Alberto Aguirre on 2015-10-23

Fix resize handling behavior.

We discard old accumulated resize events to avoid issuing too many redraw events greatly
improving resize performance.

293. By Alberto Aguirre on 2015-10-23

Use screen output id when creating a fullscreen mir surface.

294. By Alberto Aguirre on 2015-10-24

Avoid telling Qt that no windows have focus when receiving a focus lost/gained pair.

Mir may send a focus lost/gained pair of events whenever a new surface gains focus (previous surface loses focus).
Qt's handleWindowActivated API however only supports focusing a single window or not focusing anything.
When processing the surface focus lost message we need to peek into the pending events to check for any posted focus gained event so that only a single handleWindowActivated call is made.

295. By Alberto Aguirre on 2015-10-25

Support morphing non-modal to modal dialog.

QML dialogs are not parented when created. The transientParent will be set after creation but before the window is made visible.
Update the mir surface with the new parent information when the window is made visible

296. By Alberto Aguirre on 2015-10-25

Support updating title

297. By Alberto Aguirre on 2015-10-25

Add support for propagateSizeHints

298. By Alberto Aguirre on 2015-10-25

Update log message

299. By Alberto Aguirre on 2015-10-25

Slight cleanup

300. By Alberto Aguirre on 2015-10-26

Fix resize corner case

301. By Alberto Aguirre on 2015-10-26

merge lp:qtubuntu, fix conflicts

302. By Alberto Aguirre on 2015-10-27

Don't create 0x0 mir surfaces

Seems to be a bug in the pixmap window that is created for the drag and drop default platform implementation.

303. By Alberto Aguirre on 2015-11-16

merge lp:~dandrader/qtubuntu/fix-use-mir-surface-apis

304. By Alberto Aguirre on 2015-11-16

merge lp:~dandrader/qtubuntu/sizeHintsOnWindowCreation

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ubuntumirclient/integration.cpp'
2--- src/ubuntumirclient/integration.cpp 2015-06-23 22:19:27 +0000
3+++ src/ubuntumirclient/integration.cpp 2015-08-06 17:13:12 +0000
4@@ -14,28 +14,28 @@
5 * along with this program. If not, see <http://www.gnu.org/licenses/>.
6 */
7
8-// Qt
9-#include <QGuiApplication>
10-#include <private/qguiapplication_p.h>
11-#include <qpa/qplatformnativeinterface.h>
12-#include <qpa/qplatforminputcontextfactory_p.h>
13-#include <qpa/qplatforminputcontext.h>
14-#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
15-#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
16-#include <QOpenGLContext>
17-
18 // Local
19+#include "integration.h"
20 #include "backingstore.h"
21 #include "clipboard.h"
22 #include "glcontext.h"
23 #include "input.h"
24-#include "integration.h"
25 #include "logging.h"
26 #include "nativeinterface.h"
27 #include "screen.h"
28 #include "theme.h"
29 #include "window.h"
30
31+// Qt
32+#include <QGuiApplication>
33+#include <private/qguiapplication_p.h>
34+#include <qpa/qplatformnativeinterface.h>
35+#include <qpa/qplatforminputcontextfactory_p.h>
36+#include <qpa/qplatforminputcontext.h>
37+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
38+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
39+#include <QOpenGLContext>
40+
41 // platform-api
42 #include <ubuntu/application/lifecycle_delegate.h>
43 #include <ubuntu/application/id.h>
44@@ -166,11 +166,9 @@
45 switch (cap) {
46 case ThreadedPixmaps:
47 return true;
48- break;
49
50 case OpenGL:
51 return true;
52- break;
53
54 case ThreadedOpenGL:
55 if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) {
56@@ -179,8 +177,9 @@
57 DLOG("ubuntumirclient: disabled threaded OpenGL");
58 return false;
59 }
60- break;
61-
62+ case MultipleWindows:
63+ case NonFullScreenWindows:
64+ return true;
65 default:
66 return QPlatformIntegration::hasCapability(cap);
67 }
68
69=== modified file 'src/ubuntumirclient/nativeinterface.cpp'
70--- src/ubuntumirclient/nativeinterface.cpp 2014-06-18 23:10:00 +0000
71+++ src/ubuntumirclient/nativeinterface.cpp 2015-08-06 17:13:12 +0000
72@@ -14,17 +14,17 @@
73 * along with this program. If not, see <http://www.gnu.org/licenses/>.
74 */
75
76+// Local
77+#include "nativeinterface.h"
78+#include "screen.h"
79+#include "glcontext.h"
80+
81 // Qt
82 #include <private/qguiapplication_p.h>
83 #include <QtGui/qopenglcontext.h>
84 #include <QtGui/qscreen.h>
85 #include <QtCore/QMap>
86
87-// Local
88-#include "nativeinterface.h"
89-#include "screen.h"
90-#include "glcontext.h"
91-
92 class UbuntuResourceMap : public QMap<QByteArray, UbuntuNativeInterface::ResourceType>
93 {
94 public:
95
96=== modified file 'src/ubuntumirclient/screen.cpp'
97--- src/ubuntumirclient/screen.cpp 2015-06-24 17:21:21 +0000
98+++ src/ubuntumirclient/screen.cpp 2015-08-06 17:13:12 +0000
99@@ -14,6 +14,11 @@
100 * along with this program. If not, see <http://www.gnu.org/licenses/>.
101 */
102
103+// local
104+#include "screen.h"
105+#include "logging.h"
106+#include "orientationchangeevent_p.h"
107+
108 #include <mir_toolkit/mir_client_library.h>
109
110 // Qt
111@@ -24,12 +29,7 @@
112 #include <qpa/qwindowsysteminterface.h>
113 #include <QtPlatformSupport/private/qeglconvenience_p.h>
114
115-// local
116-#include "screen.h"
117-#include "logging.h"
118-#include "orientationchangeevent_p.h"
119-
120-#include "memory"
121+#include <memory>
122
123 static const int kSwapInterval = 1;
124
125
126=== modified file 'src/ubuntumirclient/window.cpp'
127--- src/ubuntumirclient/window.cpp 2015-06-24 17:21:21 +0000
128+++ src/ubuntumirclient/window.cpp 2015-08-06 17:13:12 +0000
129@@ -15,12 +15,14 @@
130 */
131
132 // Local
133+#include "window.h"
134 #include "clipboard.h"
135 #include "input.h"
136-#include "window.h"
137 #include "screen.h"
138 #include "logging.h"
139
140+#include <mir_toolkit/mir_client_library.h>
141+
142 // Qt
143 #include <qpa/qwindowsysteminterface.h>
144 #include <qpa/qwindowsysteminterface.h>
145@@ -34,10 +36,70 @@
146
147 #include <EGL/egl.h>
148
149-#define IS_OPAQUE_FLAG 1
150-
151 namespace
152 {
153+
154+// FIXME: this used to be defined by platform-api, but it's been removed in v3. Change ubuntu-keyboard to use
155+// a different enum for window roles.
156+enum UAUiWindowRole {
157+ U_MAIN_ROLE = 1,
158+ U_DASH_ROLE,
159+ U_INDICATOR_ROLE,
160+ U_NOTIFICATIONS_ROLE,
161+ U_GREETER_ROLE,
162+ U_LAUNCHER_ROLE,
163+ U_ON_SCREEN_KEYBOARD_ROLE,
164+ U_SHUTDOWN_DIALOG_ROLE,
165+};
166+
167+struct MirSpecDeleter
168+{
169+ void operator()(MirSurfaceSpec *spec) { mir_surface_spec_release(spec); }
170+};
171+
172+EGLNativeWindowType nativeWindowFor(MirSurface *surf)
173+{
174+ auto stream = mir_surface_get_buffer_stream(surf);
175+ return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream));
176+}
177+
178+class Surface
179+{
180+public:
181+ Surface(MirSurface *surface, UbuntuScreen *screen)
182+ : mMirSurface{surface},
183+ mEglDisplay{screen->eglDisplay()},
184+ mEglConfig{screen->eglConfig()},
185+ mEglSurface{EGL_NO_SURFACE}
186+ {
187+ }
188+
189+ ~Surface()
190+ {
191+ if (mEglSurface != EGL_NO_SURFACE)
192+ eglDestroySurface(mEglDisplay, mEglSurface);
193+ if (mMirSurface)
194+ mir_surface_release_sync(mMirSurface);
195+ }
196+
197+ EGLSurface eglSurface()
198+ {
199+ if (mEglSurface == EGL_NO_SURFACE)
200+ {
201+ mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, nativeWindowFor(mMirSurface), nullptr);
202+ }
203+ return mMirSurface;
204+ }
205+
206+ MirSurface *mirSurface() const { return mMirSurface; }
207+
208+private:
209+ MirSurface * const mMirSurface;
210+ const EGLDisplay mEglDisplay;
211+ const EGLConfig mEglConfig;
212+ EGLSurface mEglSurface;
213+};
214+
215 MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
216 {
217 switch (state) {
218@@ -81,102 +143,83 @@
219 }
220 #endif
221
222-} // anonymous namespace
223-
224-class UbuntuWindowPrivate
225-{
226-public:
227- void createEGLSurface(EGLNativeWindowType nativeWindow);
228- void destroyEGLSurface();
229- int panelHeight();
230-
231- UbuntuScreen* screen;
232- EGLSurface eglSurface;
233- WId id;
234- UbuntuInput* input;
235- Qt::WindowState state;
236- MirConnection *connection;
237- MirSurface* surface;
238- QSize bufferSize;
239- QSize targetBufferSize;
240- QMutex mutex;
241- QSharedPointer<UbuntuClipboard> clipboard;
242+WId generateWindowID()
243+{
244+ static int id = 1;
245+ return ++id;
246+}
247+
248+MirPixelFormat defaultPixelFormat(MirConnection *connection)
249+{
250+ MirPixelFormat format;
251+ unsigned int nformats;
252+ mir_connection_get_available_surface_formats(connection, &format, 1, &nformats);
253+ return format;
254+}
255+} // namespace
256+
257+struct UbuntuWindowPrivate
258+{
259+ UbuntuWindowPrivate(UbuntuWindow *w, UbuntuScreen *screen, UbuntuInput *input, Qt::WindowState state,
260+ MirConnection *connection, const QSharedPointer<UbuntuClipboard>& clipboard)
261+ : mWindow{w}, mScreen{screen}, mInput{input}, mConnection{connection}, mPixelFormat{defaultPixelFormat(connection)},
262+ mClipboard{clipboard}, mId{generateWindowID()}, mState{state}
263+ {}
264+
265+ UAUiWindowRole role();
266+ UbuntuWindow *transientParent();
267+ MirSurface *parentSurface();
268+
269+ void createWindow();
270+ std::unique_ptr<MirSurfaceSpec, MirSpecDeleter> createSpec(const QRect& rect);
271+ void createSurface(QRect& geom, const char *name);
272+
273+ void resize(const QRect& rect);
274+ void setSurfaceState(Qt::WindowState state);
275+
276+ EGLSurface eglSurface()
277+ {
278+ // Sometimes an egl surface is requested without making the window visible first
279+ createWindow();
280+ return mSurface->eglSurface();
281+ }
282+ MirSurface *mirSurface() const { return mSurface->mirSurface(); }
283+
284+ UbuntuWindow * const mWindow;
285+ UbuntuScreen * const mScreen;
286+ UbuntuInput * const mInput;
287+ MirConnection * const mConnection;
288+ const MirPixelFormat mPixelFormat;
289+ const QSharedPointer<UbuntuClipboard> mClipboard;
290+ const WId mId;
291+ Qt::WindowState mState;
292+ std::unique_ptr<Surface> mSurface;
293+ QSize mBufferSize;
294+ QMutex mMutex;
295 };
296
297-static void eventCallback(MirSurface* surface, const MirEvent *event, void* context)
298+namespace
299+{
300+void eventCallback(MirSurface* surface, const MirEvent *event, void* context)
301 {
302 (void) surface;
303 DASSERT(context != NULL);
304- UbuntuWindow* platformWindow = static_cast<UbuntuWindow*>(context);
305- platformWindow->priv()->input->postEvent(platformWindow, event);
306+ UbuntuWindowPrivate *priv = static_cast<UbuntuWindowPrivate*>(context);
307+ priv->mInput->postEvent(priv->mWindow, event);
308 }
309
310-static void surfaceCreateCallback(MirSurface* surface, void* context)
311+void surfaceCreateCallback(MirSurface* surface, void* context)
312 {
313 DASSERT(context != NULL);
314- UbuntuWindow* platformWindow = static_cast<UbuntuWindow*>(context);
315- platformWindow->priv()->surface = surface;
316+ UbuntuWindowPrivate *priv = static_cast<UbuntuWindowPrivate*>(context);
317+ priv->mSurface = std::move(std::unique_ptr<Surface>(new Surface(surface, priv->mScreen)));
318
319 mir_surface_set_event_handler(surface, eventCallback, context);
320 }
321
322-UbuntuWindow::UbuntuWindow(QWindow* w, QSharedPointer<UbuntuClipboard> clipboard, UbuntuScreen* screen,
323- UbuntuInput* input, MirConnection* connection)
324- : QObject(nullptr), QPlatformWindow(w)
325-{
326- DASSERT(screen != NULL);
327-
328- d = new UbuntuWindowPrivate;
329- d->screen = screen;
330- d->eglSurface = EGL_NO_SURFACE;
331- d->input = input;
332- d->state = window()->windowState();
333- d->connection = connection;
334- d->clipboard = clipboard;
335-
336- static int id = 1;
337- d->id = id++;
338-
339- // Use client geometry if set explicitly, use available screen geometry otherwise.
340- QPlatformWindow::setGeometry(window()->geometry() != screen->geometry() ?
341- window()->geometry() : screen->availableGeometry());
342- createWindow();
343- DLOG("UbuntuWindow::UbuntuWindow (this=%p, w=%p, screen=%p, input=%p)", this, w, screen, input);
344-}
345-
346-UbuntuWindow::~UbuntuWindow()
347-{
348- DLOG("UbuntuWindow::~UbuntuWindow");
349- d->destroyEGLSurface();
350-
351- mir_surface_release_sync(d->surface);
352-
353- delete d;
354-}
355-
356-void UbuntuWindowPrivate::createEGLSurface(EGLNativeWindowType nativeWindow)
357-{
358- DLOG("UbuntuWindowPrivate::createEGLSurface (this=%p, nativeWindow=%p)",
359- this, reinterpret_cast<void*>(nativeWindow));
360-
361- eglSurface = eglCreateWindowSurface(screen->eglDisplay(), screen->eglConfig(),
362- nativeWindow, nullptr);
363-
364- DASSERT(eglSurface != EGL_NO_SURFACE);
365-}
366-
367-void UbuntuWindowPrivate::destroyEGLSurface()
368-{
369- DLOG("UbuntuWindowPrivate::destroyEGLSurface (this=%p)", this);
370- if (eglSurface != EGL_NO_SURFACE) {
371- eglDestroySurface(screen->eglDisplay(), eglSurface);
372- eglSurface = EGL_NO_SURFACE;
373- }
374-}
375-
376 // FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
377 // we need to guess the panel height (3GU + 2DP)
378-int UbuntuWindowPrivate::panelHeight()
379+int panelHeight()
380 {
381 const int defaultGridUnit = 8;
382 int gridUnit = defaultGridUnit;
383@@ -191,57 +234,134 @@
384 qreal densityPixelRatio = static_cast<qreal>(gridUnit) / defaultGridUnit;
385 return gridUnit * 3 + qFloor(densityPixelRatio) * 2;
386 }
387-
388-namespace
389-{
390-static MirPixelFormat
391-mir_choose_default_pixel_format(MirConnection *connection)
392-{
393- MirPixelFormat format[mir_pixel_formats];
394- unsigned int nformats;
395-
396- mir_connection_get_available_surface_formats(connection,
397- format, mir_pixel_formats, &nformats);
398-
399- return format[0];
400-}
401-}
402-
403-void UbuntuWindow::createWindow()
404-{
405- DLOG("UbuntuWindow::createWindow (this=%p)", this);
406-
407- // FIXME: remove this remnant of an old platform-api enum - needs ubuntu-keyboard update
408- const int SCREEN_KEYBOARD_ROLE = 7;
409- // Get surface role and flags.
410- QVariant roleVariant = window()->property("role");
411- int role = roleVariant.isValid() ? roleVariant.toUInt() : 1; // 1 is the default role for apps.
412- QVariant opaqueVariant = window()->property("opaque");
413- uint flags = opaqueVariant.isValid() ?
414- opaqueVariant.toUInt() ? static_cast<uint>(IS_OPAQUE_FLAG) : 0 : 0;
415-
416- // FIXME(loicm) Opaque flag is forced for now for non-system sessions (applications) for
417- // performance reasons.
418- flags |= static_cast<uint>(IS_OPAQUE_FLAG);
419-
420- const QByteArray title = (!window()->title().isNull()) ? window()->title().toUtf8() : "Window 1"; // legacy title
421- const int panelHeight = d->panelHeight();
422-
423-#if !defined(QT_NO_DEBUG)
424- LOG("panelHeight: '%d'", panelHeight);
425- LOG("role: '%d'", role);
426- LOG("flags: '%s'", (flags & static_cast<uint>(1)) ? "Opaque" : "NotOpaque");
427- LOG("title: '%s'", title.constData());
428-#endif
429+}
430+
431+UAUiWindowRole UbuntuWindowPrivate::role()
432+{
433+ QWindow *qWindow = mWindow->window();
434+ QVariant roleVariant = qWindow->property("role");
435+
436+ if (!roleVariant.isValid())
437+ return U_MAIN_ROLE;
438+
439+ uint role = roleVariant.toUInt();
440+ if (role < U_MAIN_ROLE || role > U_SHUTDOWN_DIALOG_ROLE)
441+ return U_MAIN_ROLE;
442+
443+ return static_cast<UAUiWindowRole>(role);
444+}
445+
446+UbuntuWindow *UbuntuWindowPrivate::transientParent()
447+{
448+ QWindow *qWindow = mWindow->window();
449+ QWindow *parent = qWindow->transientParent();
450+ return parent ? dynamic_cast<UbuntuWindow *>(parent->handle()) : nullptr;
451+}
452+
453+MirSurface *UbuntuWindowPrivate::parentSurface()
454+{
455+ UbuntuWindow *parent = transientParent();
456+
457+ // Sometimes children become visible before their parents - create the
458+ // parent window at this time if that's the case.
459+ if (parent->d->mSurface == nullptr) {
460+ DLOG("[ubuntumirclient QPA] (window=%p) creating parent window before it is visible!", mWindow);
461+ parent->d->createWindow();
462+ }
463+
464+ return parent->d->mSurface->mirSurface();
465+}
466+
467+std::unique_ptr<MirSurfaceSpec, MirSpecDeleter> UbuntuWindowPrivate::createSpec(const QRect& rect)
468+{
469+ using up = std::unique_ptr<MirSurfaceSpec, MirSpecDeleter>;
470+
471+ const QWindow *qWindow = mWindow->window();
472+ const UAUiWindowRole windowRole = role();
473+ const int width = rect.width();
474+ const int height = rect.height();
475+
476+ if (windowRole == U_ON_SCREEN_KEYBOARD_ROLE)
477+ return up{mir_connection_create_spec_for_input_method(mConnection, width, height, mPixelFormat)};
478+
479+ Qt::WindowType type = qWindow->type();
480+ if (type == Qt::Popup) {
481+ auto parent = transientParent();
482+ if (parent) {
483+ auto pos = mWindow->geometry().topLeft();
484+ pos -= parent->geometry().topLeft();
485+ MirRectangle location{pos.x(), pos.y(), 0, 0};
486+ DLOG("[ubuntumirclient QPA] createSpec(window=%p) - creating menu surface", mWindow);
487+ return up{mir_connection_create_spec_for_menu(
488+ mConnection, width, height, mPixelFormat, parentSurface(),
489+ &location, mir_edge_attachment_any)};
490+ }
491+ } else if (type == Qt::Dialog) {
492+ auto parent = transientParent();
493+ if (parent) {
494+ // Modal dialog
495+ DLOG("[ubuntumirclient QPA] createSpec(window=%p) - creating modal dialog", mWindow);
496+ return up{mir_connection_create_spec_for_modal_dialog(
497+ mConnection, width, height, mPixelFormat, parentSurface())};
498+ } else {
499+ // TODO: do Qt parentless dialogs have the same semantics as mir?
500+ DLOG("[ubuntumirclient QPA] createSpec(window=%p) - creating parentless dialog", mWindow);
501+ return up{mir_connection_create_spec_for_dialog(mConnection, width, height, mPixelFormat)};
502+ }
503+ }
504+ DLOG("[ubuntumirclient QPA] createSpec(window=%p) - creating normal surface(type=0x%x)", mWindow, type);
505+ return up{mir_connection_create_spec_for_normal_surface(mConnection, width, height, mPixelFormat)};
506+}
507+
508+void UbuntuWindowPrivate::createSurface(QRect& geom, const char *name)
509+{
510+ auto spec = createSpec(geom);
511+ mir_surface_spec_set_name(spec.get(), name);
512+
513+ if (mState == Qt::WindowFullScreen) {
514+ //FIXME: How to handle multiple screens? For now just use the first display id
515+ auto displayConfig = mir_connection_create_display_config(mConnection);
516+ if (displayConfig->num_outputs > 0) {
517+ auto outputId = displayConfig->outputs[0].output_id;
518+ mir_surface_spec_set_fullscreen_on_output(spec.get(), outputId);
519+ }
520+ }
521+ mir_wait_for(mir_surface_create(spec.get(), surfaceCreateCallback, this));
522+
523+ // Window manager can give us a final size different from what we asked for
524+ // so let's check what we ended up getting
525+ MirSurfaceParameters parameters;
526+ mir_surface_get_parameters(mSurface->mirSurface(), &parameters);
527+
528+ geom.setWidth(parameters.width);
529+ geom.setHeight(parameters.height);
530+}
531+
532+void UbuntuWindowPrivate::createWindow()
533+{
534+ // Already created
535+ if (mSurface != nullptr)
536+ return;
537+
538+ DLOG("[ubuntumirclient QPA] createWindow(window=%p)", mWindow);
539+
540+ QWindow *qWindow = mWindow->window();
541+
542+ const QByteArray title = qWindow->title().isNull() ? "Window 1" : qWindow->title().toUtf8(); // legacy title
543+ const int panelHeight = ::panelHeight();
544+
545+ DLOG("[ubuntumirclient QPA] panelHeight: '%d'", panelHeight);
546+ DLOG("[ubuntumirclient QPA] role: '%d'", role());
547+ DLOG("[ubuntumirclient QPA] title: '%s'", title.constData());
548
549 // Get surface geometry.
550- QRect geometry;
551- if (d->state == Qt::WindowFullScreen) {
552- printf("UbuntuWindow - fullscreen geometry\n");
553- geometry = screen()->geometry();
554- } else if (d->state == Qt::WindowMaximized) {
555- printf("UbuntuWindow - maximized geometry\n");
556- geometry = screen()->availableGeometry();
557+ QRect geom;
558+ if (mState == Qt::WindowFullScreen) {
559+ DLOG("[ubuntumirclient QPA] fullscreen geometry chosen\n");
560+ geom = mScreen->geometry();
561+ } else if (mState == Qt::WindowMaximized) {
562+ DLOG("[ubuntumirclient QPA] maximized geometry chosen\n");
563+ geom = mScreen->availableGeometry();
564 /*
565 * FIXME: Autopilot relies on being able to convert coordinates relative of the window
566 * into absolute screen coordinates. Mir does not allow this, see bug lp:1346633
567@@ -250,101 +370,92 @@
568 *
569 * Assumption: this method only used on phone devices!
570 */
571- geometry.setY(panelHeight);
572+ geom.setY(panelHeight);
573 } else {
574- printf("UbuntuWindow - regular geometry\n");
575- geometry = this->geometry();
576- geometry.setY(panelHeight);
577+ DLOG("[ubuntumirclient QPA] regular geometry chosen\n");
578+ geom = mWindow->geometry();
579 }
580
581 DLOG("[ubuntumirclient QPA] creating surface at (%d, %d) with size (%d, %d) with title '%s'\n",
582- geometry.x(), geometry.y(), geometry.width(), geometry.height(), title.data());
583-
584- MirSurfaceSpec *spec;
585- if (role == SCREEN_KEYBOARD_ROLE)
586- {
587- spec = mir_connection_create_spec_for_input_method(d->connection, geometry.width(),
588- geometry.height(), mir_choose_default_pixel_format(d->connection));
589- }
590- else
591- {
592- spec = mir_connection_create_spec_for_normal_surface(d->connection, geometry.width(),
593- geometry.height(), mir_choose_default_pixel_format(d->connection));
594- }
595- mir_surface_spec_set_name(spec, title.data());
596-
597- // Create platform window
598- mir_wait_for(mir_surface_create(spec, surfaceCreateCallback, this));
599- mir_surface_spec_release(spec);
600-
601- DASSERT(d->surface != NULL);
602- d->createEGLSurface((EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(d->surface)));
603-
604- if (d->state == Qt::WindowFullScreen) {
605- // TODO: We could set this on creation once surface spec supports it (mps already up)
606- mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_fullscreen));
607- }
608-
609- // Window manager can give us a final size different from what we asked for
610- // so let's check what we ended up getting
611- {
612- MirSurfaceParameters parameters;
613- mir_surface_get_parameters(d->surface, &parameters);
614-
615- geometry.setWidth(parameters.width);
616- geometry.setHeight(parameters.height);
617- }
618-
619- DLOG("[ubuntumirclient QPA] created surface has size (%d, %d)",
620- geometry.width(), geometry.height());
621+ geom.x(), geom.y(), geom.width(), geom.height(), title.data());
622+
623+ createSurface(geom, title.data());
624+
625+ DLOG("[ubuntumirclient QPA] created surface has size (%d, %d)", geom.width(), geom.height());
626
627 // Assume that the buffer size matches the surface size at creation time
628- d->bufferSize = geometry.size();
629+ mBufferSize = geom.size();
630
631 // Tell Qt about the geometry.
632- QWindowSystemInterface::handleGeometryChange(window(), geometry);
633- QPlatformWindow::setGeometry(geometry);
634-}
635-
636-void UbuntuWindow::moveResize(const QRect& rect)
637-{
638- (void) rect;
639- // TODO: Not yet supported by mir.
640+ QWindowSystemInterface::handleGeometryChange(qWindow, geom);
641+ mWindow->QPlatformWindow::setGeometry(geom);
642+}
643+
644+void UbuntuWindowPrivate::resize(const QRect& rect)
645+{
646+ DLOG("[ubuntumirclient QPA] resize(window=%p, width=%d, height=%d)", mWindow, rect.width(), rect.height());
647+
648+ if (mSurface == nullptr)
649+ return;
650+
651+ using up = std::unique_ptr<MirSurfaceSpec, MirSpecDeleter>;
652+ auto spec = up{mir_connection_create_spec_for_changes(mConnection)};
653+ mir_surface_spec_set_width(spec.get(), rect.width());
654+ mir_surface_spec_set_height(spec.get(), rect.height());
655+ mir_surface_apply_spec(mirSurface(), spec.get());
656+}
657+
658+void UbuntuWindowPrivate::setSurfaceState(Qt::WindowState new_state)
659+{
660+ mir_wait_for(mir_surface_set_state(mSurface->mirSurface(), qtWindowStateToMirSurfaceState(new_state)));
661+}
662+
663+UbuntuWindow::UbuntuWindow(QWindow *w, QSharedPointer<UbuntuClipboard> clipboard, UbuntuScreen *screen,
664+ UbuntuInput *input, MirConnection *connection)
665+ : QObject(nullptr), QPlatformWindow(w), d(new UbuntuWindowPrivate{
666+ this, screen, input, w->windowState(), connection, clipboard})
667+{
668+ DLOG("[ubuntumirclient QPA] UbuntuWindow(window=%p, w=%p, screen=%p, input=%p, priv=%p)", this, w, screen, input, d.get());
669+ QPlatformWindow::setGeometry(window()->geometry() != screen->geometry() ?
670+ window()->geometry() : screen->availableGeometry());
671+}
672+
673+UbuntuWindow::~UbuntuWindow()
674+{
675+ DLOG("[ubuntumirclient QPA] ~UbuntuWindow(window=%p)", this);
676 }
677
678 void UbuntuWindow::handleSurfaceResize(int width, int height)
679 {
680- QMutexLocker(&d->mutex);
681- LOG("UbuntuWindow::handleSurfaceResize(width=%d, height=%d)", width, height);
682+ QMutexLocker(&d->mMutex);
683+ DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p, width=%d, height=%d)", this, width, height);
684
685 // The current buffer size hasn't actually changed. so just render on it and swap
686- // buffers until we render on a buffer with the target size.
687-
688- d->targetBufferSize.rwidth() = width;
689- d->targetBufferSize.rheight() = height;
690-
691- if (d->bufferSize != d->targetBufferSize) {
692+ // buffers in the hope that the next buffer will match the surface size advertised
693+ // in this event.
694+ // But since this event is processed by a thread different from the one that swaps
695+ // buffers, you can never know if this information is already outdated as there's
696+ // no synchronicity whatsoever between the processing of resize events and the
697+ // consumption of buffers.
698+ if (d->mBufferSize.width() != width || d->mBufferSize.height() != height) {
699 QWindowSystemInterface::handleExposeEvent(window(), geometry());
700- } else {
701- qWarning("[ubuntumirclient QPA] UbuntuWindow::handleSurfaceResize"
702- " current buffer already has the target size");
703- d->targetBufferSize = QSize();
704+ QWindowSystemInterface::flushWindowSystemEvents();
705 }
706 }
707
708 void UbuntuWindow::handleSurfaceFocusChange(bool focused)
709 {
710- LOG("UbuntuWindow::handleSurfaceFocusChange(focused=%s)", focused ? "true" : "false");
711+ DLOG("[ubuntumirclient QPA] handleSurfaceFocusChange(window=%p, focused=%s)", this, focused ? "true" : "false");
712 QWindow *activatedWindow = focused ? window() : nullptr;
713
714- // System clipboard contents might have changed while this window was unfocused and wihtout
715+ // System clipboard contents might have changed while this window was unfocused and without
716 // this process getting notified about it because it might have been suspended (due to
717 // application lifecycle policies), thus unable to listen to any changes notified through
718 // D-Bus.
719 // Therefore let's ensure we are up to date with the system clipboard now that we are getting
720 // focused again.
721 if (focused) {
722- d->clipboard->requestDBusClipboardContents();
723+ d->mClipboard->requestDBusClipboardContents();
724 }
725
726 QWindowSystemInterface::handleWindowActivated(activatedWindow, Qt::ActiveWindowFocusReason);
727@@ -352,98 +463,82 @@
728
729 void UbuntuWindow::setWindowState(Qt::WindowState state)
730 {
731- QMutexLocker(&d->mutex);
732- DLOG("UbuntuWindow::setWindowState (this=%p, %s)", this, qtWindowStateToStr(state));
733+ QMutexLocker(&d->mMutex);
734+ DLOG("UbuntuWindow::setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
735
736- if (state == d->state)
737+ if (state == d->mState)
738 return;
739
740- // TODO: Perhaps we should check if the states are applied?
741- mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(state)));
742- d->state = state;
743+ d->setSurfaceState(state);
744+ d->mState = state;
745 }
746
747 void UbuntuWindow::setGeometry(const QRect& rect)
748 {
749- DLOG("UbuntuWindow::setGeometry (this=%p)", this);
750-
751- bool doMoveResize;
752-
753+ DLOG("[ubuntumirclient QPA] setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)", this, rect.x(), rect.y(), rect.width(), rect.height());
754+
755+ bool resize;
756 {
757- QMutexLocker(&d->mutex);
758+ QMutexLocker(&d->mMutex);
759+ resize = d->mState != Qt::WindowFullScreen && d->mState != Qt::WindowMaximized;
760 QPlatformWindow::setGeometry(rect);
761- doMoveResize = d->state != Qt::WindowFullScreen && d->state != Qt::WindowMaximized;
762 }
763
764- if (doMoveResize) {
765- moveResize(rect);
766+ if (resize) {
767+ d->resize(rect);
768 }
769 }
770
771 void UbuntuWindow::setVisible(bool visible)
772 {
773- QMutexLocker(&d->mutex);
774- DLOG("UbuntuWindow::setVisible (this=%p, visible=%s)", this, visible ? "true" : "false");
775+ QMutexLocker(&d->mMutex);
776+ DLOG("[ubuntumirclient QPA] setVisible (window=%p, visible=%s)", this, visible ? "true" : "false");
777
778 if (visible) {
779- mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(d->state)));
780+ d->createWindow();
781+ d->setSurfaceState(d->mState);
782
783 QWindowSystemInterface::handleExposeEvent(window(), QRect());
784 QWindowSystemInterface::flushWindowSystemEvents();
785 } else {
786 // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
787 // Will have to change qtmir and unity8 for that.
788- mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_minimized));
789+ d->setSurfaceState(Qt::WindowMinimized);
790 }
791 }
792
793 void* UbuntuWindow::eglSurface() const
794 {
795- return d->eglSurface;
796+ return d->eglSurface();
797 }
798
799 WId UbuntuWindow::winId() const
800 {
801- return d->id;
802+ return d->mId;
803 }
804
805 void UbuntuWindow::onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight)
806 {
807- QMutexLocker(&d->mutex);
808+ QMutexLocker(&d->mMutex);
809
810 bool sizeKnown = newBufferWidth > 0 && newBufferHeight > 0;
811
812- if (sizeKnown && (d->bufferSize.width() != newBufferWidth ||
813- d->bufferSize.height() != newBufferHeight)) {
814+ if (sizeKnown && (d->mBufferSize.width() != newBufferWidth ||
815+ d->mBufferSize.height() != newBufferHeight)) {
816
817 DLOG("UbuntuWindow::onBuffersSwapped_threadSafe - buffer size changed from (%d,%d) to (%d,%d)",
818- d->bufferSize.width(), d->bufferSize.height(), newBufferWidth, newBufferHeight);
819+ d->mBufferSize.width(), d->mBufferSize.height(), newBufferWidth, newBufferHeight);
820
821- d->bufferSize.rwidth() = newBufferWidth;
822- d->bufferSize.rheight() = newBufferHeight;
823+ d->mBufferSize.rwidth() = newBufferWidth;
824+ d->mBufferSize.rheight() = newBufferHeight;
825
826 QRect newGeometry;
827
828 newGeometry = geometry();
829- newGeometry.setWidth(d->bufferSize.width());
830- newGeometry.setHeight(d->bufferSize.height());
831+ newGeometry.setWidth(d->mBufferSize.width());
832+ newGeometry.setHeight(d->mBufferSize.height());
833
834 QPlatformWindow::setGeometry(newGeometry);
835 QWindowSystemInterface::handleGeometryChange(window(), newGeometry, QRect());
836- QWindowSystemInterface::handleExposeEvent(window(), newGeometry);
837-
838- } else {
839- // buffer size hasn't changed
840- if (d->targetBufferSize.isValid()) {
841- if (d->bufferSize != d->targetBufferSize) {
842- // but we still didn't reach the promised buffer size from the mir resize event.
843- // thus keep swapping buffers
844- QWindowSystemInterface::handleExposeEvent(window(), geometry());
845- } else {
846- // target met. we have just provided a render with the target size and
847- // can therefore finally rest.
848- d->targetBufferSize = QSize();
849- }
850- }
851 }
852 }
853
854=== modified file 'src/ubuntumirclient/window.h'
855--- src/ubuntumirclient/window.h 2015-05-12 17:30:15 +0000
856+++ src/ubuntumirclient/window.h 2015-08-06 17:13:12 +0000
857@@ -20,15 +20,18 @@
858 #include <qpa/qplatformwindow.h>
859 #include <QSharedPointer>
860
861-#include <mir_toolkit/mir_client_library.h>
862+#include <memory>
863
864 class UbuntuClipboard;
865 class UbuntuInput;
866 class UbuntuScreen;
867-class UbuntuWindowPrivate;
868+struct UbuntuWindowPrivate;
869+struct MirConnection;
870
871 class UbuntuWindow : public QObject, public QPlatformWindow
872 {
873+ friend struct UbuntuWindowPrivate;
874+
875 Q_OBJECT
876 public:
877 UbuntuWindow(QWindow *w, QSharedPointer<UbuntuClipboard> clipboard, UbuntuScreen *screen,
878@@ -47,13 +50,8 @@
879 void handleSurfaceFocusChange(bool focused);
880 void onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight);
881
882- UbuntuWindowPrivate* priv() { return d; }
883-
884 private:
885- void createWindow();
886- void moveResize(const QRect& rect);
887-
888- UbuntuWindowPrivate *d;
889+ std::unique_ptr<UbuntuWindowPrivate> d;
890 };
891
892 #endif // UBUNTU_WINDOW_H

Subscribers

People subscribed via source and target branches