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
=== modified file 'src/ubuntumirclient/input.cpp'
--- src/ubuntumirclient/input.cpp 2016-10-24 11:31:55 +0000
+++ src/ubuntumirclient/input.cpp 2016-11-04 13:24:44 +0000
@@ -503,6 +503,8 @@
503 const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),503 const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
504 mir_pointer_event_axis_value(pev, mir_pointer_axis_y));504 mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
505505
506 mLastInputWindow = platformWindow;
507
506 switch (action) {508 switch (action) {
507 case mir_pointer_action_button_up:509 case mir_pointer_action_button_up:
508 case mir_pointer_action_button_down:510 case mir_pointer_action_button_down:
509511
=== modified file 'src/ubuntumirclient/window.cpp'
--- src/ubuntumirclient/window.cpp 2016-10-24 11:32:31 +0000
+++ src/ubuntumirclient/window.cpp 2016-11-04 13:24:44 +0000
@@ -24,6 +24,7 @@
24#include "logging.h"24#include "logging.h"
2525
26#include <mir_toolkit/mir_client_library.h>26#include <mir_toolkit/mir_client_library.h>
27#include <mir_toolkit/version.h>
2728
28// Qt29// Qt
29#include <qpa/qwindowsysteminterface.h>30#include <qpa/qwindowsysteminterface.h>
@@ -123,6 +124,23 @@
123 Q_UNREACHABLE();124 Q_UNREACHABLE();
124}125}
125126
127const char *mirSurfaceTypeToStr(MirSurfaceType type)
128{
129 switch (type) {
130 case mir_surface_type_normal: return "Normal"; /**< AKA "regular" */
131 case mir_surface_type_utility: return "Utility"; /**< AKA "floating regular" */
132 case mir_surface_type_dialog: return "Dialog";
133 case mir_surface_type_gloss: return "Gloss";
134 case mir_surface_type_freestyle: return "Freestyle";
135 case mir_surface_type_menu: return "Menu";
136 case mir_surface_type_inputmethod: return "Input Method"; /**< AKA "OSK" or handwriting etc. */
137 case mir_surface_type_satellite: return "Satellite"; /**< AKA "toolbox"/"toolbar" */
138 case mir_surface_type_tip: return "Tip"; /**< AKA "tooltip" */
139 case mir_surface_types: Q_UNREACHABLE();
140 }
141 return "";
142}
143
126MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)144MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
127{145{
128 switch (state) {146 switch (state) {
@@ -139,6 +157,27 @@
139 return mir_surface_state_unknown; // should never be reached157 return mir_surface_state_unknown; // should never be reached
140}158}
141159
160MirSurfaceType qtWindowTypeToMirSurfaceType(Qt::WindowType type)
161{
162 switch (type & Qt::WindowType_Mask) {
163 case Qt::Dialog:
164 return mir_surface_type_dialog;
165 case Qt::Sheet:
166 case Qt::Drawer:
167 return mir_surface_type_utility;
168 case Qt::Popup:
169 case Qt::Tool:
170 return mir_surface_type_menu;
171 case Qt::ToolTip:
172 return mir_surface_type_tip;
173 case Qt::SplashScreen:
174 return mir_surface_type_freestyle;
175 case Qt::Window:
176 default:
177 return mir_surface_type_normal;
178 }
179}
180
142WId makeId()181WId makeId()
143{182{
144 static int id = 1;183 static int id = 1;
@@ -164,51 +203,93 @@
164 return parent ? static_cast<UbuntuWindow *>(parent->handle()) : nullptr;203 return parent ? static_cast<UbuntuWindow *>(parent->handle()) : nullptr;
165}204}
166205
167Spec makeSurfaceSpec(QWindow *window, UbuntuInput *input, MirPixelFormat pixelFormat, MirConnection *connection)206bool requiresParent(const MirSurfaceType type)
168{207{
169 const auto geom = window->geometry();208 switch (type) {
170 const int width = geom.width() > 0 ? geom.width() : 1;209 case mir_surface_type_dialog: //FIXME - not quite what the specification dictates, but is what Mir's api dictates
171 const int height = geom.height() > 0 ? geom.height() : 1;210 case mir_surface_type_utility:
211 case mir_surface_type_gloss:
212 case mir_surface_type_menu:
213 case mir_surface_type_satellite:
214 case mir_surface_type_tip:
215 return true;
216 default:
217 return false;
218 }
219}
220
221bool requiresParent(const Qt::WindowType type)
222{
223 return requiresParent(qtWindowTypeToMirSurfaceType(type));
224}
225
226bool isMovable(const Qt::WindowType type)
227{
228 auto mirType = qtWindowTypeToMirSurfaceType(type);
229 switch (mirType) {
230 case mir_surface_type_menu:
231 case mir_surface_type_tip:
232 return true;
233 default:
234 return false;
235 }
236}
237
238Spec makeSurfaceSpec(QWindow *window, MirPixelFormat pixelFormat, UbuntuWindow *parentWindowHandle,
239 MirConnection *connection)
240{
241 const auto geometry = window->geometry();
242 const int width = geometry.width() > 0 ? geometry.width() : 1;
243 const int height = geometry.height() > 0 ? geometry.height() : 1;
244 auto type = qtWindowTypeToMirSurfaceType(window->type());
172245
173 if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {246 if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
174 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);247 type = mir_surface_type_inputmethod;
175 return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};248 }
176 }249
177250 MirRectangle location{geometry.x(), geometry.y(), 0, 0};
178 const Qt::WindowType type = window->type();251 MirSurface *parent = nullptr;
179 if (type == Qt::Popup) {252 if (parentWindowHandle) {
180 auto parent = transientParentFor(window);253 parent = parentWindowHandle->mirSurface();
181 if (parent == nullptr) {254 // Qt uses absolute positioning, but Mir positions surfaces relative to parent.
182 //NOTE: We cannot have a parentless popup -255 location.top -= parentWindowHandle->geometry().top();
183 //try using the last surface to receive input as that will most likely be256 location.left -= parentWindowHandle->geometry().left();
184 //the one that caused this popup to be created257 }
185 parent = input->lastInputWindow();258
186 }259 Spec spec;
187 if (parent) {260
188 auto pos = geom.topLeft();261 switch (type) {
189 pos -= parent->geometry().topLeft();262 case mir_surface_type_menu:
190 MirRectangle location{pos.x(), pos.y(), 0, 0};263 spec = Spec{mir_connection_create_spec_for_menu(connection, width, height, pixelFormat, parent,
191 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);264 &location, mir_edge_attachment_any)};
192 return Spec{mir_connection_create_spec_for_menu(265 break;
193 connection, width, height, pixelFormat, parent->mirSurface(),266 case mir_surface_type_dialog:
194 &location, mir_edge_attachment_any)};267 spec = Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent)};
195 } else {268 break;
196 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);269 case mir_surface_type_utility:
197 }270 spec = Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
198 } else if (type == Qt::Dialog) {271 break;
199 auto parent = transientParentFor(window);272 case mir_surface_type_tip:
200 if (parent) {273#if MIR_CLIENT_VERSION < MIR_VERSION_NUMBER(3, 4, 0)
201 // Modal dialog274 spec = Spec{mir_connection_create_spec_for_tooltip(connection, width, height, pixelFormat, parent,
202 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);275 &location)};
203 return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};276#else
204 } else {277 spec = Spec{mir_connection_create_spec_for_tip(connection, width, height, pixelFormat, parent,
205 // TODO: do Qt parentless dialogs have the same semantics as mir?278 &location, mir_edge_attachment_any)};
206 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);279#endif
207 return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};280 break;
208 }281 case mir_surface_type_inputmethod:
209 }282 spec = Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
210 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);283 break;
211 return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};284 default:
285 spec = Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
286 break;
287 }
288
289 qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)",
290 window, mirSurfaceTypeToStr(type), window->type(), location.left, location.top, width, height);
291
292 return std::move(spec);
212}293}
213294
214void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)295void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)
@@ -229,11 +310,11 @@
229 }310 }
230}311}
231312
232MirSurface *createMirSurface(QWindow *window, int mirOutputId, UbuntuInput *input, MirPixelFormat pixelFormat,313MirSurface *createMirSurface(QWindow *window, int mirOutputId, UbuntuWindow *parentWindowHandle,
233 MirConnection *connection, mir_surface_event_callback inputCallback,314 MirPixelFormat pixelFormat, MirConnection *connection,
234 void* inputContext)315 mir_surface_event_callback inputCallback, void *inputContext)
235{316{
236 auto spec = makeSurfaceSpec(window, input, pixelFormat, connection);317 auto spec = makeSurfaceSpec(window, pixelFormat, parentWindowHandle, connection);
237318
238 // Install event handler as early as possible319 // Install event handler as early as possible
239 mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext);320 mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext);
@@ -256,6 +337,20 @@
256 return surface;337 return surface;
257}338}
258339
340UbuntuWindow *getParentIfNecessary(QWindow *window, UbuntuInput *input)
341{
342 UbuntuWindow *parentWindowHandle = nullptr;
343 if (requiresParent(window->type())) {
344 parentWindowHandle = transientParentFor(window);
345 if (parentWindowHandle == nullptr) {
346 // NOTE: Mir requires this surface have a parent. Try using the last surface to receive input as that will
347 // most likely be the one that caused this surface to be created
348 parentWindowHandle = input->lastInputWindow();
349 }
350 }
351 return parentWindowHandle;
352}
353
259MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat)354MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat)
260{355{
261 switch(pixelFormat) {356 switch(pixelFormat) {
@@ -287,98 +382,18 @@
287382
288} //namespace383} //namespace
289384
385
386
290class UbuntuSurface387class UbuntuSurface
291{388{
292public:389public:
293 UbuntuSurface(UbuntuWindow *platformWindow, EGLDisplay display, UbuntuInput *input, MirConnection *connection)390 UbuntuSurface(UbuntuWindow *platformWindow, EGLDisplay display, UbuntuInput *input, MirConnection *connection);
294 : mWindow(platformWindow->window())391 ~UbuntuSurface();
295 , mPlatformWindow(platformWindow)
296 , mInput(input)
297 , mConnection(connection)
298 , mEglDisplay(display)
299 , mNeedsRepaint(false)
300 , mParented(mWindow->transientParent() || mWindow->parent())
301 , mFormat(mWindow->requestedFormat())
302 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
303 {
304 // Have Qt choose most suitable EGLConfig for the requested surface format, and update format to reflect it
305 EGLConfig config = q_configFromGLFormat(display, mFormat, true);
306 if (config == 0) {
307 // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default
308 // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a
309 // 1.4 context, but the XCB EGL backend tries to honour it, and fails. The 1.4 context appears to
310 // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default
311 // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455).
312 static const bool isMesa = QString(eglQueryString(display, EGL_VENDOR)).contains(QStringLiteral("Mesa"));
313 if (isMesa) {
314 qCDebug(ubuntumirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa");
315 mFormat.setMajorVersion(1);
316 mFormat.setMinorVersion(4);
317 config = q_configFromGLFormat(display, mFormat, true);
318 }
319 }
320 if (config == 0) {
321 qCritical() << "Qt failed to choose a suitable EGLConfig to suit the surface format" << mFormat;
322 }
323
324 mFormat = q_glFormatFromConfig(display, config, mFormat);
325
326 // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way
327 // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers.
328 auto pixelFormat = mir_connection_get_egl_pixel_format(connection, display, config);
329 // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client.
330 // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer.
331 // This is an optimisation for the compositor, as it can avoid blending this surface.
332 if (mWindow->requestedFormat().alphaBufferSize() < 0) {
333 pixelFormat = disableAlphaBufferIfPossible(pixelFormat);
334 }
335
336 const auto outputId = static_cast<UbuntuScreen *>(mWindow->screen()->handle())->mirOutputId();
337
338 mMirSurface = createMirSurface(mWindow, outputId, input, pixelFormat, connection, surfaceEventCallback, this);
339 mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirSurface), nullptr);
340
341 mNeedsExposeCatchup = mir_surface_get_visibility(mMirSurface) == mir_surface_visibility_occluded;
342
343 // Window manager can give us a final size different from what we asked for
344 // so let's check what we ended up getting
345 MirSurfaceParameters parameters;
346 mir_surface_get_parameters(mMirSurface, &parameters);
347
348 auto geom = mWindow->geometry();
349 geom.setWidth(parameters.width);
350 geom.setHeight(parameters.height);
351 if (mWindow->windowState() == Qt::WindowFullScreen) {
352 geom.moveTop(0);
353 } else {
354 geom.moveTop(panelHeight());
355 }
356
357 // Assume that the buffer size matches the surface size at creation time
358 mBufferSize = geom.size();
359 platformWindow->QPlatformWindow::setGeometry(geom);
360 QWindowSystemInterface::handleGeometryChange(mWindow, geom);
361
362 qCDebug(ubuntumirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title()
363 << "role:" << roleFor(mWindow);
364 qCDebug(ubuntumirclientGraphics)
365 << "Requested format:" << mWindow->requestedFormat()
366 << "\nActual format:" << mFormat
367 << "with associated Mir pixel format:" << mirPixelFormatToStr(pixelFormat);
368 }
369
370 ~UbuntuSurface()
371 {
372 if (mEglSurface != EGL_NO_SURFACE)
373 eglDestroySurface(mEglDisplay, mEglSurface);
374 if (mMirSurface)
375 mir_surface_release_sync(mMirSurface);
376 }
377392
378 UbuntuSurface(const UbuntuSurface &) = delete;393 UbuntuSurface(const UbuntuSurface &) = delete;
379 UbuntuSurface& operator=(const UbuntuSurface &) = delete;394 UbuntuSurface& operator=(const UbuntuSurface &) = delete;
380395
381 void resize(const QSize& newSize);396 void updateGeometry(const QRect &newGeometry);
382 void updateTitle(const QString& title);397 void updateTitle(const QString& title);
383 void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);398 void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
384399
@@ -414,6 +429,7 @@
414 UbuntuWindow * const mPlatformWindow;429 UbuntuWindow * const mPlatformWindow;
415 UbuntuInput * const mInput;430 UbuntuInput * const mInput;
416 MirConnection * const mConnection;431 MirConnection * const mConnection;
432 UbuntuWindow * mParentWindowHandle{nullptr};
417433
418 MirSurface* mMirSurface;434 MirSurface* mMirSurface;
419 const EGLDisplay mEglDisplay;435 const EGLDisplay mEglDisplay;
@@ -423,6 +439,7 @@
423 bool mParented;439 bool mParented;
424 QSize mBufferSize;440 QSize mBufferSize;
425 QSurfaceFormat mFormat;441 QSurfaceFormat mFormat;
442 MirPixelFormat mPixelFormat;
426443
427 QMutex mTargetSizeMutex;444 QMutex mTargetSizeMutex;
428 QSize mTargetSize;445 QSize mTargetSize;
@@ -430,23 +447,102 @@
430 QString mPersistentIdStr;447 QString mPersistentIdStr;
431};448};
432449
433void UbuntuSurface::resize(const QSize& size)450UbuntuSurface::UbuntuSurface(UbuntuWindow *platformWindow, EGLDisplay display, UbuntuInput *input, MirConnection *connection)
434{451 : mWindow(platformWindow->window())
435 qCDebug(ubuntumirclient,"resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());452 , mPlatformWindow(platformWindow)
436453 , mInput(input)
437 if (mWindow->windowState() == Qt::WindowFullScreen || mWindow->windowState() == Qt::WindowMaximized) {454 , mConnection(connection)
438 qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);455 , mEglDisplay(display)
439 return;456 , mNeedsRepaint(false)
440 }457 , mParented(mWindow->transientParent() || mWindow->parent())
441458 , mFormat(mWindow->requestedFormat())
442 if (size.isEmpty()) {459 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
443 qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, size is empty", mWindow);460{
444 return;461 // Have Qt choose most suitable EGLConfig for the requested surface format, and update format to reflect it
445 }462 EGLConfig config = q_configFromGLFormat(display, mFormat, true);
446463 if (config == 0) {
447 Spec spec{mir_connection_create_spec_for_changes(mConnection)};464 // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default
448 mir_surface_spec_set_width(spec.get(), size.width());465 // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a
449 mir_surface_spec_set_height(spec.get(), size.height());466 // 1.4 context, but the XCB EGL backend tries to honour it, and fails. The 1.4 context appears to
467 // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default
468 // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455).
469 static const bool isMesa = QString(eglQueryString(display, EGL_VENDOR)).contains(QStringLiteral("Mesa"));
470 if (isMesa) {
471 qCDebug(ubuntumirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa");
472 mFormat.setMajorVersion(1);
473 mFormat.setMinorVersion(4);
474 config = q_configFromGLFormat(display, mFormat, true);
475 }
476 }
477 if (config == 0) {
478 qCritical() << "Qt failed to choose a suitable EGLConfig to suit the surface format" << mFormat;
479 }
480
481 mFormat = q_glFormatFromConfig(display, config, mFormat);
482
483 // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way
484 // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers.
485 mPixelFormat = mir_connection_get_egl_pixel_format(connection, display, config);
486 // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client.
487 // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer.
488 // This is an optimisation for the compositor, as it can avoid blending this surface.
489 if (mWindow->requestedFormat().alphaBufferSize() < 0) {
490 mPixelFormat = disableAlphaBufferIfPossible(mPixelFormat);
491 }
492
493 const auto outputId = static_cast<UbuntuScreen *>(mWindow->screen()->handle())->mirOutputId();
494
495 mParentWindowHandle = getParentIfNecessary(mWindow, input);
496
497 mMirSurface = createMirSurface(mWindow, outputId, mParentWindowHandle, mPixelFormat, connection, surfaceEventCallback, this);
498 mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirSurface), nullptr);
499
500 mNeedsExposeCatchup = mir_surface_get_visibility(mMirSurface) == mir_surface_visibility_occluded;
501
502 // Window manager can give us a final size different from what we asked for
503 // so let's check what we ended up getting
504 MirSurfaceParameters parameters;
505 mir_surface_get_parameters(mMirSurface, &parameters);
506
507 auto geom = mWindow->geometry();
508 geom.setWidth(parameters.width);
509 geom.setHeight(parameters.height);
510
511 // Assume that the buffer size matches the surface size at creation time
512 mBufferSize = geom.size();
513 platformWindow->QPlatformWindow::setGeometry(geom);
514 QWindowSystemInterface::handleGeometryChange(mWindow, geom);
515
516 qCDebug(ubuntumirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title()
517 << "role:" << roleFor(mWindow);
518 qCDebug(ubuntumirclientGraphics)
519 << "Requested format:" << mWindow->requestedFormat()
520 << "\nActual format:" << mFormat
521 << "with associated Mir pixel format:" << mirPixelFormatToStr(mPixelFormat);
522}
523
524UbuntuSurface::~UbuntuSurface()
525{
526 if (mEglSurface != EGL_NO_SURFACE)
527 eglDestroySurface(mEglDisplay, mEglSurface);
528 if (mMirSurface) {
529 mir_surface_release_sync(mMirSurface);
530 }
531}
532
533void UbuntuSurface::updateGeometry(const QRect &newGeometry)
534{
535 qCDebug(ubuntumirclient,"updateGeometry(window=%p, width=%d, height=%d)", mWindow,
536 newGeometry.width(), newGeometry.height());
537
538 Spec spec;
539 if (isMovable(mWindow->type())) {
540 spec = Spec{makeSurfaceSpec(mWindow, mPixelFormat, mParentWindowHandle, mConnection)};
541 } else {
542 spec = Spec{mir_connection_create_spec_for_changes(mConnection)};
543 mir_surface_spec_set_width(spec.get(), newGeometry.width());
544 mir_surface_spec_set_height(spec.get(), newGeometry.height());
545 }
450 mir_surface_apply_spec(mMirSurface, spec.get());546 mir_surface_apply_spec(mMirSurface, spec.get());
451}547}
452548
@@ -690,7 +786,7 @@
690786
691void UbuntuWindow::handleSurfaceVisibilityChanged(bool visible)787void UbuntuWindow::handleSurfaceVisibilityChanged(bool visible)
692{788{
693 qCDebug(ubuntumirclient, "handleSurfaceVisibilityChanged(visible=%d)", visible);789 qCDebug(ubuntumirclient, "handleSurfaceVisibilityChanged(window=%p, visible=%d)", window(), visible);
694790
695 if (mWindowVisible == visible) return;791 if (mWindowVisible == visible) return;
696 mWindowVisible = visible;792 mWindowVisible = visible;
@@ -739,6 +835,10 @@
739 */835 */
740void UbuntuWindow::updatePanelHeightHack(bool enable)836void UbuntuWindow::updatePanelHeightHack(bool enable)
741{837{
838 if ((window()->type() & Qt::WindowType_Mask) != Qt::Window) { // only plain windows get the hack
839 return;
840 }
841
742 QMutexLocker lock(&mMutex);842 QMutexLocker lock(&mMutex);
743843
744 QRect newGeometry = geometry();844 QRect newGeometry = geometry();
@@ -758,13 +858,20 @@
758void UbuntuWindow::setGeometry(const QRect &rect)858void UbuntuWindow::setGeometry(const QRect &rect)
759{859{
760 QMutexLocker lock(&mMutex);860 QMutexLocker lock(&mMutex);
861
862 if (window()->windowState() == Qt::WindowFullScreen || window()->windowState() == Qt::WindowMaximized) {
863 qCDebug(ubuntumirclient, "setGeometry(window=%p) - not resizing, window is maximized or fullscreen", window());
864 return;
865 }
866
761 qCDebug(ubuntumirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)",867 qCDebug(ubuntumirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)",
762 window(), rect.x(), rect.y(), rect.width(), rect.height());868 window(), rect.x(), rect.y(), rect.width(), rect.height());
763869 // Immediately update internal geometry so Qt believes position updated
764 //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates870 QRect newPosition(geometry());
765 const auto newSize = rect.size();871 newPosition.moveTo(rect.topLeft());
766872 QPlatformWindow::setGeometry(newPosition);
767 mSurface->resize(newSize);873
874 mSurface->updateGeometry(rect);
768 // Note: don't call handleGeometryChange here, wait to see what Mir replies with.875 // Note: don't call handleGeometryChange here, wait to see what Mir replies with.
769}876}
770877

Subscribers

People subscribed via source and target branches