65
87
case Qt::WindowNoState:
68
89
case Qt::WindowFullScreen:
69
90
return "FullScreen";
71
91
case Qt::WindowMaximized:
72
92
return "Maximized";
74
93
case Qt::WindowMinimized:
75
94
return "Minimized";
83
} // anonymous namespace
85
class UbuntuWindowPrivate
88
void createEGLSurface(EGLNativeWindowType nativeWindow);
89
void destroyEGLSurface();
93
EGLSurface eglSurface;
96
Qt::WindowState state;
97
MirConnection *connection;
101
QSharedPointer<UbuntuClipboard> clipboard;
102
int resizeCatchUpAttempts;
103
#if !defined(QT_NO_DEBUG)
108
static void eventCallback(MirSurface* surface, const MirEvent *event, void* context)
111
DASSERT(context != NULL);
112
UbuntuWindow* platformWindow = static_cast<UbuntuWindow*>(context);
113
platformWindow->priv()->input->postEvent(platformWindow, event);
116
static void surfaceCreateCallback(MirSurface* surface, void* context)
118
DASSERT(context != NULL);
119
UbuntuWindow* platformWindow = static_cast<UbuntuWindow*>(context);
120
platformWindow->priv()->surface = surface;
122
mir_surface_set_event_handler(surface, eventCallback, context);
125
UbuntuWindow::UbuntuWindow(QWindow* w, QSharedPointer<UbuntuClipboard> clipboard, UbuntuScreen* screen,
126
UbuntuInput* input, MirConnection* connection)
127
: QObject(nullptr), QPlatformWindow(w)
129
DASSERT(screen != NULL);
131
d = new UbuntuWindowPrivate;
133
d->eglSurface = EGL_NO_SURFACE;
135
d->state = window()->windowState();
136
d->connection = connection;
137
d->clipboard = clipboard;
138
d->resizeCatchUpAttempts = 0;
140
103
static int id = 1;
143
#if !defined(QT_NO_DEBUG)
147
// Use client geometry if set explicitly, use available screen geometry otherwise.
148
QPlatformWindow::setGeometry(window()->geometry() != screen->geometry() ?
149
window()->geometry() : screen->availableGeometry());
151
DLOG("UbuntuWindow::UbuntuWindow (this=%p, w=%p, screen=%p, input=%p)", this, w, screen, input);
154
UbuntuWindow::~UbuntuWindow()
156
DLOG("UbuntuWindow::~UbuntuWindow");
157
d->destroyEGLSurface();
159
mir_surface_release_sync(d->surface);
164
void UbuntuWindowPrivate::createEGLSurface(EGLNativeWindowType nativeWindow)
166
DLOG("UbuntuWindowPrivate::createEGLSurface (this=%p, nativeWindow=%p)",
167
this, reinterpret_cast<void*>(nativeWindow));
169
eglSurface = eglCreateWindowSurface(screen->eglDisplay(), screen->eglConfig(),
170
nativeWindow, nullptr);
172
DASSERT(eglSurface != EGL_NO_SURFACE);
175
void UbuntuWindowPrivate::destroyEGLSurface()
177
DLOG("UbuntuWindowPrivate::destroyEGLSurface (this=%p)", this);
178
if (eglSurface != EGL_NO_SURFACE) {
179
eglDestroySurface(screen->eglDisplay(), eglSurface);
180
eglSurface = EGL_NO_SURFACE;
107
MirPixelFormat defaultPixelFormatFor(MirConnection *connection)
109
MirPixelFormat format;
110
unsigned int nformats;
111
mir_connection_get_available_surface_formats(connection, &format, 1, &nformats);
115
UAUiWindowRole roleFor(QWindow *window)
117
QVariant roleVariant = window->property("role");
118
if (!roleVariant.isValid())
121
uint role = roleVariant.toUInt();
122
if (role < U_MAIN_ROLE || role > U_SHUTDOWN_DIALOG_ROLE)
125
return static_cast<UAUiWindowRole>(role);
128
UbuntuWindow *transientParentFor(QWindow *window)
130
QWindow *parent = window->transientParent();
131
return parent ? static_cast<UbuntuWindow *>(parent->handle()) : nullptr;
134
Spec makeSurfaceSpec(QWindow *window, UbuntuInput *input, MirConnection *connection)
136
const auto geom = window->geometry();
137
const int width = geom.width() > 0 ? geom.width() : 1;
138
const int height = geom.height() > 0 ? geom.height() : 1;
139
const auto pixelFormat = defaultPixelFormatFor(connection);
141
if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
142
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);
143
return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
146
const Qt::WindowType type = window->type();
147
if (type == Qt::Popup) {
148
auto parent = transientParentFor(window);
149
if (parent == nullptr) {
150
//NOTE: We cannot have a parentless popup -
151
//try using the last surface to receive input as that will most likely be
152
//the one that caused this popup to be created
153
parent = input->lastFocusedWindow();
156
auto pos = geom.topLeft();
157
pos -= parent->geometry().topLeft();
158
MirRectangle location{pos.x(), pos.y(), 0, 0};
159
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);
160
return Spec{mir_connection_create_spec_for_menu(
161
connection, width, height, pixelFormat, parent->mirSurface(),
162
&location, mir_edge_attachment_any)};
164
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
166
} else if (type == Qt::Dialog) {
167
auto parent = transientParentFor(window);
170
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);
171
return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};
173
// TODO: do Qt parentless dialogs have the same semantics as mir?
174
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);
175
return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
178
DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);
179
return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
182
void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)
184
mir_surface_spec_set_min_width(spec, minSize.width());
185
mir_surface_spec_set_min_height(spec, minSize.height());
186
if (maxSize.width() >= minSize.width()) {
187
mir_surface_spec_set_max_width(spec, maxSize.width());
189
if (maxSize.height() >= minSize.height()) {
190
mir_surface_spec_set_max_height(spec, maxSize.height());
192
if (increment.width() > 0) {
193
mir_surface_spec_set_width_increment(spec, increment.width());
195
if (increment.height() > 0) {
196
mir_surface_spec_set_height_increment(spec, increment.height());
200
MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)
202
auto spec = makeSurfaceSpec(window, input, connection);
203
const auto title = window->title().toUtf8();
204
mir_surface_spec_set_name(spec.get(), title.constData());
206
setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement());
208
if (window->windowState() == Qt::WindowFullScreen) {
209
mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());
212
auto surface = mir_surface_create_sync(spec.get());
213
Q_ASSERT(mir_surface_is_valid(surface));
184
217
// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
185
218
// we need to guess the panel height (3GU + 2DP)
186
int UbuntuWindowPrivate::panelHeight()
188
221
const int defaultGridUnit = 8;
189
222
int gridUnit = defaultGridUnit;
199
232
return gridUnit * 3 + qFloor(densityPixelRatio) * 2;
204
static MirPixelFormat
205
mir_choose_default_pixel_format(MirConnection *connection)
207
MirPixelFormat format[mir_pixel_formats];
208
unsigned int nformats;
210
mir_connection_get_available_surface_formats(connection,
211
format, mir_pixel_formats, &nformats);
217
void UbuntuWindow::createWindow()
219
DLOG("UbuntuWindow::createWindow (this=%p)", this);
221
// FIXME: remove this remnant of an old platform-api enum - needs ubuntu-keyboard update
222
const int SCREEN_KEYBOARD_ROLE = 7;
223
// Get surface role and flags.
224
QVariant roleVariant = window()->property("role");
225
int role = roleVariant.isValid() ? roleVariant.toUInt() : 1; // 1 is the default role for apps.
226
QVariant opaqueVariant = window()->property("opaque");
227
uint flags = opaqueVariant.isValid() ?
228
opaqueVariant.toUInt() ? static_cast<uint>(IS_OPAQUE_FLAG) : 0 : 0;
230
// FIXME(loicm) Opaque flag is forced for now for non-system sessions (applications) for
231
// performance reasons.
232
flags |= static_cast<uint>(IS_OPAQUE_FLAG);
234
const QByteArray title = (!window()->title().isNull()) ? window()->title().toUtf8() : "Window 1"; // legacy title
235
const int panelHeight = d->panelHeight();
237
#if !defined(QT_NO_DEBUG)
238
LOG("panelHeight: '%d'", panelHeight);
239
LOG("role: '%d'", role);
240
LOG("flags: '%s'", (flags & static_cast<uint>(1)) ? "Opaque" : "NotOpaque");
241
LOG("title: '%s'", title.constData());
244
// Get surface geometry.
246
if (d->state == Qt::WindowFullScreen) {
247
printf("UbuntuWindow - fullscreen geometry\n");
248
geometry = screen()->geometry();
249
} else if (d->state == Qt::WindowMaximized) {
250
printf("UbuntuWindow - maximized geometry\n");
251
geometry = screen()->availableGeometry();
253
* FIXME: Autopilot relies on being able to convert coordinates relative of the window
254
* into absolute screen coordinates. Mir does not allow this, see bug lp:1346633
255
* Until there's a correct way to perform this transformation agreed, this horrible hack
256
* guesses the transformation heuristically.
258
* Assumption: this method only used on phone devices!
260
geometry.setY(panelHeight);
262
printf("UbuntuWindow - regular geometry\n");
263
geometry = this->geometry();
264
geometry.setY(panelHeight);
267
DLOG("[ubuntumirclient QPA] creating surface at (%d, %d) with size (%d, %d) with title '%s'\n",
268
geometry.x(), geometry.y(), geometry.width(), geometry.height(), title.data());
270
MirSurfaceSpec *spec;
271
if (role == SCREEN_KEYBOARD_ROLE)
273
spec = mir_connection_create_spec_for_input_method(d->connection, geometry.width(),
274
geometry.height(), mir_choose_default_pixel_format(d->connection));
278
spec = mir_connection_create_spec_for_normal_surface(d->connection, geometry.width(),
279
geometry.height(), mir_choose_default_pixel_format(d->connection));
281
mir_surface_spec_set_name(spec, title.data());
283
// Create platform window
284
mir_wait_for(mir_surface_create(spec, surfaceCreateCallback, this));
285
mir_surface_spec_release(spec);
287
DASSERT(d->surface != NULL);
288
d->createEGLSurface((EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(d->surface)));
290
if (d->state == Qt::WindowFullScreen) {
291
// TODO: We could set this on creation once surface spec supports it (mps already up)
292
mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_fullscreen));
295
// Window manager can give us a final size different from what we asked for
296
// so let's check what we ended up getting
240
UbuntuSurface(UbuntuWindow *platformWindow, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)
241
: mWindow(platformWindow->window())
242
, mPlatformWindow(platformWindow)
245
, mConnection(connection)
246
, mMirSurface(createMirSurface(mWindow, screen, input, connection))
247
, mEglDisplay(screen->eglDisplay())
248
, mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr))
250
, mNeedsRepaint(false)
251
, mParented(mWindow->transientParent() || mWindow->parent())
252
, mWindowState(mWindow->windowState())
255
mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this);
257
// Window manager can give us a final size different from what we asked for
258
// so let's check what we ended up getting
298
259
MirSurfaceParameters parameters;
299
mir_surface_get_parameters(d->surface, ¶meters);
301
geometry.setWidth(parameters.width);
302
geometry.setHeight(parameters.height);
305
DLOG("[ubuntumirclient QPA] created surface has size (%d, %d)",
306
geometry.width(), geometry.height());
308
// Assume that the buffer size matches the surface size at creation time
309
d->bufferSize = geometry.size();
311
// Tell Qt about the geometry.
312
QWindowSystemInterface::handleGeometryChange(window(), geometry);
313
QPlatformWindow::setGeometry(geometry);
316
void UbuntuWindow::moveResize(const QRect& rect)
319
// TODO: Not yet supported by mir.
322
void UbuntuWindow::handleSurfaceResize(int width, int height)
324
QMutexLocker(&d->mutex);
325
DLOG("UbuntuWindow::handleSurfaceResize(width=%d, height=%d) [%d]", width, height,
328
// The current buffer size hasn't actually changed. so just render on it and swap
329
// buffers in the hope that the next buffer will match the surface size advertised
331
// But since this event is processed by a thread different from the one that swaps
332
// buffers, you can never know if this information is already outdated as there's
333
// no synchronicity whatsoever between the processing of resize events and the
334
// consumption of buffers.
335
if (d->bufferSize.width() != width || d->bufferSize.height() != height) {
336
// if the next buffer doesn't have a different size, try some
338
// FIXME: This is working around a mir bug! We really shound't have to
339
// swap more than once to get a buffer with the new size!
340
d->resizeCatchUpAttempts = 2;
342
QWindowSystemInterface::handleExposeEvent(window(), geometry());
343
QWindowSystemInterface::flushWindowSystemEvents();
347
void UbuntuWindow::handleSurfaceFocusChange(bool focused)
349
LOG("UbuntuWindow::handleSurfaceFocusChange(focused=%s)", focused ? "true" : "false");
350
QWindow *activatedWindow = focused ? window() : nullptr;
352
// System clipboard contents might have changed while this window was unfocused and wihtout
260
mir_surface_get_parameters(mMirSurface, ¶meters);
262
auto geom = mWindow->geometry();
263
geom.setWidth(parameters.width);
264
geom.setHeight(parameters.height);
265
geom.setY(panelHeight());
267
// Assume that the buffer size matches the surface size at creation time
268
mBufferSize = geom.size();
269
platformWindow->QPlatformWindow::setGeometry(geom);
270
QWindowSystemInterface::handleGeometryChange(mWindow, geom);
272
DLOG("[ubuntumirclient QPA] created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n",
273
geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow));
278
if (mEglSurface != EGL_NO_SURFACE)
279
eglDestroySurface(mEglDisplay, mEglSurface);
281
mir_surface_release_sync(mMirSurface);
284
void resize(const QSize& newSize);
285
void setState(Qt::WindowState newState);
286
void setVisible(bool state);
287
void updateTitle(const QString& title);
288
void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
290
void onSwapBuffersDone();
291
void handleSurfaceResized(int width, int height);
292
int needsRepaint() const;
294
EGLSurface eglSurface() const { return mEglSurface; }
295
MirSurface *mirSurface() const { return mMirSurface; }
298
static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context);
299
void postEvent(const MirEvent *event);
300
void updateSurface();
302
QWindow * const mWindow;
303
UbuntuWindow * const mPlatformWindow;
304
UbuntuScreen * const mScreen;
305
UbuntuInput * const mInput;
306
MirConnection * const mConnection;
308
MirSurface * const mMirSurface;
309
const EGLDisplay mEglDisplay;
310
const EGLSurface mEglSurface;
315
Qt::WindowState mWindowState;
318
QMutex mTargetSizeMutex;
322
void UbuntuSurface::resize(const QSize& size)
324
DLOG("[ubuntumirclient QPA] resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
326
if (mWindowState == Qt::WindowFullScreen || mWindowState == Qt::WindowMaximized) {
327
DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
331
if (size.isEmpty()) {
332
DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, size is empty", mWindow);
336
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
337
mir_surface_spec_set_width(spec.get(), size.width());
338
mir_surface_spec_set_height(spec.get(), size.height());
339
mir_surface_apply_spec(mMirSurface, spec.get());
342
void UbuntuSurface::setState(Qt::WindowState newState)
344
mir_wait_for(mir_surface_set_state(mMirSurface, qtWindowStateToMirSurfaceState(newState)));
345
mWindowState = newState;
348
void UbuntuSurface::setVisible(bool visible)
350
if (mVisible == visible)
358
// TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
359
// Will have to change qtmir and unity8 for that.
360
const auto newState = visible ? qtWindowStateToMirSurfaceState(mWindowState) : mir_surface_state_minimized;
361
mir_wait_for(mir_surface_set_state(mMirSurface, newState));
364
void UbuntuSurface::updateTitle(const QString& newTitle)
366
const auto title = newTitle.toUtf8();
367
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
368
mir_surface_spec_set_name(spec.get(), title.constData());
369
mir_surface_apply_spec(mMirSurface, spec.get());
372
void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment)
374
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
375
::setSizingConstraints(spec.get(), minSize, maxSize, increment);
376
mir_surface_apply_spec(mMirSurface, spec.get());
379
void UbuntuSurface::handleSurfaceResized(int width, int height)
381
QMutexLocker lock(&mTargetSizeMutex);
383
// mir's resize event is mainly a signal that we need to redraw our content. We use the
384
// width/height as identifiers to figure out if this is the latest surface resize event
385
// that has posted, discarding any old ones. This avoids issuing too many redraw events.
386
// see TODO in postEvent as the ideal way we should handle this.
387
// The actual buffer size may or may have not changed at this point, so let the rendering
388
// thread drive the window geometry updates.
389
mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height;
392
int UbuntuSurface::needsRepaint() const
395
if (mTargetSize != mBufferSize) {
396
//If the buffer hasn't changed yet, we need at least two redraws,
397
//once to get the new buffer size and propagate the geometry changes
398
//and the second to redraw the content at the new size
401
// The buffer size has already been updated so we only need one redraw
402
// to render at the new size
409
void UbuntuSurface::onSwapBuffersDone()
411
#if !defined(QT_NO_DEBUG)
412
static int sFrameNumber = 0;
416
EGLint eglSurfaceWidth = -1;
417
EGLint eglSurfaceHeight = -1;
418
eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth);
419
eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight);
421
const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0;
423
if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {
425
DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
426
mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);
428
mBufferSize.rwidth() = eglSurfaceWidth;
429
mBufferSize.rheight() = eglSurfaceHeight;
431
QRect newGeometry = mPlatformWindow->geometry();
432
newGeometry.setSize(mBufferSize);
434
mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
435
QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
437
DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
438
mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());
442
void UbuntuSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context)
445
Q_ASSERT(context != nullptr);
447
auto s = static_cast<UbuntuSurface *>(context);
451
void UbuntuSurface::postEvent(const MirEvent *event)
453
if (mir_event_type_resize == mir_event_get_type(event)) {
454
// TODO: The current event queue just accumulates all resize events;
455
// It would be nicer if we could update just one event if that event has not been dispatched.
456
// As a workaround, we use the width/height as an identifier of this latest event
457
// so the event handler (handleSurfaceResized) can discard/ignore old ones.
458
const auto resizeEvent = mir_event_get_resize_event(event);
459
const auto width = mir_resize_event_get_width(resizeEvent);
460
const auto height = mir_resize_event_get_height(resizeEvent);
461
DLOG("[ubuntumirclient QPA] resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);
463
QMutexLocker lock(&mTargetSizeMutex);
464
mTargetSize.rwidth() = width;
465
mTargetSize.rheight() = height;
468
mInput->postEvent(mPlatformWindow, event);
471
void UbuntuSurface::updateSurface()
473
DLOG("[ubuntumirclient QPA] updateSurface(window=%p)", mWindow);
475
if (!mParented && mWindow->type() == Qt::Dialog) {
476
// The dialog may have been parented after creation time
477
// so morph it into a modal dialog
478
auto parent = transientParentFor(mWindow);
480
DLOG("[ubuntumirclient QPA] updateSurface(window=%p) dialog now parented", mWindow);
482
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
483
mir_surface_spec_set_parent(spec.get(), parent->mirSurface());
484
mir_surface_apply_spec(mMirSurface, spec.get());
489
UbuntuWindow::UbuntuWindow(QWindow *w, QSharedPointer<UbuntuClipboard> clipboard, UbuntuScreen *screen,
490
UbuntuInput *input, MirConnection *connection)
494
, mClipboard(clipboard)
495
, mSurface(new UbuntuSurface{this, screen, input, connection})
497
DLOG("[ubuntumirclient QPA] UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());
500
UbuntuWindow::~UbuntuWindow()
502
DLOG("[ubuntumirclient QPA] ~UbuntuWindow(window=%p)", this);
505
void UbuntuWindow::handleSurfaceResized(int width, int height)
507
QMutexLocker lock(&mMutex);
508
DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height);
510
mSurface->handleSurfaceResized(width, height);
512
// This resize event could have occurred just after the last buffer swap for this window.
513
// This means the client may still be holding a buffer with the older size. The first redraw call
514
// will then render at the old size. After swapping the client now will get a new buffer with the
515
// updated size but it still needs re-rendering so another redraw may be needed.
516
// A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice
517
auto const numRepaints = mSurface->needsRepaint();
518
DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
519
for (int i = 0; i < numRepaints; i++) {
520
DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());
521
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
525
void UbuntuWindow::handleSurfaceFocused()
527
DLOG("[ubuntumirclient QPA] handleSurfaceFocused(window=%p)", window());
529
// System clipboard contents might have changed while this window was unfocused and without
353
530
// this process getting notified about it because it might have been suspended (due to
354
531
// application lifecycle policies), thus unable to listen to any changes notified through
356
533
// Therefore let's ensure we are up to date with the system clipboard now that we are getting
357
534
// focused again.
359
d->clipboard->requestDBusClipboardContents();
362
QWindowSystemInterface::handleWindowActivated(activatedWindow, Qt::ActiveWindowFocusReason);
535
mClipboard->requestDBusClipboardContents();
536
QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
365
539
void UbuntuWindow::setWindowState(Qt::WindowState state)
367
QMutexLocker(&d->mutex);
368
DLOG("UbuntuWindow::setWindowState (this=%p, %s)", this, qtWindowStateToStr(state));
370
if (state == d->state)
373
// TODO: Perhaps we should check if the states are applied?
374
mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(state)));
541
QMutexLocker lock(&mMutex);
542
DLOG("[ubuntumirclient QPA] setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
543
mSurface->setState(state);
378
546
void UbuntuWindow::setGeometry(const QRect& rect)
380
DLOG("UbuntuWindow::setGeometry (this=%p)", this);
385
QMutexLocker(&d->mutex);
386
QPlatformWindow::setGeometry(rect);
387
doMoveResize = d->state != Qt::WindowFullScreen && d->state != Qt::WindowMaximized;
548
QMutexLocker lock(&mMutex);
549
DLOG("[ubuntumirclient QPA] setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)",
550
window(), rect.x(), rect.y(), rect.width(), rect.height());
552
//NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates
553
const auto newSize = rect.size();
554
auto newGeometry = geometry();
555
newGeometry.setSize(newSize);
556
QPlatformWindow::setGeometry(newGeometry);
558
mSurface->resize(newSize);
395
561
void UbuntuWindow::setVisible(bool visible)
397
QMutexLocker(&d->mutex);
398
DLOG("UbuntuWindow::setVisible (this=%p, visible=%s)", this, visible ? "true" : "false");
401
mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(d->state)));
403
QWindowSystemInterface::handleExposeEvent(window(), QRect());
404
QWindowSystemInterface::flushWindowSystemEvents();
406
// TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
407
// Will have to change qtmir and unity8 for that.
408
mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_minimized));
412
void UbuntuWindow::setWindowTitle(const QString &title)
414
MirSurfaceSpec *spec = mir_connection_create_spec_for_changes(d->connection);
415
mir_surface_spec_set_name(spec, title.toUtf8().constData());
416
mir_surface_apply_spec(d->surface, spec);
417
mir_surface_spec_release(spec);
563
QMutexLocker lock(&mMutex);
564
DLOG("[ubuntumirclient QPA] setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false");
566
mSurface->setVisible(visible);
567
const QRect& exposeRect = visible ? QRect(QPoint(), geometry().size()) : QRect();
570
QWindowSystemInterface::handleExposeEvent(window(), exposeRect);
571
QWindowSystemInterface::flushWindowSystemEvents();
574
void UbuntuWindow::setWindowTitle(const QString& title)
576
QMutexLocker lock(&mMutex);
577
DLOG("[ubuntumirclient QPA] setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
578
mSurface->updateTitle(title);
581
void UbuntuWindow::propagateSizeHints()
583
QMutexLocker lock(&mMutex);
584
const auto win = window();
585
DLOG("[ubuntumirclient QPA] propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",
586
win, win->minimumSize().width(), win->minimumSize().height(),
587
win->maximumSize().width(), win->maximumSize().height(),
588
win->sizeIncrement().width(), win->sizeIncrement().height());
589
mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement());
420
592
void* UbuntuWindow::eglSurface() const
422
return d->eglSurface;
594
return mSurface->eglSurface();
597
MirSurface *UbuntuWindow::mirSurface() const
599
return mSurface->mirSurface();
425
602
WId UbuntuWindow::winId() const
430
void UbuntuWindow::onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight)
607
void UbuntuWindow::onSwapBuffersDone()
432
QMutexLocker(&d->mutex);
434
bool sizeKnown = newBufferWidth > 0 && newBufferHeight > 0;
436
#if !defined(QT_NO_DEBUG)
440
if (sizeKnown && (d->bufferSize.width() != newBufferWidth ||
441
d->bufferSize.height() != newBufferHeight)) {
442
d->resizeCatchUpAttempts = 0;
444
DLOG("UbuntuWindow::onBuffersSwapped_threadSafe [%d] - buffer size changed from (%d,%d) to (%d,%d)"
445
" resizeCatchUpAttempts=%d",
446
d->frameNumber, d->bufferSize.width(), d->bufferSize.height(), newBufferWidth, newBufferHeight,
447
d->resizeCatchUpAttempts);
449
d->bufferSize.rwidth() = newBufferWidth;
450
d->bufferSize.rheight() = newBufferHeight;
454
newGeometry = geometry();
455
newGeometry.setWidth(d->bufferSize.width());
456
newGeometry.setHeight(d->bufferSize.height());
458
QPlatformWindow::setGeometry(newGeometry);
459
QWindowSystemInterface::handleGeometryChange(window(), newGeometry, QRect());
460
} else if (d->resizeCatchUpAttempts > 0) {
461
--d->resizeCatchUpAttempts;
462
DLOG("UbuntuWindow::onBuffersSwapped_threadSafe [%d] - buffer size (%d,%d). Redrawing to catch up a resized buffer."
463
" resizeCatchUpAttempts=%d",
464
d->frameNumber, d->bufferSize.width(), d->bufferSize.height(), d->resizeCatchUpAttempts);
465
QWindowSystemInterface::handleExposeEvent(window(), geometry());
467
DLOG("UbuntuWindow::onBuffersSwapped_threadSafe [%d] - buffer size (%d,%d). resizeCatchUpAttempts=%d",
468
d->frameNumber, d->bufferSize.width(), d->bufferSize.height(), d->resizeCatchUpAttempts);
609
QMutexLocker lock(&mMutex);
610
mSurface->onSwapBuffersDone();