Merge lp:~gerboland/qtubuntu/add--more-surface-type-support into lp:qtubuntu

Proposed by Gerry Boland
Status: Merged
Approved by: Nick Dedekind
Approved revision: 301
Merged at revision: 355
Proposed branch: lp:~gerboland/qtubuntu/add--more-surface-type-support
Merge into: lp:qtubuntu
Prerequisite: lp:~gerboland/qtubuntu/rasterGLSurface
Diff against target: 535 lines (+264/-155)
2 files modified
src/ubuntumirclient/input.cpp (+2/-0)
src/ubuntumirclient/window.cpp (+262/-155)
To merge this branch: bzr merge lp:~gerboland/qtubuntu/add--more-surface-type-support
Reviewer Review Type Date Requested Status
Nick Dedekind (community) Approve
Unity8 CI Bot continuous-integration Approve
Lukáš Tinkl (community) Needs Information
Review via email: mp+308367@code.launchpad.net

This proposal supersedes a proposal from 2016-10-13.

Commit message

Add support for more surface types and surface repositioning.

Helps Menus, Dropdowns and Tooltips to work with Mir

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:297
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/145/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/145/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:297
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/147/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/147/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Just a curious question inline :)

review: Needs Information
Revision history for this message
Gerry Boland (gerboland) wrote :

> Wouldn't Qt:Tool better be represented by mir_surface_type_satellite?

Maybe, but while Mir has the surface Type in an enum, it doesn't let me create surfaces of type satellite yet (i.e. no mir_connection_create_spec_for_satellite)! So I just chose the nearest type I can create.

This mapping is not final, I expect it to change in future. That's why I put the mapping in an obvious method.

Revision history for this message
Gerry Boland (gerboland) wrote :

Hmm, I've broken OSK with this. Marking WIP until I sort that out

Revision history for this message
Gerry Boland (gerboland) wrote :

Fixed

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:299
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/148/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/148/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

"""
 void UbuntuWindow::handleSurfaceVisibilityChanged(bool visible)
493 {
494 - qCDebug(ubuntumirclient, "handleSurfaceFocused(window=%p)", window());
495 + qCDebug(ubuntumirclient, "handleSurfaceVisibilityChanged(window=%p, visible=%d)", window(), visible);
"""

https://code.launchpad.net/~dandrader/qtubuntu/loggingFixes/+merge/305374 already touches this. Branches will conflict.

300. By Gerry Boland

Fix for dialogs crash

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:300
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/149/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/149/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
301. By Gerry Boland

This is not python, fix comment

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:301
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/155/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/155/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:301
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/158/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3199
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3227
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3083/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3083/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3083/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3083/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3083/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3083/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3083/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3083/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3083
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3083/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/158/rebuild

review: Approve (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Couple of comments.

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) :
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Ok, if you're confident! LGTM

review: Approve
302. By Gerry Boland

Only set internal position in setGeometry, not size

303. By Gerry Boland

Merge trunk & resolve conflict

Revision history for this message
Gerry Boland (gerboland) wrote :

Hmm, I can't land this as it will break Autopilot tests on phones :(

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ubuntumirclient/input.cpp'
2--- src/ubuntumirclient/input.cpp 2016-10-24 11:31:55 +0000
3+++ src/ubuntumirclient/input.cpp 2016-11-04 13:24:44 +0000
4@@ -503,6 +503,8 @@
5 const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
6 mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
7
8+ mLastInputWindow = platformWindow;
9+
10 switch (action) {
11 case mir_pointer_action_button_up:
12 case mir_pointer_action_button_down:
13
14=== modified file 'src/ubuntumirclient/window.cpp'
15--- src/ubuntumirclient/window.cpp 2016-10-24 11:32:31 +0000
16+++ src/ubuntumirclient/window.cpp 2016-11-04 13:24:44 +0000
17@@ -24,6 +24,7 @@
18 #include "logging.h"
19
20 #include <mir_toolkit/mir_client_library.h>
21+#include <mir_toolkit/version.h>
22
23 // Qt
24 #include <qpa/qwindowsysteminterface.h>
25@@ -123,6 +124,23 @@
26 Q_UNREACHABLE();
27 }
28
29+const char *mirSurfaceTypeToStr(MirSurfaceType type)
30+{
31+ switch (type) {
32+ case mir_surface_type_normal: return "Normal"; /**< AKA "regular" */
33+ case mir_surface_type_utility: return "Utility"; /**< AKA "floating regular" */
34+ case mir_surface_type_dialog: return "Dialog";
35+ case mir_surface_type_gloss: return "Gloss";
36+ case mir_surface_type_freestyle: return "Freestyle";
37+ case mir_surface_type_menu: return "Menu";
38+ case mir_surface_type_inputmethod: return "Input Method"; /**< AKA "OSK" or handwriting etc. */
39+ case mir_surface_type_satellite: return "Satellite"; /**< AKA "toolbox"/"toolbar" */
40+ case mir_surface_type_tip: return "Tip"; /**< AKA "tooltip" */
41+ case mir_surface_types: Q_UNREACHABLE();
42+ }
43+ return "";
44+}
45+
46 MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
47 {
48 switch (state) {
49@@ -139,6 +157,27 @@
50 return mir_surface_state_unknown; // should never be reached
51 }
52
53+MirSurfaceType qtWindowTypeToMirSurfaceType(Qt::WindowType type)
54+{
55+ switch (type & Qt::WindowType_Mask) {
56+ case Qt::Dialog:
57+ return mir_surface_type_dialog;
58+ case Qt::Sheet:
59+ case Qt::Drawer:
60+ return mir_surface_type_utility;
61+ case Qt::Popup:
62+ case Qt::Tool:
63+ return mir_surface_type_menu;
64+ case Qt::ToolTip:
65+ return mir_surface_type_tip;
66+ case Qt::SplashScreen:
67+ return mir_surface_type_freestyle;
68+ case Qt::Window:
69+ default:
70+ return mir_surface_type_normal;
71+ }
72+}
73+
74 WId makeId()
75 {
76 static int id = 1;
77@@ -164,51 +203,93 @@
78 return parent ? static_cast<UbuntuWindow *>(parent->handle()) : nullptr;
79 }
80
81-Spec makeSurfaceSpec(QWindow *window, UbuntuInput *input, MirPixelFormat pixelFormat, MirConnection *connection)
82-{
83- const auto geom = window->geometry();
84- const int width = geom.width() > 0 ? geom.width() : 1;
85- const int height = geom.height() > 0 ? geom.height() : 1;
86+bool requiresParent(const MirSurfaceType type)
87+{
88+ switch (type) {
89+ case mir_surface_type_dialog: //FIXME - not quite what the specification dictates, but is what Mir's api dictates
90+ case mir_surface_type_utility:
91+ case mir_surface_type_gloss:
92+ case mir_surface_type_menu:
93+ case mir_surface_type_satellite:
94+ case mir_surface_type_tip:
95+ return true;
96+ default:
97+ return false;
98+ }
99+}
100+
101+bool requiresParent(const Qt::WindowType type)
102+{
103+ return requiresParent(qtWindowTypeToMirSurfaceType(type));
104+}
105+
106+bool isMovable(const Qt::WindowType type)
107+{
108+ auto mirType = qtWindowTypeToMirSurfaceType(type);
109+ switch (mirType) {
110+ case mir_surface_type_menu:
111+ case mir_surface_type_tip:
112+ return true;
113+ default:
114+ return false;
115+ }
116+}
117+
118+Spec makeSurfaceSpec(QWindow *window, MirPixelFormat pixelFormat, UbuntuWindow *parentWindowHandle,
119+ MirConnection *connection)
120+{
121+ const auto geometry = window->geometry();
122+ const int width = geometry.width() > 0 ? geometry.width() : 1;
123+ const int height = geometry.height() > 0 ? geometry.height() : 1;
124+ auto type = qtWindowTypeToMirSurfaceType(window->type());
125
126 if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
127- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);
128- return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
129- }
130-
131- const Qt::WindowType type = window->type();
132- if (type == Qt::Popup) {
133- auto parent = transientParentFor(window);
134- if (parent == nullptr) {
135- //NOTE: We cannot have a parentless popup -
136- //try using the last surface to receive input as that will most likely be
137- //the one that caused this popup to be created
138- parent = input->lastInputWindow();
139- }
140- if (parent) {
141- auto pos = geom.topLeft();
142- pos -= parent->geometry().topLeft();
143- MirRectangle location{pos.x(), pos.y(), 0, 0};
144- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);
145- return Spec{mir_connection_create_spec_for_menu(
146- connection, width, height, pixelFormat, parent->mirSurface(),
147- &location, mir_edge_attachment_any)};
148- } else {
149- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
150- }
151- } else if (type == Qt::Dialog) {
152- auto parent = transientParentFor(window);
153- if (parent) {
154- // Modal dialog
155- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);
156- return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};
157- } else {
158- // TODO: do Qt parentless dialogs have the same semantics as mir?
159- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);
160- return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
161- }
162- }
163- qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);
164- return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
165+ type = mir_surface_type_inputmethod;
166+ }
167+
168+ MirRectangle location{geometry.x(), geometry.y(), 0, 0};
169+ MirSurface *parent = nullptr;
170+ if (parentWindowHandle) {
171+ parent = parentWindowHandle->mirSurface();
172+ // Qt uses absolute positioning, but Mir positions surfaces relative to parent.
173+ location.top -= parentWindowHandle->geometry().top();
174+ location.left -= parentWindowHandle->geometry().left();
175+ }
176+
177+ Spec spec;
178+
179+ switch (type) {
180+ case mir_surface_type_menu:
181+ spec = Spec{mir_connection_create_spec_for_menu(connection, width, height, pixelFormat, parent,
182+ &location, mir_edge_attachment_any)};
183+ break;
184+ case mir_surface_type_dialog:
185+ spec = Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent)};
186+ break;
187+ case mir_surface_type_utility:
188+ spec = Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
189+ break;
190+ case mir_surface_type_tip:
191+#if MIR_CLIENT_VERSION < MIR_VERSION_NUMBER(3, 4, 0)
192+ spec = Spec{mir_connection_create_spec_for_tooltip(connection, width, height, pixelFormat, parent,
193+ &location)};
194+#else
195+ spec = Spec{mir_connection_create_spec_for_tip(connection, width, height, pixelFormat, parent,
196+ &location, mir_edge_attachment_any)};
197+#endif
198+ break;
199+ case mir_surface_type_inputmethod:
200+ spec = Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
201+ break;
202+ default:
203+ spec = Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
204+ break;
205+ }
206+
207+ qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)",
208+ window, mirSurfaceTypeToStr(type), window->type(), location.left, location.top, width, height);
209+
210+ return std::move(spec);
211 }
212
213 void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)
214@@ -229,11 +310,11 @@
215 }
216 }
217
218-MirSurface *createMirSurface(QWindow *window, int mirOutputId, UbuntuInput *input, MirPixelFormat pixelFormat,
219- MirConnection *connection, mir_surface_event_callback inputCallback,
220- void* inputContext)
221+MirSurface *createMirSurface(QWindow *window, int mirOutputId, UbuntuWindow *parentWindowHandle,
222+ MirPixelFormat pixelFormat, MirConnection *connection,
223+ mir_surface_event_callback inputCallback, void *inputContext)
224 {
225- auto spec = makeSurfaceSpec(window, input, pixelFormat, connection);
226+ auto spec = makeSurfaceSpec(window, pixelFormat, parentWindowHandle, connection);
227
228 // Install event handler as early as possible
229 mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext);
230@@ -256,6 +337,20 @@
231 return surface;
232 }
233
234+UbuntuWindow *getParentIfNecessary(QWindow *window, UbuntuInput *input)
235+{
236+ UbuntuWindow *parentWindowHandle = nullptr;
237+ if (requiresParent(window->type())) {
238+ parentWindowHandle = transientParentFor(window);
239+ if (parentWindowHandle == nullptr) {
240+ // NOTE: Mir requires this surface have a parent. Try using the last surface to receive input as that will
241+ // most likely be the one that caused this surface to be created
242+ parentWindowHandle = input->lastInputWindow();
243+ }
244+ }
245+ return parentWindowHandle;
246+}
247+
248 MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat)
249 {
250 switch(pixelFormat) {
251@@ -287,98 +382,18 @@
252
253 } //namespace
254
255+
256+
257 class UbuntuSurface
258 {
259 public:
260- UbuntuSurface(UbuntuWindow *platformWindow, EGLDisplay display, UbuntuInput *input, MirConnection *connection)
261- : mWindow(platformWindow->window())
262- , mPlatformWindow(platformWindow)
263- , mInput(input)
264- , mConnection(connection)
265- , mEglDisplay(display)
266- , mNeedsRepaint(false)
267- , mParented(mWindow->transientParent() || mWindow->parent())
268- , mFormat(mWindow->requestedFormat())
269- , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
270- {
271- // Have Qt choose most suitable EGLConfig for the requested surface format, and update format to reflect it
272- EGLConfig config = q_configFromGLFormat(display, mFormat, true);
273- if (config == 0) {
274- // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default
275- // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a
276- // 1.4 context, but the XCB EGL backend tries to honour it, and fails. The 1.4 context appears to
277- // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default
278- // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455).
279- static const bool isMesa = QString(eglQueryString(display, EGL_VENDOR)).contains(QStringLiteral("Mesa"));
280- if (isMesa) {
281- qCDebug(ubuntumirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa");
282- mFormat.setMajorVersion(1);
283- mFormat.setMinorVersion(4);
284- config = q_configFromGLFormat(display, mFormat, true);
285- }
286- }
287- if (config == 0) {
288- qCritical() << "Qt failed to choose a suitable EGLConfig to suit the surface format" << mFormat;
289- }
290-
291- mFormat = q_glFormatFromConfig(display, config, mFormat);
292-
293- // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way
294- // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers.
295- auto pixelFormat = mir_connection_get_egl_pixel_format(connection, display, config);
296- // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client.
297- // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer.
298- // This is an optimisation for the compositor, as it can avoid blending this surface.
299- if (mWindow->requestedFormat().alphaBufferSize() < 0) {
300- pixelFormat = disableAlphaBufferIfPossible(pixelFormat);
301- }
302-
303- const auto outputId = static_cast<UbuntuScreen *>(mWindow->screen()->handle())->mirOutputId();
304-
305- mMirSurface = createMirSurface(mWindow, outputId, input, pixelFormat, connection, surfaceEventCallback, this);
306- mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirSurface), nullptr);
307-
308- mNeedsExposeCatchup = mir_surface_get_visibility(mMirSurface) == mir_surface_visibility_occluded;
309-
310- // Window manager can give us a final size different from what we asked for
311- // so let's check what we ended up getting
312- MirSurfaceParameters parameters;
313- mir_surface_get_parameters(mMirSurface, &parameters);
314-
315- auto geom = mWindow->geometry();
316- geom.setWidth(parameters.width);
317- geom.setHeight(parameters.height);
318- if (mWindow->windowState() == Qt::WindowFullScreen) {
319- geom.moveTop(0);
320- } else {
321- geom.moveTop(panelHeight());
322- }
323-
324- // Assume that the buffer size matches the surface size at creation time
325- mBufferSize = geom.size();
326- platformWindow->QPlatformWindow::setGeometry(geom);
327- QWindowSystemInterface::handleGeometryChange(mWindow, geom);
328-
329- qCDebug(ubuntumirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title()
330- << "role:" << roleFor(mWindow);
331- qCDebug(ubuntumirclientGraphics)
332- << "Requested format:" << mWindow->requestedFormat()
333- << "\nActual format:" << mFormat
334- << "with associated Mir pixel format:" << mirPixelFormatToStr(pixelFormat);
335- }
336-
337- ~UbuntuSurface()
338- {
339- if (mEglSurface != EGL_NO_SURFACE)
340- eglDestroySurface(mEglDisplay, mEglSurface);
341- if (mMirSurface)
342- mir_surface_release_sync(mMirSurface);
343- }
344+ UbuntuSurface(UbuntuWindow *platformWindow, EGLDisplay display, UbuntuInput *input, MirConnection *connection);
345+ ~UbuntuSurface();
346
347 UbuntuSurface(const UbuntuSurface &) = delete;
348 UbuntuSurface& operator=(const UbuntuSurface &) = delete;
349
350- void resize(const QSize& newSize);
351+ void updateGeometry(const QRect &newGeometry);
352 void updateTitle(const QString& title);
353 void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
354
355@@ -414,6 +429,7 @@
356 UbuntuWindow * const mPlatformWindow;
357 UbuntuInput * const mInput;
358 MirConnection * const mConnection;
359+ UbuntuWindow * mParentWindowHandle{nullptr};
360
361 MirSurface* mMirSurface;
362 const EGLDisplay mEglDisplay;
363@@ -423,6 +439,7 @@
364 bool mParented;
365 QSize mBufferSize;
366 QSurfaceFormat mFormat;
367+ MirPixelFormat mPixelFormat;
368
369 QMutex mTargetSizeMutex;
370 QSize mTargetSize;
371@@ -430,23 +447,102 @@
372 QString mPersistentIdStr;
373 };
374
375-void UbuntuSurface::resize(const QSize& size)
376-{
377- qCDebug(ubuntumirclient,"resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
378-
379- if (mWindow->windowState() == Qt::WindowFullScreen || mWindow->windowState() == Qt::WindowMaximized) {
380- qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
381- return;
382- }
383-
384- if (size.isEmpty()) {
385- qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, size is empty", mWindow);
386- return;
387- }
388-
389- Spec spec{mir_connection_create_spec_for_changes(mConnection)};
390- mir_surface_spec_set_width(spec.get(), size.width());
391- mir_surface_spec_set_height(spec.get(), size.height());
392+UbuntuSurface::UbuntuSurface(UbuntuWindow *platformWindow, EGLDisplay display, UbuntuInput *input, MirConnection *connection)
393+ : mWindow(platformWindow->window())
394+ , mPlatformWindow(platformWindow)
395+ , mInput(input)
396+ , mConnection(connection)
397+ , mEglDisplay(display)
398+ , mNeedsRepaint(false)
399+ , mParented(mWindow->transientParent() || mWindow->parent())
400+ , mFormat(mWindow->requestedFormat())
401+ , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
402+{
403+ // Have Qt choose most suitable EGLConfig for the requested surface format, and update format to reflect it
404+ EGLConfig config = q_configFromGLFormat(display, mFormat, true);
405+ if (config == 0) {
406+ // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default
407+ // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a
408+ // 1.4 context, but the XCB EGL backend tries to honour it, and fails. The 1.4 context appears to
409+ // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default
410+ // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455).
411+ static const bool isMesa = QString(eglQueryString(display, EGL_VENDOR)).contains(QStringLiteral("Mesa"));
412+ if (isMesa) {
413+ qCDebug(ubuntumirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa");
414+ mFormat.setMajorVersion(1);
415+ mFormat.setMinorVersion(4);
416+ config = q_configFromGLFormat(display, mFormat, true);
417+ }
418+ }
419+ if (config == 0) {
420+ qCritical() << "Qt failed to choose a suitable EGLConfig to suit the surface format" << mFormat;
421+ }
422+
423+ mFormat = q_glFormatFromConfig(display, config, mFormat);
424+
425+ // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way
426+ // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers.
427+ mPixelFormat = mir_connection_get_egl_pixel_format(connection, display, config);
428+ // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client.
429+ // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer.
430+ // This is an optimisation for the compositor, as it can avoid blending this surface.
431+ if (mWindow->requestedFormat().alphaBufferSize() < 0) {
432+ mPixelFormat = disableAlphaBufferIfPossible(mPixelFormat);
433+ }
434+
435+ const auto outputId = static_cast<UbuntuScreen *>(mWindow->screen()->handle())->mirOutputId();
436+
437+ mParentWindowHandle = getParentIfNecessary(mWindow, input);
438+
439+ mMirSurface = createMirSurface(mWindow, outputId, mParentWindowHandle, mPixelFormat, connection, surfaceEventCallback, this);
440+ mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirSurface), nullptr);
441+
442+ mNeedsExposeCatchup = mir_surface_get_visibility(mMirSurface) == mir_surface_visibility_occluded;
443+
444+ // Window manager can give us a final size different from what we asked for
445+ // so let's check what we ended up getting
446+ MirSurfaceParameters parameters;
447+ mir_surface_get_parameters(mMirSurface, &parameters);
448+
449+ auto geom = mWindow->geometry();
450+ geom.setWidth(parameters.width);
451+ geom.setHeight(parameters.height);
452+
453+ // Assume that the buffer size matches the surface size at creation time
454+ mBufferSize = geom.size();
455+ platformWindow->QPlatformWindow::setGeometry(geom);
456+ QWindowSystemInterface::handleGeometryChange(mWindow, geom);
457+
458+ qCDebug(ubuntumirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title()
459+ << "role:" << roleFor(mWindow);
460+ qCDebug(ubuntumirclientGraphics)
461+ << "Requested format:" << mWindow->requestedFormat()
462+ << "\nActual format:" << mFormat
463+ << "with associated Mir pixel format:" << mirPixelFormatToStr(mPixelFormat);
464+}
465+
466+UbuntuSurface::~UbuntuSurface()
467+{
468+ if (mEglSurface != EGL_NO_SURFACE)
469+ eglDestroySurface(mEglDisplay, mEglSurface);
470+ if (mMirSurface) {
471+ mir_surface_release_sync(mMirSurface);
472+ }
473+}
474+
475+void UbuntuSurface::updateGeometry(const QRect &newGeometry)
476+{
477+ qCDebug(ubuntumirclient,"updateGeometry(window=%p, width=%d, height=%d)", mWindow,
478+ newGeometry.width(), newGeometry.height());
479+
480+ Spec spec;
481+ if (isMovable(mWindow->type())) {
482+ spec = Spec{makeSurfaceSpec(mWindow, mPixelFormat, mParentWindowHandle, mConnection)};
483+ } else {
484+ spec = Spec{mir_connection_create_spec_for_changes(mConnection)};
485+ mir_surface_spec_set_width(spec.get(), newGeometry.width());
486+ mir_surface_spec_set_height(spec.get(), newGeometry.height());
487+ }
488 mir_surface_apply_spec(mMirSurface, spec.get());
489 }
490
491@@ -690,7 +786,7 @@
492
493 void UbuntuWindow::handleSurfaceVisibilityChanged(bool visible)
494 {
495- qCDebug(ubuntumirclient, "handleSurfaceVisibilityChanged(visible=%d)", visible);
496+ qCDebug(ubuntumirclient, "handleSurfaceVisibilityChanged(window=%p, visible=%d)", window(), visible);
497
498 if (mWindowVisible == visible) return;
499 mWindowVisible = visible;
500@@ -739,6 +835,10 @@
501 */
502 void UbuntuWindow::updatePanelHeightHack(bool enable)
503 {
504+ if ((window()->type() & Qt::WindowType_Mask) != Qt::Window) { // only plain windows get the hack
505+ return;
506+ }
507+
508 QMutexLocker lock(&mMutex);
509
510 QRect newGeometry = geometry();
511@@ -758,13 +858,20 @@
512 void UbuntuWindow::setGeometry(const QRect &rect)
513 {
514 QMutexLocker lock(&mMutex);
515+
516+ if (window()->windowState() == Qt::WindowFullScreen || window()->windowState() == Qt::WindowMaximized) {
517+ qCDebug(ubuntumirclient, "setGeometry(window=%p) - not resizing, window is maximized or fullscreen", window());
518+ return;
519+ }
520+
521 qCDebug(ubuntumirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)",
522 window(), rect.x(), rect.y(), rect.width(), rect.height());
523-
524- //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates
525- const auto newSize = rect.size();
526-
527- mSurface->resize(newSize);
528+ // Immediately update internal geometry so Qt believes position updated
529+ QRect newPosition(geometry());
530+ newPosition.moveTo(rect.topLeft());
531+ QPlatformWindow::setGeometry(newPosition);
532+
533+ mSurface->updateGeometry(rect);
534 // Note: don't call handleGeometryChange here, wait to see what Mir replies with.
535 }
536

Subscribers

People subscribed via source and target branches