6 #include "shell_interface.h"
8 #include "generic_shell_surface_p.h"
10 #include "resource_p.h"
11 #include "surface_interface.h"
15 #include <wayland-server.h>
21 class ShellInterface::Private :
public Global::Private
24 Private(ShellInterface *q, Display *d);
29 static void createSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t
id, wl_resource *surface);
30 void bind(wl_client *client, uint32_t version, uint32_t
id)
override;
31 void createSurface(wl_client *client, uint32_t version, uint32_t
id, SurfaceInterface *surface, wl_resource *parentResource);
34 static const struct wl_shell_interface s_interface;
35 static const quint32 s_version;
38 const quint32 ShellInterface::Private::s_version = 1;
40 ShellInterface::Private::Private(ShellInterface *q, Display *d)
41 : Global::Private(d, &wl_shell_interface, s_version)
47 const struct wl_shell_interface ShellInterface::Private::s_interface = {createSurfaceCallback};
50 class ShellSurfaceInterface::Private :
public Resource::Private,
public GenericShellSurface<ShellSurfaceInterface>
53 Private(ShellSurfaceInterface *q, ShellInterface *shell, SurfaceInterface *surface, wl_resource *parentResource);
56 void commit()
override;
59 quint32 pingSerial = 0;
60 enum class WindowMode {
66 WindowMode windowMode = WindowMode::Toplevel;
69 bool acceptsKeyboardFocus =
true;
70 void setWindowMode(WindowMode newWindowMode);
72 ShellSurfaceInterface *q_func()
74 return reinterpret_cast<ShellSurfaceInterface *
>(q);
79 static void pongCallback(wl_client *client, wl_resource *resource, uint32_t serial);
80 static void setToplevelCallback(wl_client *client, wl_resource *resource);
81 static void setTransientCallback(wl_client *client, wl_resource *resource, wl_resource *parent, int32_t x, int32_t y, uint32_t flags);
82 static void setFullscreenCallback(wl_client *client, wl_resource *resource, uint32_t method, uint32_t framerate, wl_resource *output);
84 setPopupCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, wl_resource *parent, int32_t x, int32_t y, uint32_t flags);
85 static void setMaximizedCallback(wl_client *client, wl_resource *resource, wl_resource *output);
87 void pong(quint32 serial);
88 void setAcceptsFocus(quint32 flags);
90 static const struct wl_shell_surface_interface s_interface;
93 ShellInterface::ShellInterface(Display *display,
QObject *parent)
94 : Global(new Private(this, display), parent)
98 ShellInterface::~ShellInterface() =
default;
100 void ShellInterface::Private::bind(wl_client *client, uint32_t version, uint32_t
id)
102 auto c = display->getConnection(client);
103 wl_resource *shell = c->createResource(&wl_shell_interface, qMin(version, s_version),
id);
105 wl_client_post_no_memory(client);
108 wl_resource_set_implementation(shell, &s_interface,
this,
nullptr);
111 void ShellInterface::Private::createSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t
id, wl_resource *surface)
113 auto s =
reinterpret_cast<ShellInterface::Private *
>(wl_resource_get_user_data(resource));
114 s->createSurface(client, wl_resource_get_version(resource), id,
SurfaceInterface::get(surface), resource);
117 void ShellInterface::Private::createSurface(wl_client *client, uint32_t version, uint32_t
id, SurfaceInterface *surface, wl_resource *parentResource)
119 auto it = std::find_if(surfaces.constBegin(), surfaces.constEnd(), [surface](ShellSurfaceInterface *s) {
120 return surface == s->surface();
122 if (it != surfaces.constEnd()) {
123 wl_resource_post_error(surface->resource(), WL_SHELL_ERROR_ROLE,
"ShellSurface already created");
126 ShellSurfaceInterface *shellSurface =
new ShellSurfaceInterface(q, surface, parentResource);
127 surfaces << shellSurface;
128 QObject::connect(shellSurface, &ShellSurfaceInterface::destroyed, q, [
this, shellSurface] {
129 surfaces.removeAll(shellSurface);
131 shellSurface->d->create(display->getConnection(client), version,
id);
132 Q_EMIT q->surfaceCreated(shellSurface);
138 ShellSurfaceInterface::Private::Private(ShellSurfaceInterface *q, ShellInterface *shell, SurfaceInterface *surface, wl_resource *parentResource)
139 :
Resource::Private(q, shell, parentResource, &wl_shell_surface_interface, &s_interface)
140 , GenericShellSurface<KWayland::Server::ShellSurfaceInterface>(q, surface)
143 pingTimer->setSingleShot(
true);
144 pingTimer->setInterval(1000);
148 const struct wl_shell_surface_interface ShellSurfaceInterface::Private::s_interface = {pongCallback,
150 resizeCallback<wl_shell_surface_resize>,
152 setTransientCallback,
153 setFullscreenCallback,
155 setMaximizedCallback,
160 ShellSurfaceInterface::ShellSurfaceInterface(ShellInterface *shell, SurfaceInterface *parent, wl_resource *parentResource)
161 :
Resource(new Private(this, shell, parent, parentResource))
165 auto unsetSurface = [
this] {
167 d->surface =
nullptr;
173 ShellSurfaceInterface::~ShellSurfaceInterface() =
default;
175 void ShellSurfaceInterface::Private::commit()
179 void ShellSurfaceInterface::Private::pongCallback(wl_client *client, wl_resource *resource, uint32_t serial)
181 auto s = cast<Private>(resource);
182 Q_ASSERT(client == *s->client);
186 void ShellSurfaceInterface::Private::pong(quint32 serial)
188 if (pingTimer->isActive() && serial == pingSerial) {
190 Q_Q(ShellSurfaceInterface);
191 Q_EMIT q->pongReceived();
195 void ShellSurfaceInterface::ping()
204 void ShellSurfaceInterface::Private::ping()
206 if (pingTimer->isActive()) {
209 pingSerial = global->display()->nextSerial();
210 wl_shell_surface_send_ping(resource, pingSerial);
215 void ShellSurfaceInterface::setPingTimeout(uint msec)
218 d->pingTimer->setInterval(msec);
221 bool ShellSurfaceInterface::isPinged()
const
224 return d->pingTimer->isActive();
227 void ShellSurfaceInterface::requestSize(
const QSize &size)
234 wl_shell_surface_send_configure(d->resource, 0, size.
width(), size.
height());
241 Qt::Edges edgesToQtEdges(wl_shell_surface_resize edges)
245 case WL_SHELL_SURFACE_RESIZE_TOP:
248 case WL_SHELL_SURFACE_RESIZE_BOTTOM:
251 case WL_SHELL_SURFACE_RESIZE_LEFT:
254 case WL_SHELL_SURFACE_RESIZE_TOP_LEFT:
257 case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT:
260 case WL_SHELL_SURFACE_RESIZE_RIGHT:
263 case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT:
266 case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT:
269 case WL_SHELL_SURFACE_RESIZE_NONE:
279 void ShellSurfaceInterface::Private::setToplevelCallback(wl_client *client, wl_resource *resource)
281 auto s = cast<Private>(resource);
282 Q_ASSERT(client == *s->client);
283 s->setWindowMode(WindowMode::Toplevel);
286 void ShellSurfaceInterface::Private::setTransientCallback(wl_client *client, wl_resource *resource, wl_resource *parent, int32_t x, int32_t y, uint32_t flags)
289 auto s = cast<Private>(resource);
290 Q_ASSERT(client == *s->client);
292 if (surface && s->surface == surface) {
293 wl_resource_post_error(surface->resource(), WL_SHELL_ERROR_ROLE,
"Cannot be a transient to itself");
297 s->transientOffset =
QPoint(x, y);
298 Q_EMIT s->q_func()->transientChanged(!s->transientFor.isNull());
299 Q_EMIT s->q_func()->transientOffsetChanged(s->transientOffset);
300 Q_EMIT s->q_func()->transientForChanged();
301 s->setAcceptsFocus(flags);
304 void ShellSurfaceInterface::Private::setAcceptsFocus(quint32 flags)
306 const bool acceptsFocus = !(flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
307 if (acceptsFocus != acceptsKeyboardFocus) {
308 acceptsKeyboardFocus = acceptsFocus;
309 Q_Q(ShellSurfaceInterface);
310 Q_EMIT q->acceptsKeyboardFocusChanged();
314 void ShellSurfaceInterface::Private::setFullscreenCallback(wl_client *client, wl_resource *resource, uint32_t method, uint32_t framerate, wl_resource *output)
319 auto s = cast<Private>(resource);
320 Q_ASSERT(client == *s->client);
322 s->setWindowMode(WindowMode::Fullscreen);
325 void ShellSurfaceInterface::Private::setWindowMode(WindowMode newWindowMode)
327 if (windowMode == newWindowMode) {
330 const WindowMode oldWindowMode = windowMode;
331 windowMode = newWindowMode;
332 Q_Q(ShellSurfaceInterface);
333 if (oldWindowMode == WindowMode::Fullscreen || newWindowMode == WindowMode::Fullscreen) {
334 Q_EMIT q->fullscreenChanged(windowMode == WindowMode::Fullscreen);
336 if (oldWindowMode == WindowMode::Toplevel || newWindowMode == WindowMode::Toplevel) {
337 Q_EMIT q->toplevelChanged(windowMode == WindowMode::Toplevel);
339 if (oldWindowMode == WindowMode::Maximized || newWindowMode == WindowMode::Maximized) {
340 Q_EMIT q->maximizedChanged(windowMode == WindowMode::Maximized);
342 if (oldWindowMode == WindowMode::Popup || newWindowMode == WindowMode::Popup) {
343 Q_EMIT q->popupChanged(windowMode == WindowMode::Popup);
347 void ShellSurfaceInterface::Private::setPopupCallback(wl_client *client,
348 wl_resource *resource,
359 auto s = cast<Private>(resource);
360 Q_ASSERT(client == *s->client);
363 s->transientOffset =
QPoint(x, y);
364 s->setWindowMode(WindowMode::Popup);
365 Q_EMIT s->q_func()->transientChanged(!s->transientFor.isNull());
366 Q_EMIT s->q_func()->transientOffsetChanged(s->transientOffset);
367 Q_EMIT s->q_func()->transientForChanged();
371 s->setAcceptsFocus(WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
374 void ShellSurfaceInterface::Private::setMaximizedCallback(wl_client *client, wl_resource *resource, wl_resource *output)
377 auto s = cast<Private>(resource);
378 Q_ASSERT(client == *s->client);
379 s->setWindowMode(WindowMode::Maximized);
394 QString ShellSurfaceInterface::title()
const
400 QByteArray ShellSurfaceInterface::windowClass()
const
403 return d->windowClass;
406 bool ShellSurfaceInterface::isFullscreen()
const
409 return d->windowMode == Private::WindowMode::Fullscreen;
412 bool ShellSurfaceInterface::isToplevel()
const
415 return d->windowMode == Private::WindowMode::Toplevel;
418 bool ShellSurfaceInterface::isMaximized()
const
421 return d->windowMode == Private::WindowMode::Maximized;
424 bool ShellSurfaceInterface::isPopup()
const
427 return d->windowMode == Private::WindowMode::Popup;
430 bool ShellSurfaceInterface::isTransient()
const
433 return !d->transientFor.isNull();
436 QPoint ShellSurfaceInterface::transientOffset()
const
439 return d->transientOffset;
442 bool ShellSurfaceInterface::acceptsKeyboardFocus()
const
445 return d->acceptsKeyboardFocus;
448 void ShellSurfaceInterface::popupDone()
451 if (isPopup() && d->resource) {
452 wl_shell_surface_send_popup_done(d->resource);
459 return d->transientFor;
462 ShellSurfaceInterface::Private *ShellSurfaceInterface::d_func()
const
464 return reinterpret_cast<ShellSurfaceInterface::Private *
>(d.data());