From 72635101f02742c05d03b9af26d6fe03d41a0b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 9 Jul 2015 09:10:33 +0200 Subject: [PATCH] [wayland] Improve creation of KWayland::Server::PlasmaWindowInterface The creation of PlasmaWindowInterface is moved from WaylandServer into AbstractClient. This allows the sub classes to better control when to create/destroy the Client. For creation it's bound to becoming visible - that is Windows which are only created but never shown are not announced at all. For Client it's destroyed with the normal tear-down of a Client, for ShellClient it's destroyed on unmapped (which also means a new one will be created again in case of another mapping of the surface). As a side effect, this works around the problem that ShellClients do not yet get destroyed for QtWayland's menus (needs further investigation). --- abstract_client.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++++ abstract_client.h | 13 +++++ client.cpp | 7 ++- composite.cpp | 4 +- events.cpp | 1 + shell_client.cpp | 15 +++++- shell_client.h | 1 + wayland_server.cpp | 105 ------------------------------------- wayland_server.h | 4 +- 9 files changed, 163 insertions(+), 110 deletions(-) diff --git a/abstract_client.cpp b/abstract_client.cpp index 972377da40..f058c786c0 100644 --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -25,6 +25,11 @@ along with this program. If not, see . #endif #include "workspace.h" +#if HAVE_WAYLAND +#include "wayland_server.h" +#include +#endif + namespace KWin { @@ -509,4 +514,122 @@ bool AbstractClient::hasStrut() const return false; } +void AbstractClient::setupWindowManagementInterface() +{ +#if HAVE_WAYLAND + if (m_windowManagementInterface) { + // already setup + return; + } + if (!waylandServer() || !surface()) { + return; + } + if (!waylandServer()->windowManagement()) { + return; + } + using namespace KWayland::Server; + auto w = waylandServer()->windowManagement()->createWindow(this); + w->setTitle(caption()); + w->setVirtualDesktop(isOnAllDesktops() ? 0 : desktop() - 1); + w->setActive(isActive()); + w->setFullscreen(isFullScreen()); + w->setKeepAbove(keepAbove()); + w->setKeepBelow(keepBelow()); + w->setMaximized(maximizeMode() == KWin::MaximizeFull); + w->setMinimized(isMinimized()); + w->setOnAllDesktops(isOnAllDesktops()); + w->setDemandsAttention(isDemandingAttention()); + w->setCloseable(isCloseable()); + w->setMaximizeable(isMaximizable()); + w->setMinimizeable(isMinimizable()); + w->setFullscreenable(isFullScreenable()); + w->setThemedIconName(icon().name().isEmpty() ? QStringLiteral("xorg") : icon().name()); + connect(this, &AbstractClient::captionChanged, w, [w, this] { w->setTitle(caption()); }); + connect(this, &AbstractClient::desktopChanged, w, + [w, this] { + if (isOnAllDesktops()) { + w->setOnAllDesktops(true); + return; + } + w->setVirtualDesktop(desktop() - 1); + w->setOnAllDesktops(false); + } + ); + connect(this, &AbstractClient::activeChanged, w, [w, this] { w->setActive(isActive()); }); + connect(this, &AbstractClient::fullScreenChanged, w, [w, this] { w->setFullscreen(isFullScreen()); }); + connect(this, &AbstractClient::keepAboveChanged, w, &PlasmaWindowInterface::setKeepAbove); + connect(this, &AbstractClient::keepBelowChanged, w, &PlasmaWindowInterface::setKeepBelow); + connect(this, &AbstractClient::minimizedChanged, w, [w, this] { w->setMinimized(isMinimized()); }); + connect(this, static_cast(&AbstractClient::clientMaximizedStateChanged), w, + [w] (KWin::AbstractClient *c, MaximizeMode mode) { + Q_UNUSED(c); + w->setMaximized(mode == KWin::MaximizeFull); + } + ); + connect(this, &AbstractClient::demandsAttentionChanged, w, [w, this] { w->setDemandsAttention(isDemandingAttention()); }); + connect(this, &AbstractClient::iconChanged, w, + [w, this] { + const QIcon i = icon(); + w->setThemedIconName(i.name().isEmpty() ? QStringLiteral("xorg") : i.name()); + } + ); + connect(w, &PlasmaWindowInterface::closeRequested, this, [this] { closeWindow(); }); + connect(w, &PlasmaWindowInterface::virtualDesktopRequested, this, + [this] (quint32 desktop) { + workspace()->sendClientToDesktop(this, desktop + 1, true); + } + ); + connect(w, &PlasmaWindowInterface::fullscreenRequested, this, + [this] (bool set) { + setFullScreen(set, false); + } + ); + connect(w, &PlasmaWindowInterface::minimizedRequested, this, + [this] (bool set) { + if (set) { + minimize(); + } else { + unminimize(); + } + } + ); + connect(w, &PlasmaWindowInterface::maximizedRequested, this, + [this] (bool set) { + maximize(set ? MaximizeFull : MaximizeRestore); + } + ); + connect(w, &PlasmaWindowInterface::keepAboveRequested, this, + [this] (bool set) { + setKeepAbove(set); + } + ); + connect(w, &PlasmaWindowInterface::keepBelowRequested, this, + [this] (bool set) { + setKeepBelow(set); + } + ); + connect(w, &PlasmaWindowInterface::demandsAttentionRequested, this, + [this] (bool set) { + demandAttention(set); + } + ); + connect(w, &PlasmaWindowInterface::activeRequested, this, + [this] (bool set) { + if (set) { + workspace()->activateClient(this, true); + } + } + ); + m_windowManagementInterface = w; +#endif +} + +void AbstractClient::destroyWindowManagementInterface() +{ +#if HAVE_WAYLAND + delete m_windowManagementInterface; + m_windowManagementInterface = nullptr; +#endif +} + } diff --git a/abstract_client.h b/abstract_client.h index 8b2a2e7777..2e1a3b1e0e 100644 --- a/abstract_client.h +++ b/abstract_client.h @@ -26,6 +26,14 @@ along with this program. If not, see . #include +namespace KWayland +{ +namespace Server +{ +class PlasmaWindowInterface; +} +} + namespace KWin { @@ -430,6 +438,9 @@ protected: virtual void doSetSkipTaskbar(); virtual void doSetSkipPager(); + void setupWindowManagementInterface(); + void destroyWindowManagementInterface(); + void updateColorScheme(QString path); private: @@ -456,6 +467,8 @@ private: std::shared_ptr m_palette; static QHash> s_palettes; static std::shared_ptr s_defaultPalette; + + KWayland::Server::PlasmaWindowInterface *m_windowManagementInterface = nullptr; }; inline void AbstractClient::move(const QPoint& p, ForceGeometry_t force) diff --git a/client.cpp b/client.cpp index 98bc6f9751..acbe49249d 100644 --- a/client.cpp +++ b/client.cpp @@ -223,6 +223,7 @@ void Client::releaseWindow(bool on_shutdown) { assert(!deleting); deleting = true; + destroyWindowManagementInterface(); Deleted* del = NULL; if (!on_shutdown) { del = Deleted::create(this); @@ -293,6 +294,7 @@ void Client::destroyClient() { assert(!deleting); deleting = true; + destroyWindowManagementInterface(); Deleted* del = Deleted::create(this); if (moveResizeMode) emit clientFinishUserMovedResized(this); @@ -1824,6 +1826,7 @@ void Client::sendSyncRequest() if (!ready_for_painting) { // failed on initial pre-show request setReadyForPainting(); + setupWindowManagementInterface(); return; } // failed during resize @@ -2231,8 +2234,10 @@ void Client::setDecoratedClient(QPointer< Decoration::DecoratedClientImpl > clie void Client::addDamage(const QRegion &damage) { if (!ready_for_painting) { // avoid "setReadyForPainting()" function calling overhead - if (syncRequest.counter == XCB_NONE) // cannot detect complete redraw, consider done now + if (syncRequest.counter == XCB_NONE) { // cannot detect complete redraw, consider done now setReadyForPainting(); + setupWindowManagementInterface(); + } } Toplevel::addDamage(damage); } diff --git a/composite.cpp b/composite.cpp index 8371390613..a586ffdd0c 100644 --- a/composite.cpp +++ b/composite.cpp @@ -1024,8 +1024,10 @@ void Client::damageNotifyEvent() } if (!ready_for_painting) { // avoid "setReadyForPainting()" function calling overhead - if (syncRequest.counter == XCB_NONE) // cannot detect complete redraw, consider done now + if (syncRequest.counter == XCB_NONE) { // cannot detect complete redraw, consider done now setReadyForPainting(); + setupWindowManagementInterface(); + } } Toplevel::damageNotifyEvent(); diff --git a/events.cpp b/events.cpp index cdbcf65d60..1add8e0494 100644 --- a/events.cpp +++ b/events.cpp @@ -1547,6 +1547,7 @@ void Client::syncEvent(xcb_sync_alarm_notify_event_t* e) { if (e->alarm == syncRequest.alarm && e->counter_value.hi == syncRequest.value.hi && e->counter_value.lo == syncRequest.value.lo) { setReadyForPainting(); + setupWindowManagementInterface(); syncRequest.isPending = false; if (syncRequest.failsafeTimeout) syncRequest.failsafeTimeout->stop(); diff --git a/shell_client.cpp b/shell_client.cpp index 2ff3eaa660..9608f3b9c5 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -52,6 +52,7 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface) setupCompositing(); if (surface->surface()->buffer()) { setReadyForPainting(); + setupWindowManagementInterface(); m_unmapped = false; m_clientSize = surface->surface()->buffer()->size(); } else { @@ -211,12 +212,21 @@ void ShellClient::addDamage(const QRegion &damage) } setGeometry(QRect(position, m_clientSize)); } - m_unmapped = false; + markAsUnmapped(); setDepth(m_shellSurface->surface()->buffer()->hasAlphaChannel() ? 32 : 24); - setReadyForPainting(); Toplevel::addDamage(damage); } +void ShellClient::markAsUnmapped() +{ + if (!m_unmapped) { + return; + } + m_unmapped = false; + setReadyForPainting(); + setupWindowManagementInterface(); +} + void ShellClient::setGeometry(const QRect &rect) { if (geom == rect) { @@ -591,6 +601,7 @@ void ShellClient::unmap() { m_unmapped = true; ready_for_painting = false; + destroyWindowManagementInterface(); addWorkspaceRepaint(visibleRect()); workspace()->clientHidden(this); emit windowHidden(this); diff --git a/shell_client.h b/shell_client.h index 3ef084bb59..bf91c43728 100644 --- a/shell_client.h +++ b/shell_client.h @@ -127,6 +127,7 @@ private: void findInternalWindow(); void updateInternalWindowGeometry(); void updateIcon(); + void markAsUnmapped(); static void deleteClient(ShellClient *c); KWayland::Server::ShellSurfaceInterface *m_shellSurface; diff --git a/wayland_server.cpp b/wayland_server.cpp index 770950a9cc..9f414a725c 100644 --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -87,9 +87,6 @@ void WaylandServer::init(const QByteArray &socketName) }; if (Toplevel *t = ws->findToplevel(check)) { t->setSurface(surface); - if (Client *c = dynamic_cast(t)) { - announceClientToWindowManagement(c); - } } } ); @@ -201,111 +198,9 @@ void WaylandServer::initWorkspace() ); } ); - connect(workspace(), &Workspace::clientAdded, this, &WaylandServer::announceClientToWindowManagement); - connect(this, &WaylandServer::shellClientAdded, this, &WaylandServer::announceClientToWindowManagement); } } -void WaylandServer::announceClientToWindowManagement(AbstractClient *c) -{ - if (!c->surface()) { - return; - } - using namespace KWayland::Server; - auto w = m_windowManagement->createWindow(c); - w->setTitle(c->caption()); - w->setVirtualDesktop(c->isOnAllDesktops() ? 0 : c->desktop() - 1); - w->setActive(c->isActive()); - w->setFullscreen(c->isFullScreen()); - w->setKeepAbove(c->keepAbove()); - w->setKeepBelow(c->keepBelow()); - w->setMaximized(c->maximizeMode() == KWin::MaximizeFull); - w->setMinimized(c->isMinimized()); - w->setOnAllDesktops(c->isOnAllDesktops()); - w->setDemandsAttention(c->isDemandingAttention()); - w->setCloseable(c->isCloseable()); - w->setMaximizeable(c->isMaximizable()); - w->setMinimizeable(c->isMinimizable()); - w->setFullscreenable(c->isFullScreenable()); - w->setThemedIconName(c->icon().name().isEmpty() ? QStringLiteral("xorg") : c->icon().name()); - connect(c, &AbstractClient::captionChanged, w, [w, c] { w->setTitle(c->caption()); }); - connect(c, &AbstractClient::desktopChanged, w, - [w, c] { - if (c->isOnAllDesktops()) { - w->setOnAllDesktops(true); - return; - } - w->setVirtualDesktop(c->desktop() - 1); - w->setOnAllDesktops(false); - } - ); - connect(c, &AbstractClient::activeChanged, w, [w, c] { w->setActive(c->isActive()); }); - connect(c, &AbstractClient::fullScreenChanged, w, [w, c] { w->setFullscreen(c->isFullScreen()); }); - connect(c, &AbstractClient::keepAboveChanged, w, &PlasmaWindowInterface::setKeepAbove); - connect(c, &AbstractClient::keepBelowChanged, w, &PlasmaWindowInterface::setKeepBelow); - connect(c, &AbstractClient::minimizedChanged, w, [w, c] { w->setMinimized(c->isMinimized()); }); - connect(c, static_cast(&AbstractClient::clientMaximizedStateChanged), w, - [w] (KWin::AbstractClient *c, MaximizeMode mode) { - Q_UNUSED(c); - w->setMaximized(mode == KWin::MaximizeFull); - } - ); - connect(c, &AbstractClient::demandsAttentionChanged, w, [w, c] { w->setDemandsAttention(c->isDemandingAttention()); }); - connect(c, &AbstractClient::iconChanged, w, - [w, c] { - const QIcon icon = c->icon(); - w->setThemedIconName(icon.name().isEmpty() ? QStringLiteral("xorg") : icon.name()); - } - ); - connect(w, &PlasmaWindowInterface::closeRequested, c, [c] { c->closeWindow(); }); - connect(w, &PlasmaWindowInterface::virtualDesktopRequested, c, - [c] (quint32 desktop) { - workspace()->sendClientToDesktop(c, desktop + 1, true); - } - ); - connect(w, &PlasmaWindowInterface::fullscreenRequested, c, - [c] (bool set) { - c->setFullScreen(set, false); - } - ); - connect(w, &PlasmaWindowInterface::minimizedRequested, c, - [c] (bool set) { - if (set) { - c->minimize(); - } else { - c->unminimize(); - } - } - ); - connect(w, &PlasmaWindowInterface::maximizedRequested, c, - [c] (bool set) { - c->maximize(set ? MaximizeFull : MaximizeRestore); - } - ); - connect(w, &PlasmaWindowInterface::keepAboveRequested, c, - [c] (bool set) { - c->setKeepAbove(set); - } - ); - connect(w, &PlasmaWindowInterface::keepBelowRequested, c, - [c] (bool set) { - c->setKeepBelow(set); - } - ); - connect(w, &PlasmaWindowInterface::demandsAttentionRequested, c, - [c] (bool set) { - c->demandAttention(set); - } - ); - connect(w, &PlasmaWindowInterface::activeRequested, c, - [c] (bool set) { - if (set) { - workspace()->activateClient(c, true); - } - } - ); -} - void WaylandServer::initOutputs() { if (m_backend && m_backend->handlesOutputs()) { diff --git a/wayland_server.h b/wayland_server.h index 69d00d25fc..1081ff2e93 100644 --- a/wayland_server.h +++ b/wayland_server.h @@ -76,6 +76,9 @@ public: KWayland::Server::ShellInterface *shell() { return m_shell; } + KWayland::Server::PlasmaWindowManagementInterface *windowManagement() { + return m_windowManagement; + } QList clients() const { return m_clients; } @@ -138,7 +141,6 @@ Q_SIGNALS: private: void fakeDummyQtWindowInput(); quint16 createClientId(KWayland::Server::ClientConnection *c); - void announceClientToWindowManagement(AbstractClient *c); KWayland::Server::Display *m_display = nullptr; KWayland::Server::CompositorInterface *m_compositor = nullptr; KWayland::Server::SeatInterface *m_seat = nullptr;