File indexing completed on 2024-11-10 04:57:29

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