/* SPDX-FileCopyrightText: 2015 Martin Gräßlin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "server_decoration_interface.h" #include "display.h" #include "global_p.h" #include "logging.h" #include "resource_p.h" #include "surface_interface.h" #include #include namespace KWaylandServer { class ServerSideDecorationManagerInterface::Private : public Global::Private { public: Private(ServerSideDecorationManagerInterface *q, Display *d); Mode defaultMode = Mode::None; QVector resources; private: void bind(wl_client *client, uint32_t version, uint32_t id) override; static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { return reinterpret_cast(wl_resource_get_user_data(r)); } static void createCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface); void create(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface); ServerSideDecorationManagerInterface *q; static const struct org_kde_kwin_server_decoration_manager_interface s_interface; static const quint32 s_version; }; const quint32 ServerSideDecorationManagerInterface::Private::s_version = 1; #ifndef K_DOXYGEN const struct org_kde_kwin_server_decoration_manager_interface ServerSideDecorationManagerInterface::Private::s_interface = { createCallback }; #endif void ServerSideDecorationManagerInterface::Private::createCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface) { reinterpret_cast(wl_resource_get_user_data(resource))->create(client, resource, id, surface); } void ServerSideDecorationManagerInterface::Private::create(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface) { SurfaceInterface *s = SurfaceInterface::get(surface); if (!s) { // TODO: send error? qCWarning(KWAYLAND_SERVER) << "ServerSideDecorationInterface requested for non existing SurfaceInterface"; return; } ServerSideDecorationInterface *decoration = new ServerSideDecorationInterface(q, s, resource); decoration->create(display->getConnection(client), wl_resource_get_version(resource), id); if (!decoration->resource()) { wl_resource_post_no_memory(resource); delete decoration; return; } decoration->setMode(defaultMode); emit q->decorationCreated(decoration); } ServerSideDecorationManagerInterface::Mode ServerSideDecorationManagerInterface::defaultMode() const { return d_func()->defaultMode; } ServerSideDecorationManagerInterface::Private::Private(ServerSideDecorationManagerInterface *q, Display *d) : Global::Private(d, &org_kde_kwin_server_decoration_manager_interface, s_version) , q(q) { } namespace { static uint32_t modeWayland(ServerSideDecorationManagerInterface::Mode mode) { switch (mode) { case ServerSideDecorationManagerInterface::Mode::None: return ORG_KDE_KWIN_SERVER_DECORATION_MODE_NONE; break; case ServerSideDecorationManagerInterface::Mode::Client: return ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT; break; case ServerSideDecorationManagerInterface::Mode::Server: return ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER; break; default: Q_UNREACHABLE(); } } } void ServerSideDecorationManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); wl_resource *resource = c->createResource(&org_kde_kwin_server_decoration_manager_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &s_interface, this, unbind); resources << resource; org_kde_kwin_server_decoration_manager_send_default_mode(resource, modeWayland(defaultMode)); c->flush(); } void ServerSideDecorationManagerInterface::Private::unbind(wl_resource *resource) { cast(resource)->resources.removeAll(resource); } ServerSideDecorationManagerInterface::ServerSideDecorationManagerInterface(Display *display, QObject *parent) : Global(new Private(this, display), parent) { } ServerSideDecorationManagerInterface::~ServerSideDecorationManagerInterface() = default; ServerSideDecorationManagerInterface::Private *ServerSideDecorationManagerInterface::d_func() const { return reinterpret_cast(d.data()); } void ServerSideDecorationManagerInterface::setDefaultMode(Mode mode) { Q_D(); d->defaultMode = mode; const uint32_t wlMode = modeWayland(mode); for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); it++) { org_kde_kwin_server_decoration_manager_send_default_mode(*it, wlMode); } } class ServerSideDecorationInterface::Private : public Resource::Private { public: Private(ServerSideDecorationInterface *q, ServerSideDecorationManagerInterface *c, SurfaceInterface *surface, wl_resource *parentResource); ~Private(); ServerSideDecorationManagerInterface::Mode mode = ServerSideDecorationManagerInterface::Mode::None; SurfaceInterface *surface; static ServerSideDecorationInterface *get(SurfaceInterface *s); private: static void requestModeCallback(wl_client *client, wl_resource *resource, uint32_t mode); ServerSideDecorationInterface *q_func() { return reinterpret_cast(q); } static const struct org_kde_kwin_server_decoration_interface s_interface; static QVector s_all; }; #ifndef K_DOXYGEN const struct org_kde_kwin_server_decoration_interface ServerSideDecorationInterface::Private::s_interface = { resourceDestroyedCallback, requestModeCallback }; QVector ServerSideDecorationInterface::Private::s_all; #endif void ServerSideDecorationInterface::Private::requestModeCallback(wl_client *client, wl_resource *resource, uint32_t mode) { Q_UNUSED(client) ServerSideDecorationManagerInterface::Mode m = ServerSideDecorationManagerInterface::Mode::None; switch (mode) { case ORG_KDE_KWIN_SERVER_DECORATION_MODE_NONE: m = ServerSideDecorationManagerInterface::Mode::None; break; case ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT: m = ServerSideDecorationManagerInterface::Mode::Client; break; case ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER: m = ServerSideDecorationManagerInterface::Mode::Server; break; default: // invalid mode qCWarning(KWAYLAND_SERVER) << "Invalid mode:" << mode; return; } emit cast(resource)->q_func()->modeRequested(m); } ServerSideDecorationInterface *ServerSideDecorationInterface::Private::get(SurfaceInterface *s) { auto it = std::find_if(s_all.constBegin(), s_all.constEnd(), [s] (Private *p) { return p->surface == s; }); if (it == s_all.constEnd()) { return nullptr; } return (*it)->q_func(); } ServerSideDecorationInterface::Private::Private(ServerSideDecorationInterface *q, ServerSideDecorationManagerInterface *c, SurfaceInterface *surface, wl_resource *parentResource) : Resource::Private(q, c, parentResource, &org_kde_kwin_server_decoration_interface, &s_interface) , surface(surface) { s_all << this; } ServerSideDecorationInterface::Private::~Private() { s_all.removeAll(this); } ServerSideDecorationInterface::ServerSideDecorationInterface(ServerSideDecorationManagerInterface *parent, SurfaceInterface *surface, wl_resource *parentResource) : Resource(new Private(this, parent, surface, parentResource)) { } ServerSideDecorationInterface::~ServerSideDecorationInterface() = default; void ServerSideDecorationInterface::setMode(ServerSideDecorationManagerInterface::Mode mode) { Q_D(); d->mode = mode; org_kde_kwin_server_decoration_send_mode(resource(), modeWayland(mode)); client()->flush(); } ServerSideDecorationManagerInterface::Mode ServerSideDecorationInterface::mode() const { Q_D(); return d->mode; } SurfaceInterface *ServerSideDecorationInterface::surface() const { Q_D(); return d->surface; } ServerSideDecorationInterface::Private *ServerSideDecorationInterface::d_func() const { return reinterpret_cast(d.data()); } ServerSideDecorationInterface *ServerSideDecorationInterface::get(SurfaceInterface *s) { return Private::get(s); } }