/* SPDX-FileCopyrightText: 2015 Martin Gräßlin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "plasmashell_interface.h" #include "global_p.h" #include "resource_p.h" #include "display.h" #include "surface_interface.h" #include #include #include namespace KWaylandServer { class PlasmaShellInterface::Private : public Global::Private { public: Private(PlasmaShellInterface *q, Display *d); QList surfaces; private: static void createSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface); void bind(wl_client *client, uint32_t version, uint32_t id) override; void createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource); PlasmaShellInterface *q; static const struct org_kde_plasma_shell_interface s_interface; static const quint32 s_version; }; const quint32 PlasmaShellInterface::Private::s_version = 6; PlasmaShellInterface::Private::Private(PlasmaShellInterface *q, Display *d) : Global::Private(d, &org_kde_plasma_shell_interface, s_version) , q(q) { } #ifndef K_DOXYGEN const struct org_kde_plasma_shell_interface PlasmaShellInterface::Private::s_interface = { createSurfaceCallback }; #endif class PlasmaShellSurfaceInterface::Private : public Resource::Private { public: Private(PlasmaShellSurfaceInterface *q, PlasmaShellInterface *shell, SurfaceInterface *surface, wl_resource *parentResource); QPointer surface; QPoint m_globalPos; Role m_role = Role::Normal; bool m_positionSet = false; PanelBehavior m_panelBehavior = PanelBehavior::AlwaysVisible; bool m_skipTaskbar = false; bool m_skipSwitcher = false; bool panelTakesFocus = false; private: // interface callbacks static void setOutputCallback(wl_client *client, wl_resource *resource, wl_resource *output); static void setPositionCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y); static void setRoleCallback(wl_client *client, wl_resource *resource, uint32_t role); static void setPanelBehaviorCallback(wl_client *client, wl_resource *resource, uint32_t flag); static void setSkipTaskbarCallback(wl_client *client, wl_resource *resource, uint32_t skip); static void setSkipSwitcherCallback(wl_client *client, wl_resource *resource, uint32_t skip); static void panelAutoHideHideCallback(wl_client *client, wl_resource *resource); static void panelAutoHideShowCallback(wl_client *client, wl_resource *resource); static void panelTakesFocusCallback(wl_client *client, wl_resource *resource, uint32_t takesFocus); void setPosition(const QPoint &globalPos); void setRole(uint32_t role); void setPanelBehavior(org_kde_plasma_surface_panel_behavior behavior); PlasmaShellSurfaceInterface *q_func() { return reinterpret_cast(q); } static const struct org_kde_plasma_surface_interface s_interface; }; PlasmaShellInterface::PlasmaShellInterface(Display *display, QObject *parent) : Global(new Private(this, display), parent) { } PlasmaShellInterface::~PlasmaShellInterface() = default; void PlasmaShellInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); wl_resource *shell = c->createResource(&org_kde_plasma_shell_interface, qMin(version, s_version), id); if (!shell) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(shell, &s_interface, this, nullptr); } void PlasmaShellInterface::Private::createSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface) { auto s = reinterpret_cast(wl_resource_get_user_data(resource)); s->createSurface(client, wl_resource_get_version(resource), id, SurfaceInterface::get(surface), resource); } void PlasmaShellInterface::Private::createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource) { auto it = std::find_if(surfaces.constBegin(), surfaces.constEnd(), [surface](PlasmaShellSurfaceInterface *s) { return surface == s->surface(); } ); if (it != surfaces.constEnd()) { wl_resource_post_error(surface->resource(), WL_DISPLAY_ERROR_INVALID_OBJECT, "PlasmaShellSurface already created"); return; } PlasmaShellSurfaceInterface *shellSurface = new PlasmaShellSurfaceInterface(q, surface, parentResource); surfaces << shellSurface; QObject::connect(shellSurface, &PlasmaShellSurfaceInterface::destroyed, q, [this, shellSurface] { surfaces.removeAll(shellSurface); } ); shellSurface->d->create(display->getConnection(client), version, id); emit q->surfaceCreated(shellSurface); } /********************************* * ShellSurfaceInterface *********************************/ PlasmaShellSurfaceInterface::Private::Private(PlasmaShellSurfaceInterface *q, PlasmaShellInterface *shell, SurfaceInterface *surface, wl_resource *parentResource) : Resource::Private(q, shell, parentResource, &org_kde_plasma_surface_interface, &s_interface) , surface(surface) { } #ifndef K_DOXYGEN const struct org_kde_plasma_surface_interface PlasmaShellSurfaceInterface::Private::s_interface = { resourceDestroyedCallback, setOutputCallback, setPositionCallback, setRoleCallback, setPanelBehaviorCallback, setSkipTaskbarCallback, panelAutoHideHideCallback, panelAutoHideShowCallback, panelTakesFocusCallback, setSkipSwitcherCallback }; #endif PlasmaShellSurfaceInterface::PlasmaShellSurfaceInterface(PlasmaShellInterface *shell, SurfaceInterface *parent, wl_resource *parentResource) : Resource(new Private(this, shell, parent, parentResource)) { } PlasmaShellSurfaceInterface::~PlasmaShellSurfaceInterface() = default; SurfaceInterface *PlasmaShellSurfaceInterface::surface() const { Q_D(); return d->surface; } PlasmaShellInterface *PlasmaShellSurfaceInterface::shell() const { Q_D(); return reinterpret_cast(d->global); } PlasmaShellSurfaceInterface::Private *PlasmaShellSurfaceInterface::d_func() const { return reinterpret_cast(d.data()); } void PlasmaShellSurfaceInterface::Private::setOutputCallback(wl_client *client, wl_resource *resource, wl_resource *output) { Q_UNUSED(client) Q_UNUSED(resource) Q_UNUSED(output) // TODO: implement } void PlasmaShellSurfaceInterface::Private::setPositionCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->setPosition(QPoint(x, y)); } void PlasmaShellSurfaceInterface::Private::setPosition(const QPoint &globalPos) { if (m_globalPos == globalPos && m_positionSet) { return; } m_positionSet = true; m_globalPos = globalPos; Q_Q(PlasmaShellSurfaceInterface); emit q->positionChanged(); } void PlasmaShellSurfaceInterface::Private::setRoleCallback(wl_client *client, wl_resource *resource, uint32_t role) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->setRole(role); } void PlasmaShellSurfaceInterface::Private::setRole(uint32_t role) { Role r = Role::Normal; switch (role) { case ORG_KDE_PLASMA_SURFACE_ROLE_DESKTOP: r = Role::Desktop; break; case ORG_KDE_PLASMA_SURFACE_ROLE_PANEL: r = Role::Panel; break; case ORG_KDE_PLASMA_SURFACE_ROLE_ONSCREENDISPLAY: r = Role::OnScreenDisplay; break; case ORG_KDE_PLASMA_SURFACE_ROLE_NOTIFICATION: r = Role::Notification; break; case ORG_KDE_PLASMA_SURFACE_ROLE_TOOLTIP: r = Role::ToolTip; break; case ORG_KDE_PLASMA_SURFACE_ROLE_CRITICALNOTIFICATION: r = Role::CriticalNotification; break; case ORG_KDE_PLASMA_SURFACE_ROLE_NORMAL: default: r = Role::Normal; break; } if (r == m_role) { return; } m_role = r; Q_Q(PlasmaShellSurfaceInterface); emit q->roleChanged(); } void PlasmaShellSurfaceInterface::Private::setPanelBehaviorCallback(wl_client *client, wl_resource *resource, uint32_t flag) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->setPanelBehavior(org_kde_plasma_surface_panel_behavior(flag)); } void PlasmaShellSurfaceInterface::Private::setSkipTaskbarCallback(wl_client *client, wl_resource *resource, uint32_t skip) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->m_skipTaskbar = (bool)skip; emit s->q_func()->skipTaskbarChanged(); } void PlasmaShellSurfaceInterface::Private::setSkipSwitcherCallback(wl_client *client, wl_resource *resource, uint32_t skip) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->m_skipSwitcher = (bool)skip; emit s->q_func()->skipSwitcherChanged(); } void PlasmaShellSurfaceInterface::Private::panelAutoHideHideCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); if (s->m_role != Role::Panel || (s->m_panelBehavior != PanelBehavior::AutoHide && s->m_panelBehavior != PanelBehavior::WindowsCanCover)) { wl_resource_post_error(s->resource, ORG_KDE_PLASMA_SURFACE_ERROR_PANEL_NOT_AUTO_HIDE, "Not an auto hide panel"); return; } emit s->q_func()->panelAutoHideHideRequested(); } void PlasmaShellSurfaceInterface::Private::panelAutoHideShowCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); if (s->m_role != Role::Panel || s->m_panelBehavior != PanelBehavior::AutoHide) { wl_resource_post_error(s->resource, ORG_KDE_PLASMA_SURFACE_ERROR_PANEL_NOT_AUTO_HIDE, "Not an auto hide panel"); return; } emit s->q_func()->panelAutoHideShowRequested(); } void PlasmaShellSurfaceInterface::Private::panelTakesFocusCallback(wl_client *client, wl_resource *resource, uint32_t takesFocus) { auto s = cast(resource); Q_ASSERT(client == *s->client); if (s->panelTakesFocus == takesFocus) { return; } s->panelTakesFocus = takesFocus; emit s->q_func()->panelTakesFocusChanged(); } void PlasmaShellSurfaceInterface::Private::setPanelBehavior(org_kde_plasma_surface_panel_behavior behavior) { PanelBehavior newBehavior = PanelBehavior::AlwaysVisible; switch (behavior) { case ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_AUTO_HIDE: newBehavior = PanelBehavior::AutoHide; break; case ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_WINDOWS_CAN_COVER: newBehavior = PanelBehavior::WindowsCanCover; break; case ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_WINDOWS_GO_BELOW: newBehavior = PanelBehavior::WindowsGoBelow; break; case ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_ALWAYS_VISIBLE: default: break; } if (m_panelBehavior == newBehavior) { return; } m_panelBehavior = newBehavior; Q_Q(PlasmaShellSurfaceInterface); emit q->panelBehaviorChanged(); } QPoint PlasmaShellSurfaceInterface::position() const { Q_D(); return d->m_globalPos; } PlasmaShellSurfaceInterface::Role PlasmaShellSurfaceInterface::role() const { Q_D(); return d->m_role; } bool PlasmaShellSurfaceInterface::isPositionSet() const { Q_D(); return d->m_positionSet; } PlasmaShellSurfaceInterface::PanelBehavior PlasmaShellSurfaceInterface::panelBehavior() const { Q_D(); return d->m_panelBehavior; } bool PlasmaShellSurfaceInterface::skipTaskbar() const { Q_D(); return d->m_skipTaskbar; } bool PlasmaShellSurfaceInterface::skipSwitcher() const { Q_D(); return d->m_skipSwitcher; } void PlasmaShellSurfaceInterface::hideAutoHidingPanel() { Q_D(); if (!d->resource) { return; } org_kde_plasma_surface_send_auto_hidden_panel_hidden(d->resource); } void PlasmaShellSurfaceInterface::showAutoHidingPanel() { Q_D(); if (!d->resource) { return; } org_kde_plasma_surface_send_auto_hidden_panel_shown(d->resource); } bool PlasmaShellSurfaceInterface::panelTakesFocus() const { Q_D(); return d->panelTakesFocus; } PlasmaShellSurfaceInterface *PlasmaShellSurfaceInterface::get(wl_resource *native) { return Private::get(native); } }