File indexing completed on 2024-05-19 16:35:23

0001 /*
0002     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0003     SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 #include "plasmashell_interface.h"
0008 #include "display.h"
0009 #include "surface_interface.h"
0010 #include "utils.h"
0011 
0012 #include <qwayland-server-plasma-shell.h>
0013 
0014 namespace KWaylandServer
0015 {
0016 static const quint32 s_version = 8;
0017 static QList<PlasmaShellSurfaceInterface *> s_shellSurfaces;
0018 
0019 class PlasmaShellInterfacePrivate : public QtWaylandServer::org_kde_plasma_shell
0020 {
0021 public:
0022     PlasmaShellInterfacePrivate(PlasmaShellInterface *q, Display *display);
0023 
0024 private:
0025     void org_kde_plasma_shell_get_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface) override;
0026     PlasmaShellInterface *q;
0027 };
0028 
0029 PlasmaShellInterfacePrivate::PlasmaShellInterfacePrivate(PlasmaShellInterface *_q, Display *display)
0030     : QtWaylandServer::org_kde_plasma_shell(*display, s_version)
0031     , q(_q)
0032 {
0033 }
0034 
0035 class PlasmaShellSurfaceInterfacePrivate : public QtWaylandServer::org_kde_plasma_surface
0036 {
0037 public:
0038     PlasmaShellSurfaceInterfacePrivate(PlasmaShellSurfaceInterface *q, SurfaceInterface *surface, wl_resource *resource);
0039 
0040     QPointer<SurfaceInterface> surface;
0041     PlasmaShellSurfaceInterface *q;
0042     QPoint m_globalPos;
0043     PlasmaShellSurfaceInterface::Role m_role = PlasmaShellSurfaceInterface::Role::Normal;
0044     PlasmaShellSurfaceInterface::PanelBehavior m_panelBehavior = PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible;
0045     bool m_positionSet = false;
0046     bool m_skipTaskbar = false;
0047     bool m_skipSwitcher = false;
0048     bool m_panelTakesFocus = false;
0049     bool m_openUnderCursorRequested = false;
0050 
0051 private:
0052     void org_kde_plasma_surface_destroy_resource(Resource *resource) override;
0053     void org_kde_plasma_surface_destroy(Resource *resource) override;
0054     void org_kde_plasma_surface_set_output(Resource *resource, struct ::wl_resource *output) override;
0055     void org_kde_plasma_surface_set_position(Resource *resource, int32_t x, int32_t y) override;
0056     void org_kde_plasma_surface_set_role(Resource *resource, uint32_t role) override;
0057     void org_kde_plasma_surface_set_panel_behavior(Resource *resource, uint32_t flag) override;
0058     void org_kde_plasma_surface_set_skip_taskbar(Resource *resource, uint32_t skip) override;
0059     void org_kde_plasma_surface_panel_auto_hide_hide(Resource *resource) override;
0060     void org_kde_plasma_surface_panel_auto_hide_show(Resource *resource) override;
0061     void org_kde_plasma_surface_set_panel_takes_focus(Resource *resource, uint32_t takes_focus) override;
0062     void org_kde_plasma_surface_set_skip_switcher(Resource *resource, uint32_t skip) override;
0063     void org_kde_plasma_surface_open_under_cursor(Resource *resource) override;
0064 };
0065 
0066 PlasmaShellInterface::PlasmaShellInterface(Display *display, QObject *parent)
0067     : QObject(parent)
0068     , d(new PlasmaShellInterfacePrivate(this, display))
0069 {
0070 }
0071 
0072 PlasmaShellInterface::~PlasmaShellInterface() = default;
0073 
0074 void PlasmaShellInterfacePrivate::org_kde_plasma_shell_get_surface(QtWaylandServer::org_kde_plasma_shell::Resource *resource,
0075                                                                    uint32_t id,
0076                                                                    struct ::wl_resource *surface)
0077 {
0078     SurfaceInterface *s = SurfaceInterface::get(surface);
0079     if (!s) {
0080         wl_resource_post_error(resource->handle, 0, "Invalid  surface");
0081         return;
0082     }
0083 
0084     if (PlasmaShellSurfaceInterface::get(s)) {
0085         wl_resource_post_error(resource->handle, 0, "org_kde_plasma_shell_surface already exists");
0086         return;
0087     }
0088 
0089     wl_resource *shell_resource = wl_resource_create(resource->client(), &org_kde_plasma_surface_interface, resource->version(), id);
0090 
0091     auto shellSurface = new PlasmaShellSurfaceInterface(s, shell_resource);
0092     s_shellSurfaces.append(shellSurface);
0093 
0094     QObject::connect(shellSurface, &QObject::destroyed, [shellSurface]() {
0095         s_shellSurfaces.removeOne(shellSurface);
0096     });
0097 
0098     Q_EMIT q->surfaceCreated(shellSurface);
0099 }
0100 
0101 /*********************************
0102  * ShellSurfaceInterface
0103  *********************************/
0104 PlasmaShellSurfaceInterfacePrivate::PlasmaShellSurfaceInterfacePrivate(PlasmaShellSurfaceInterface *_q, SurfaceInterface *surface, wl_resource *resource)
0105     : QtWaylandServer::org_kde_plasma_surface(resource)
0106     , surface(surface)
0107     , q(_q)
0108 {
0109 }
0110 
0111 PlasmaShellSurfaceInterface::PlasmaShellSurfaceInterface(SurfaceInterface *surface, wl_resource *resource)
0112     : d(new PlasmaShellSurfaceInterfacePrivate(this, surface, resource))
0113 {
0114 }
0115 
0116 PlasmaShellSurfaceInterface::~PlasmaShellSurfaceInterface() = default;
0117 
0118 SurfaceInterface *PlasmaShellSurfaceInterface::surface() const
0119 {
0120     return d->surface;
0121 }
0122 
0123 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_destroy(Resource *resource)
0124 {
0125     wl_resource_destroy(resource->handle);
0126 }
0127 
0128 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_destroy_resource(Resource *resource)
0129 {
0130     delete q;
0131 }
0132 
0133 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_output(Resource *resource, struct ::wl_resource *output)
0134 {
0135     // TODO: implement
0136 }
0137 
0138 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_position(Resource *resource, int32_t x, int32_t y)
0139 {
0140     QPoint globalPos(x, y);
0141     if (m_globalPos == globalPos && m_positionSet) {
0142         return;
0143     }
0144     m_positionSet = true;
0145     m_globalPos = globalPos;
0146     Q_EMIT q->positionChanged();
0147 }
0148 
0149 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_open_under_cursor(Resource *resource)
0150 {
0151     if (surface && surface->buffer()) {
0152         wl_resource_post_error(resource->handle, -1, "open_under_cursor: surface has a buffer");
0153     }
0154     m_openUnderCursorRequested = true;
0155     Q_EMIT q->openUnderCursorRequested();
0156 }
0157 
0158 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_role(Resource *resource, uint32_t role)
0159 {
0160     PlasmaShellSurfaceInterface::Role r = PlasmaShellSurfaceInterface::Role::Normal;
0161     switch (role) {
0162     case role_desktop:
0163         r = PlasmaShellSurfaceInterface::Role::Desktop;
0164         break;
0165     case role_panel:
0166         r = PlasmaShellSurfaceInterface::Role::Panel;
0167         break;
0168     case role_onscreendisplay:
0169         r = PlasmaShellSurfaceInterface::Role::OnScreenDisplay;
0170         break;
0171     case role_notification:
0172         r = PlasmaShellSurfaceInterface::Role::Notification;
0173         break;
0174     case role_tooltip:
0175         r = PlasmaShellSurfaceInterface::Role::ToolTip;
0176         break;
0177     case role_criticalnotification:
0178         r = PlasmaShellSurfaceInterface::Role::CriticalNotification;
0179         break;
0180     case role_appletpopup:
0181         r = PlasmaShellSurfaceInterface::Role::AppletPopup;
0182         break;
0183     case role_normal:
0184     default:
0185         r = PlasmaShellSurfaceInterface::Role::Normal;
0186         break;
0187     }
0188     if (r == m_role) {
0189         return;
0190     }
0191     m_role = r;
0192     Q_EMIT q->roleChanged();
0193 }
0194 
0195 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_panel_behavior(Resource *resource, uint32_t flag)
0196 {
0197     PlasmaShellSurfaceInterface::PanelBehavior newBehavior = PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible;
0198     switch (flag) {
0199     case panel_behavior_auto_hide:
0200         newBehavior = PlasmaShellSurfaceInterface::PanelBehavior::AutoHide;
0201         break;
0202     case panel_behavior_windows_can_cover:
0203         newBehavior = PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover;
0204         break;
0205     case panel_behavior_windows_go_below:
0206         newBehavior = PlasmaShellSurfaceInterface::PanelBehavior::WindowsGoBelow;
0207         break;
0208     case panel_behavior_always_visible:
0209     default:
0210         break;
0211     }
0212     if (m_panelBehavior == newBehavior) {
0213         return;
0214     }
0215     m_panelBehavior = newBehavior;
0216     Q_EMIT q->panelBehaviorChanged();
0217 }
0218 
0219 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_skip_taskbar(Resource *resource, uint32_t skip)
0220 {
0221     m_skipTaskbar = (bool)skip;
0222     Q_EMIT q->skipTaskbarChanged();
0223 }
0224 
0225 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_skip_switcher(Resource *resource, uint32_t skip)
0226 {
0227     m_skipSwitcher = (bool)skip;
0228     Q_EMIT q->skipSwitcherChanged();
0229 }
0230 
0231 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_panel_auto_hide_hide(Resource *resource)
0232 {
0233     if (m_role != PlasmaShellSurfaceInterface::Role::Panel
0234         || (m_panelBehavior != PlasmaShellSurfaceInterface::PanelBehavior::AutoHide
0235             && m_panelBehavior != PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover)) {
0236         wl_resource_post_error(resource->handle, error_panel_not_auto_hide, "Not an auto hide panel");
0237         return;
0238     }
0239     Q_EMIT q->panelAutoHideHideRequested();
0240 }
0241 
0242 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_panel_auto_hide_show(Resource *resource)
0243 {
0244     if (m_role != PlasmaShellSurfaceInterface::Role::Panel || m_panelBehavior != PlasmaShellSurfaceInterface::PanelBehavior::AutoHide) {
0245         wl_resource_post_error(resource->handle, error_panel_not_auto_hide, "Not an auto hide panel");
0246         return;
0247     }
0248     Q_EMIT q->panelAutoHideShowRequested();
0249 }
0250 
0251 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_panel_takes_focus(Resource *resource, uint32_t takesFocus)
0252 {
0253     if (m_panelTakesFocus == takesFocus) {
0254         return;
0255     }
0256     m_panelTakesFocus = takesFocus;
0257     Q_EMIT q->panelTakesFocusChanged();
0258 }
0259 
0260 QPoint PlasmaShellSurfaceInterface::position() const
0261 {
0262     return d->m_globalPos;
0263 }
0264 
0265 PlasmaShellSurfaceInterface::Role PlasmaShellSurfaceInterface::role() const
0266 {
0267     return d->m_role;
0268 }
0269 
0270 bool PlasmaShellSurfaceInterface::isPositionSet() const
0271 {
0272     return d->m_positionSet;
0273 }
0274 
0275 bool PlasmaShellSurfaceInterface::wantsOpenUnderCursor() const
0276 {
0277     return d->m_openUnderCursorRequested;
0278 }
0279 
0280 PlasmaShellSurfaceInterface::PanelBehavior PlasmaShellSurfaceInterface::panelBehavior() const
0281 {
0282     return d->m_panelBehavior;
0283 }
0284 
0285 bool PlasmaShellSurfaceInterface::skipTaskbar() const
0286 {
0287     return d->m_skipTaskbar;
0288 }
0289 
0290 bool PlasmaShellSurfaceInterface::skipSwitcher() const
0291 {
0292     return d->m_skipSwitcher;
0293 }
0294 
0295 void PlasmaShellSurfaceInterface::hideAutoHidingPanel()
0296 {
0297     d->send_auto_hidden_panel_hidden();
0298 }
0299 
0300 void PlasmaShellSurfaceInterface::showAutoHidingPanel()
0301 {
0302     d->send_auto_hidden_panel_shown();
0303 }
0304 
0305 bool PlasmaShellSurfaceInterface::panelTakesFocus() const
0306 {
0307     return d->m_panelTakesFocus;
0308 }
0309 
0310 PlasmaShellSurfaceInterface *PlasmaShellSurfaceInterface::get(wl_resource *native)
0311 {
0312     if (auto surfacePrivate = resource_cast<PlasmaShellSurfaceInterfacePrivate *>(native)) {
0313         return surfacePrivate->q;
0314     }
0315     return nullptr;
0316 }
0317 
0318 PlasmaShellSurfaceInterface *PlasmaShellSurfaceInterface::get(SurfaceInterface *surface)
0319 {
0320     for (PlasmaShellSurfaceInterface *shellSurface : std::as_const(s_shellSurfaces)) {
0321         if (shellSurface->surface() == surface) {
0322             return shellSurface;
0323         }
0324     }
0325     return nullptr;
0326 }
0327 
0328 }