diff --git a/CMakeLists.txt b/CMakeLists.txt index e28632f712..7950808758 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,8 @@ set_package_properties(KF5DocTools PROPERTIES ) add_feature_info("KF5DocTools" KF5DocTools_FOUND "Enable building documentation") +find_package(KDecoration2 CONFIG REQUIRED) + if(${Qt5Gui_OPENGL_IMPLEMENTATION} STREQUAL "GL") find_package(OpenGL) set_package_properties(OpenGL PROPERTIES DESCRIPTION "The OpenGL libraries" @@ -313,7 +315,6 @@ set(kwin_KDEINIT_SRCS main.cpp options.cpp outline.cpp - decorations.cpp events.cpp killwindow.cpp geometrytip.cpp @@ -321,7 +322,6 @@ set(kwin_KDEINIT_SRCS shadow.cpp sm.cpp group.cpp - bridge.cpp manage.cpp overlaywindow.cpp activation.cpp @@ -342,7 +342,6 @@ set(kwin_KDEINIT_SRCS effects.cpp effectloader.cpp compositingprefs.cpp - paintredirector.cpp virtualdesktops.cpp xcbutils.cpp scripting/scripting.cpp @@ -354,6 +353,10 @@ set(kwin_KDEINIT_SRCS scripting/scripting_model.cpp scripting/dbuscall.cpp scripting/screenedgeitem.cpp + decorations/decoratedclient.cpp + decorations/decorationbridge.cpp + decorations/settings.cpp + decorations/decorationrenderer.cpp ) if(KWIN_BUILD_TABBOX) @@ -445,6 +448,8 @@ set(kwin_KDE_LIBS KF5::Service KF5::Plasma KF5::WindowSystem + KDecoration2::KDecoration + KDecoration2::KDecoration2Private ) set(kwin_XLIB_LIBS diff --git a/bridge.cpp b/bridge.cpp deleted file mode 100644 index 62ea04f6ec..0000000000 --- a/bridge.cpp +++ /dev/null @@ -1,380 +0,0 @@ -/******************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 2003 Lubos Lunak - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#include "bridge.h" - -#include "client.h" -#include "cursor.h" -#include "options.h" - -#include -#include "composite.h" -#include "paintredirector.h" -#include "virtualdesktops.h" -#include "workspace.h" - -#include - -namespace KWin -{ - -Bridge::Bridge(Client* cl) - : c(cl) -{ -} - -#define BRIDGE_HELPER( rettype, prototype, args1, args2, cst ) \ - rettype Bridge::prototype ( args1 ) cst \ - { \ - return c->prototype( args2 ); \ - } - -BRIDGE_HELPER(bool, isCloseable, , , const) -BRIDGE_HELPER(bool, isMaximizable, , , const) -BRIDGE_HELPER(Bridge::MaximizeMode, maximizeMode, , , const) -BRIDGE_HELPER(Bridge::QuickTileMode, quickTileMode, , , const) -BRIDGE_HELPER(bool, isMinimizable, , , const) -BRIDGE_HELPER(bool, providesContextHelp, , , const) -BRIDGE_HELPER(int, desktop, , , const) -BRIDGE_HELPER(bool, isModal, , , const) -BRIDGE_HELPER(bool, isShadeable, , , const) -BRIDGE_HELPER(bool, isShade, , , const) -BRIDGE_HELPER(bool, keepAbove, , , const) -BRIDGE_HELPER(bool, keepBelow, , , const) -BRIDGE_HELPER(bool, isMovable, , , const) -BRIDGE_HELPER(bool, isResizable, , , const) -BRIDGE_HELPER(void, processMousePressEvent, QMouseEvent* e, e,) -BRIDGE_HELPER(QRect, geometry, , , const) -BRIDGE_HELPER(void, closeWindow, , ,) -BRIDGE_HELPER(void, maximize, MaximizeMode m, m,) -BRIDGE_HELPER(void, minimize, , ,) -BRIDGE_HELPER(void, showContextHelp, , ,) -BRIDGE_HELPER(void, setDesktop, int desktop, desktop,) -BRIDGE_HELPER(QPalette, palette, , , const) - -bool Bridge::isActive() const -{ - return c->isActive() || (c->tabGroup() && c->tabGroup()->isActive()); -} - -void Bridge::setKeepAbove(bool set) -{ - if (c->keepAbove() != set) - workspace()->performWindowOperation(c, KeepAboveOp); -} - -void Bridge::setKeepBelow(bool set) -{ - if (c->keepBelow() != set) - workspace()->performWindowOperation(c, KeepBelowOp); -} - -NET::WindowType Bridge::windowType(unsigned long supported_types) const -{ - return c->windowType(false, supported_types); -} - -QIcon Bridge::icon() const -{ - return c->icon(); -} - -bool Bridge::isSetShade() const -{ - return c->shadeMode() != ShadeNone; -} - -void Bridge::showWindowMenu(const QPoint &p) -{ - workspace()->showWindowMenu(QRect(p,p), c); -} - -void Bridge::showWindowMenu(const QPoint &p, long id) -{ - Client *cc = clientForId(id); - if (!cc) - cc = c; - workspace()->showWindowMenu(QRect(p,p), cc); -} - -void Bridge::showWindowMenu(const QRect &p) -{ - workspace()->showWindowMenu(p, c); -} - -void Bridge::showApplicationMenu(const QPoint &p) -{ -#ifdef KWIN_BUILD_KAPPMENU - c->showApplicationMenu(p); -#else - Q_UNUSED(p) -#endif -} - -bool Bridge::menuAvailable() const -{ -#ifdef KWIN_BUILD_KAPPMENU - return c->menuAvailable(); -#else - return false; -#endif -} - -void Bridge::performWindowOperation(WindowOperation op) -{ - workspace()->performWindowOperation(c, op); -} - -void Bridge::setMask(const QRegion& r, int mode) -{ - c->setMask(r, mode); -} - -bool Bridge::isPreview() const -{ - return false; -} - -QRect Bridge::iconGeometry() const -{ - NETRect r = c->info->iconGeometry(); - return QRect(r.pos.x, r.pos.y, r.size.width, r.size.height); -} - -WId Bridge::windowId() const -{ - return c->window(); -} - -void Bridge::titlebarDblClickOperation() -{ - workspace()->performWindowOperation(c, options->operationTitlebarDblClick()); - c->dontMoveResize(); -} - -void Bridge::titlebarMouseWheelOperation(int delta) -{ - c->performMouseCommand(options->operationTitlebarMouseWheel(delta), Cursor::pos()); -} - -void Bridge::setShade(bool set) -{ - c->setShade(set ? ShadeNormal : ShadeNone); -} - -int Bridge::currentDesktop() const -{ - return VirtualDesktopManager::self()->current(); -} - -Qt::WindowFlags Bridge::initialWFlags() const -{ - return Qt::WindowDoesNotAcceptFocus; -} - -QRegion Bridge::unobscuredRegion(const QRegion& r) const -{ - QRegion reg(r); - const ToplevelList stacking_order = workspace()->stackingOrder(); - int pos = stacking_order.indexOf(c); - ++pos; - for (; pos < stacking_order.count(); ++pos) { - Client *client = qobject_cast(stacking_order[pos]); - if (!client) { - continue; - } - if (!client->isShown(true)) - continue; // these don't obscure the window - if (c->isOnAllDesktops()) { - if (!client->isOnCurrentDesktop()) - continue; - } else { - if (!client->isOnDesktop(c->desktop())) - continue; - } - /* the clients all have their mask-regions in local coords - so we have to translate them to a shared coord system - we choose ours */ - int dx = client->x() - c->x(); - int dy = client->y() - c->y(); - QRegion creg = client->mask(); - creg.translate(dx, dy); - reg -= creg; - if (reg.isEmpty()) { - // early out, we are completely obscured - break; - } - } - return reg; -} - -void Bridge::grabXServer(bool grab) -{ - if (grab) - KWin::grabXServer(); - else - KWin::ungrabXServer(); -} - -bool Bridge::compositingActive() const -{ - return Compositor::compositing(); -} - -QRect Bridge::transparentRect() const -{ - return c->transparentRect().translated(-c->decorationRect().topLeft()); -} - -void Bridge::update(const QRegion ®ion) -{ - if (c->paintRedirector) { - c->paintRedirector->addRepaint(region); - } -} - -//BEGIN TABBING - -Client *Bridge::clientForId(long id) const -{ - Client* client = reinterpret_cast(id); - if (!workspace()->hasClient(client)) { - qWarning() << "****** ARBITRARY CODE EXECUTION ATTEMPT DETECTED ******" << id; - return 0; - } - return client; -} - -int Bridge::tabCount() const -{ - if (c->tabGroup()) - return c->tabGroup()->count(); - return 1; -} - -long Bridge::tabId(int idx) const -{ - if (c->tabGroup()) - return tabIdOf(c->tabGroup()->clients().at(idx)); - return tabIdOf(c); -} - -QIcon Bridge::icon(int idx) const -{ - if (c->tabGroup()) { - return c->tabGroup()->clients().at(idx)->icon(); - } - return icon(); -} - -QString Bridge::caption() const -{ - return c->caption(true, true); -} - -QString Bridge::caption(int idx) const -{ - if (c->tabGroup()) - return c->tabGroup()->clients().at(idx)->caption(true, true); - return c->caption(true, true); -} - -long Bridge::currentTabId() const -{ - if (c->tabGroup()) - return tabIdOf(c->tabGroup()->current()); - return 0; -} - -void Bridge::setCurrentTab(long id) -{ - if (c->tabGroup()) - c->tabGroup()->setCurrent(clientForId(id)); -} - -void Bridge::tab_A_before_B(long A, long B) -{ - if (!B) { - if (c->tabGroup()) { - if (Client *a = clientForId(A)) - a->untab(); - } - return; - } - - if (Client *a = clientForId(A)) - if (Client *b = clientForId(B)) - if (a != b) - a->tabBefore(b, true); -} - -void Bridge::tab_A_behind_B(long A, long B) -{ - if (!B) { - if (c->tabGroup()) { - if (Client *a = clientForId(A)) - a->untab(); - } - return; - } - - if (Client *a = clientForId(A)) - if (Client *b = clientForId(B)) - if (a != b) - a->tabBehind(b, true); -} - - -void Bridge::untab(long id, const QRect& newGeom) -{ - if (c->tabGroup()) - if (Client* client = clientForId(id)) - if (client->untab(newGeom)) { - if (options->focusPolicyIsReasonable()) - workspace()->takeActivity(client, Workspace::ActivityFocus | Workspace::ActivityRaise); - workspace()->raiseClient(client); - } -} - -void Bridge::closeTab(long id) -{ - if (Client* client = clientForId(id)) - client->closeWindow(); -} - -void Bridge::closeTabGroup() -{ - if (c->tabGroup()) - c->tabGroup()->closeAll(); -} - -//END TABBING - -bool Bridge::isOnAllDesktopsAvailable() const -{ - return VirtualDesktopManager::self()->count() > 1; -} - -KDecoration::WindowOperation Bridge::buttonToWindowOperation(Qt::MouseButtons button) -{ - return c->mouseButtonToWindowOperation(button); -} - -} // namespace diff --git a/bridge.h b/bridge.h deleted file mode 100644 index dbed9d118b..0000000000 --- a/bridge.h +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 2003 Lubos Lunak - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#ifndef KWIN_BRIDGE_H -#define KWIN_BRIDGE_H - -#include - -namespace KWin -{ - -class Client; - -class Bridge : public KDecorationBridge -{ -public: - explicit Bridge(Client* cl); - virtual bool isActive() const override; - virtual bool isCloseable() const override; - virtual bool isMaximizable() const override; - virtual MaximizeMode maximizeMode() const override; - virtual QuickTileMode quickTileMode() const override; - virtual bool isMinimizable() const override; - virtual bool providesContextHelp() const override; - virtual int desktop() const override; - bool isOnAllDesktopsAvailable() const override; - virtual bool isModal() const override; - virtual bool isShadeable() const override; - virtual bool isShade() const override; - virtual bool isSetShade() const override; - virtual bool keepAbove() const override; - virtual bool keepBelow() const override; - virtual bool isMovable() const override; - virtual bool isResizable() const override; - virtual NET::WindowType windowType(unsigned long supported_types) const override; - virtual QIcon icon() const override; - virtual QString caption() const override; - virtual void processMousePressEvent(QMouseEvent*) override; - virtual void showWindowMenu(const QPoint &) override; - virtual void showWindowMenu(const QRect &) override; - virtual void showApplicationMenu(const QPoint &) override; - virtual bool menuAvailable() const override; - virtual void performWindowOperation(WindowOperation) override; - virtual void setMask(const QRegion&, int) override; - virtual bool isPreview() const override; - virtual QRect geometry() const override; - virtual QRect iconGeometry() const override; - virtual QRegion unobscuredRegion(const QRegion& r) const override; - virtual WId windowId() const override; - virtual void closeWindow() override; - virtual void maximize(MaximizeMode mode) override; - virtual void minimize() override; - virtual void showContextHelp() override; - virtual void setDesktop(int desktop) override; - virtual void titlebarDblClickOperation() override; - virtual void titlebarMouseWheelOperation(int delta) override; - virtual void setShade(bool set) override; - virtual void setKeepAbove(bool) override; - virtual void setKeepBelow(bool) override; - virtual int currentDesktop() const override; - virtual Qt::WindowFlags initialWFlags() const override; - virtual void grabXServer(bool grab) override; - - virtual bool compositingActive() const override; - virtual QRect transparentRect() const override; - - virtual void update(const QRegion ®ion) override; - virtual QPalette palette() const override; - - // Window tabbing - virtual QString caption(int idx) const override; - virtual void closeTab(long id) override; - virtual void closeTabGroup() override; - virtual long currentTabId() const override; - virtual QIcon icon(int idx) const override; - virtual void setCurrentTab(long id) override; - virtual void showWindowMenu(const QPoint &, long id) override; - virtual void tab_A_before_B(long A, long B) override; - virtual void tab_A_behind_B(long A, long B) override; - virtual int tabCount() const override; - virtual long tabId(int idx) const override; - virtual void untab(long id, const QRect& newGeom) override; - - virtual WindowOperation buttonToWindowOperation(Qt::MouseButtons button) override; - -private: - Client *clientForId(long id) const; - static inline long tabIdOf(Client *c) { - return reinterpret_cast(c); - } - Client* c; -}; - -} // namespace - -#endif diff --git a/client.cpp b/client.cpp index 68fe122126..63a02003e5 100644 --- a/client.cpp +++ b/client.cpp @@ -28,21 +28,22 @@ along with this program. If not, see . #include "appmenu.h" #endif #include "atoms.h" -#include "bridge.h" #include "client_machine.h" #include "composite.h" #include "cursor.h" -#include "decorations.h" #include "deleted.h" #include "focuschain.h" #include "group.h" -#include "paintredirector.h" #include "shadow.h" #ifdef KWIN_BUILD_TABBOX #include "tabbox.h" #endif #include "workspace.h" #include "screenedge.h" +#include "decorations/decorationbridge.h" +#include "decorations/decoratedclient.h" +#include +#include // KDE #include #include @@ -181,8 +182,7 @@ Client::Client() , m_client() , m_wrapper() , m_frame() - , decoration(NULL) - , bridge(new Bridge(this)) + , m_decoration(nullptr) , m_activityUpdatesBlocked(false) , m_blockedActivityUpdatesRequireTransients(false) , m_moveResizeGrabWindow() @@ -211,16 +211,7 @@ Client::Client() , block_geometry_updates(0) , pending_geometry_update(PendingGeometryNone) , shade_geometry_change(false) - , border_left(0) - , border_right(0) - , border_top(0) - , border_bottom(0) - , padding_left(0) - , padding_right(0) - , padding_top(0) - , padding_bottom(0) , sm_stacking_order(-1) - , paintRedirector(0) , m_firstInTabBox(false) , electricMaximizing(false) , activitiesDefined(false) @@ -306,12 +297,6 @@ Client::Client() connect(clientMachine(), &ClientMachine::localhostChanged, this, &Client::updateCaption); connect(options, &Options::condensedTitleChanged, this, &Client::updateCaption); - m_connections << connect(VirtualDesktopManager::self(), &VirtualDesktopManager::countChanged, [this]() { - if (decoration) { - decoration->onAllDesktopsAvailableChanged(); - } - }); - // SELI TODO: Initialize xsizehints?? } @@ -331,10 +316,9 @@ Client::~Client() assert(m_client == XCB_WINDOW_NONE); assert(m_wrapper == XCB_WINDOW_NONE); //assert( frameId() == None ); - assert(decoration == NULL); + Q_ASSERT(m_decoration == nullptr); assert(block_geometry_updates == 0); assert(!check_active_modal); - delete bridge; for (auto it = m_connections.constBegin(); it != m_connections.constEnd(); ++it) { disconnect(*it); } @@ -461,6 +445,7 @@ void Client::updateInputWindow() QRegion region; +#if 0 if (!noBorder()) { // This function is implemented as a slot to avoid breaking binary // compatibility @@ -468,6 +453,7 @@ void Client::updateInputWindow() Q_RETURN_ARG(QRegion, region), Q_ARG(KDecorationDefines::Region, KDecorationDefines::ExtendedBorderRegion)); } +#endif if (region.isEmpty()) { m_decoInputExtent.reset(); @@ -507,7 +493,7 @@ void Client::updateInputWindow() void Client::updateDecoration(bool check_workspace_pos, bool force) { if (!force && - ((decoration == NULL && noBorder()) || (decoration != NULL && !noBorder()))) + ((m_decoration == NULL && noBorder()) || (m_decoration != NULL && !noBorder()))) return; QRect oldgeom = geometry(); blockGeometryUpdates(true); @@ -521,55 +507,19 @@ void Client::updateDecoration(bool check_workspace_pos, bool force) checkWorkspacePosition(oldgeom); updateInputWindow(); blockGeometryUpdates(false); - if (!noBorder()) - decoration->show(); updateFrameExtents(); } void Client::createDecoration(const QRect& oldgeom) { - setMask(QRegion()); // Reset shape mask - if (decorationPlugin()->isDisabled()) { - decoration = NULL; - return; - } else { - decoration = decorationPlugin()->createDecoration(bridge); + m_decoration = Decoration::DecorationBridge::self()->createDecoration(this); + if (m_decoration) { + m_decoration->update(); } - connect(this, &Client::iconChanged, decoration, &KDecoration::iconChanged); - connect(this, &Client::shadeChanged, decoration, &KDecoration::shadeChanged); - connect(this, &Client::desktopChanged, decoration, &KDecoration::desktopChanged); - connect(this, &Client::captionChanged, decoration, &KDecoration::captionChanged); - connect(this, &Client::activeChanged, decoration, &KDecoration::activeChanged); - auto signalMaximizeChanged = static_cast(&Client::clientMaximizedStateChanged); - connect(this, signalMaximizeChanged, decoration, &KDecoration::maximizeChanged); - auto slotKeepAbove = static_cast(&KDecoration::keepAboveChanged); - connect(this, &Client::keepAboveChanged, decoration, slotKeepAbove); - auto slotKeepBelow = static_cast(&KDecoration::keepBelowChanged); - connect(this, &Client::keepBelowChanged, decoration, slotKeepBelow); -#ifdef KWIN_BUILD_KAPPMENU - connect(this, SIGNAL(showRequest()), decoration, SIGNAL(showRequest())); - connect(this, SIGNAL(appMenuAvailable()), decoration, SIGNAL(appMenuAvailable())); - connect(this, SIGNAL(appMenuUnavailable()), decoration, SIGNAL(appMenuUnavailable())); - connect(this, SIGNAL(menuHidden()), decoration, SIGNAL(menuHidden())); -#endif - // TODO: Check decoration's minimum size? - decoration->init(); - if (decoration->widget()) { - decoration->widget()->installEventFilter(this); - decoration->window()->setParent(m_frameWrapper.data()); - } else if (decoration->window()) { - decoration->window()->installEventFilter(this); - xcb_reparent_window(connection(), decoration->window()->winId(), frameId(), 0, 0); - } - decoration->window()->lower(); - decoration->borders(border_left, border_right, border_top, border_bottom); - padding_left = padding_right = padding_top = padding_bottom = 0; - decoration->padding(padding_left, padding_right, padding_top, padding_bottom); - Xcb::moveWindow(decoration->window()->winId(), -padding_left, -padding_top); + move(calculateGravitation(false)); plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); if (Compositor::compositing()) { - paintRedirector = PaintRedirector::create(this, decoration); discardWindowPixmap(); } emit geometryShapeChanged(this, oldgeom); @@ -578,13 +528,10 @@ void Client::createDecoration(const QRect& oldgeom) void Client::destroyDecoration() { QRect oldgeom = geometry(); - if (decoration != NULL) { - delete decoration; - decoration = NULL; - paintRedirector = NULL; + if (m_decoration) { + delete m_decoration; + m_decoration = nullptr; QPoint grav = calculateGravitation(true); - border_left = border_right = border_top = border_bottom = 0; - setMask(QRegion()); // Reset shape mask plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); move(grav); if (compositing()) @@ -598,6 +545,7 @@ void Client::destroyDecoration() bool Client::checkBorderSizes(bool also_resize) { +#if 0 if (decoration == NULL) return false; @@ -630,25 +578,28 @@ bool Client::checkBorderSizes(bool also_resize) QRect oldgeom = geometry(); plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); checkWorkspacePosition(oldgeom); +#endif return true; } void Client::triggerDecorationRepaint() { - if (decoration && decoration->widget()) - decoration->widget()->update(); + if (m_decoration) { + m_decoration->update(); + } } void Client::layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom, Client::CoordinateMode mode) const { - QRect r = decoration->rect(); - if (mode == WindowRelative) - r.translate(-padding_left, -padding_top); + if (!m_decoration) { + return; + } + QRect r = m_decoration->rect(); NETStrut strut = info->frameOverlap(); // Ignore the overlap strut when compositing is disabled - if (!compositing() || !decorationPlugin()->supportsFrameOverlap()) + if (!compositing()) strut.left = strut.top = strut.right = strut.bottom = 0; else if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1) { top = QRect(r.x(), r.y(), r.width(), r.height() / 3); @@ -658,20 +609,13 @@ void Client::layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect return; } - top = QRect(r.x(), r.y(), r.width(), padding_top + border_top + strut.top); - bottom = QRect(r.x(), r.y() + r.height() - padding_bottom - border_bottom - strut.bottom, - r.width(), padding_bottom + border_bottom + strut.bottom); + top = QRect(r.x(), r.y(), r.width(), borderTop() + strut.top); + bottom = QRect(r.x(), r.y() + r.height() - borderBottom() - strut.bottom, + r.width(), borderBottom() + strut.bottom); left = QRect(r.x(), r.y() + top.height(), - padding_left + border_left + strut.left, r.height() - top.height() - bottom.height()); - right = QRect(r.x() + r.width() - padding_right - border_right - strut.right, r.y() + top.height(), - padding_right + border_right + strut.right, r.height() - top.height() - bottom.height()); -} - -QRegion Client::decorationPendingRegion() const -{ - if (!paintRedirector) - return QRegion(); - return paintRedirector->scheduledRepaintRegion().translated(x() - padding_left, y() - padding_top); + borderLeft() + strut.left, r.height() - top.height() - bottom.height()); + right = QRect(r.x() + r.width() - borderRight() - strut.right, r.y() + top.height(), + borderRight() + strut.right, r.height() - top.height() - bottom.height()); } QRect Client::transparentRect() const @@ -681,7 +625,7 @@ QRect Client::transparentRect() const NETStrut strut = info->frameOverlap(); // Ignore the strut when compositing is disabled or the decoration doesn't support it - if (!compositing() || !decorationPlugin()->supportsFrameOverlap()) + if (!compositing()) strut.left = strut.top = strut.right = strut.bottom = 0; else if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1) return QRect(); @@ -733,10 +677,10 @@ void Client::detectNoBorder() void Client::updateFrameExtents() { NETStrut strut; - strut.left = border_left; - strut.right = border_right; - strut.top = border_top; - strut.bottom = border_bottom; + strut.left = borderLeft(); + strut.right = borderRight(); + strut.top = borderTop(); + strut.bottom = borderBottom(); info->setFrameExtents(strut); } @@ -756,32 +700,16 @@ void Client::detectGtkFrameExtents() */ void Client::resizeDecoration(const QSize& s) { - if (decoration == NULL) - return; - QSize newSize = s + QSize(padding_left + padding_right, padding_top + padding_bottom); - QSize oldSize = decoration->window()->size(); - decoration->resize(newSize); - if (oldSize == newSize) { - QResizeEvent e(newSize, oldSize); - QObject *receiver = nullptr; - if (decoration->widget()) { - receiver = decoration->widget(); - } else { - receiver = decoration->window(); - } - QApplication::sendEvent(receiver, &e); - } else if (paintRedirector) { // oldSize != newSize - paintRedirector->resizePixmaps(); - } else { - triggerDecorationRepaint(); + if (m_decoration) { + m_decoration->update(); + updateInputWindow(); } - Xcb::moveWindow(decoration->window()->winId(), -padding_left, -padding_top); updateInputWindow(); } bool Client::noBorder() const { - return decorationPlugin()->isDisabled() || noborder || isFullScreen(); + return noborder || isFullScreen(); } bool Client::userCanSetNoBorder() const @@ -870,59 +798,6 @@ void Client::updateInputShape() } } -void Client::setMask(const QRegion& reg, int mode) -{ - QRegion r = reg.translated(-padding_left, -padding_right) & QRect(0, 0, width(), height()); - if (_mask == r) - return; - _mask = r; - xcb_connection_t *c = connection(); - xcb_window_t shape_window = frameId(); - if (shape()) { - // The same way of applying a shape without strange intermediate states like above - if (!shape_helper_window.isValid()) - shape_helper_window.create(QRect(0, 0, 1, 1)); - shape_window = shape_helper_window; - } - if (_mask.isEmpty()) { - xcb_shape_mask(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, shape_window, 0, 0, XCB_PIXMAP_NONE); - } else { - const QVector< QRect > rects = _mask.rects(); - QVector< xcb_rectangle_t > xrects(rects.count()); - for (int i = 0; i < rects.count(); ++i) { - const QRect &rect = rects.at(i); - xcb_rectangle_t xrect; - xrect.x = rect.x(); - xrect.y = rect.y(); - xrect.width = rect.width(); - xrect.height = rect.height(); - xrects[i] = xrect; - } - xcb_shape_rectangles(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, mode, shape_window, - 0, 0, xrects.count(), xrects.constData()); - } - if (shape()) { - // The rest of the applying using a temporary window - xcb_rectangle_t rec = { 0, 0, static_cast(clientSize().width()), - static_cast(clientSize().height()) }; - xcb_shape_rectangles(c, XCB_SHAPE_SO_SUBTRACT, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, - shape_helper_window, clientPos().x(), clientPos().y(), 1, &rec); - xcb_shape_combine(c, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING, - shape_helper_window, clientPos().x(), clientPos().y(), window()); - xcb_shape_combine(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING, - frameId(), 0, 0, shape_helper_window); - } - emit geometryShapeChanged(this, geometry()); - updateShape(); -} - -QRegion Client::mask() const -{ - if (_mask.isEmpty()) - return QRegion(0, 0, width(), height()); - return _mask; -} - void Client::hideClient(bool hide) { if (hidden == hide) @@ -1066,8 +941,10 @@ void Client::setShade(ShadeMode mode) // Decorations may turn off some borders when shaded // this has to happen _before_ the tab alignment since it will restrict the minimum geometry +#if 0 if (decoration) decoration->borders(border_left, border_right, border_top, border_bottom); +#endif // Update states of all other windows in this group if (tabGroup()) @@ -1079,7 +956,7 @@ void Client::setShade(ShadeMode mode) return; // No real change in shaded state } - assert(decoration != NULL); // noborder windows can't be shaded + assert(m_decoration != NULL); // noborder windows can't be shaded GeometryUpdatesBlocker blocker(this); // TODO: All this unmapping, resizing etc. feels too much duplicated from elsewhere @@ -1089,7 +966,7 @@ void Client::setShade(ShadeMode mode) // Shade shade_geometry_change = true; QSize s(sizeForClientSize(QSize(clientSize()))); - s.setHeight(border_top + border_bottom); + s.setHeight(borderTop() + borderBottom()); m_wrapper.selectInput(ClientWinMask); // Avoid getting UnmapNotify m_wrapper.unmap(); m_client.unmap(); @@ -1314,8 +1191,6 @@ void Client::map() // for use in effects, but now we want to have access to the new pixmap if (compositing()) discardWindowPixmap(); - if (decoration != NULL) - decoration->show(); // Not really necessary, but let it know the state m_frame.map(); if (!isShade()) { m_wrapper.map(); @@ -1343,8 +1218,6 @@ void Client::unmap() m_client.unmap(); m_decoInputExtent.unmap(); m_wrapper.selectInput(ClientWinMask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY); - if (decoration != NULL) - decoration->hide(); // Not really necessary, but let it know the state exportMappingState(IconicState); } @@ -2093,8 +1966,10 @@ void Client::getMotifHints() motif_may_close = mclose; // Motif apps like to crash when they set this hint and WM closes them anyway if (isManaged()) updateDecoration(true); // Check if noborder state has changed +#if 0 if (decoration && closabilityChanged) emit decoration->decorationButtonsChanged(); +#endif } void Client::getIcons() @@ -2302,8 +2177,6 @@ void Client::updateCursor() if (c == m_cursor) return; m_cursor = c; - if (decoration != NULL) - decoration->window()->setCursor(m_cursor); xcb_cursor_t nativeCursor = Cursor::x11Cursor(m_cursor); m_frame.defineCursor(nativeCursor); if (m_decoInputExtent.isValid()) @@ -2326,8 +2199,29 @@ void Client::setBlockingCompositing(bool block) Client::Position Client::mousePosition(const QPoint& p) const { - if (decoration != NULL) - return decoration->mousePosition(p); + Q_UNUSED(p) + if (m_decoration) { + switch (m_decoration->windowFrameSection()) { + case Qt::BottomLeftSection: + return KDecorationDefines::PositionBottomLeft; + case Qt::BottomRightSection: + return KDecorationDefines::PositionBottomRight; + case Qt::BottomSection: + return KDecorationDefines::PositionBottom; + case Qt::LeftSection: + return KDecorationDefines::PositionLeft; + case Qt::RightSection: + return KDecorationDefines::PositionRight; + case Qt::TopSection: + return KDecorationDefines::PositionTop; + case Qt::TopLeftSection: + return KDecorationDefines::PositionTopLeft; + case Qt::TopRightSection: + return KDecorationDefines::PositionTopRight; + default: + return KDecorationDefines::PositionCenter; + } + } return PositionCenter; } @@ -2360,8 +2254,10 @@ void Client::updateAllowedActions(bool force) // ONLY if relevant features have changed (and the window didn't just get/loose moveresize for maximization state changes) const NET::Actions relevant = ~(NET::ActionMove|NET::ActionResize); +#if 0 if (decoration && (allowed_actions & relevant) != (old_allowed_actions & relevant)) emit decoration->decorationButtonsChanged(); +#endif } void Client::autoRaise() @@ -2433,21 +2329,13 @@ void Client::setSessionInteract(bool needed) QRect Client::decorationRect() const { - if (decoration) { - return decoration->rect().translated(-padding_left, -padding_top); - } else { - return QRect(0, 0, width(), height()); - } + return QRect(0, 0, width(), height()); } KDecorationDefines::Position Client::titlebarPosition() const { - Position titlePos = PositionCenter; // PositionTop is returned by the default implementation - // this will hint errors in the metaobject usage ;-) - if (decoration) - QMetaObject::invokeMethod(decoration, "titlebarPosition", Qt::DirectConnection, - Q_RETURN_ARG(KDecorationDefines::Position, titlePos)); - return titlePos; + // TODO: still needed, remove? + return PositionTop; } void Client::updateFirstInTabBox() @@ -2518,6 +2406,7 @@ NET::WindowType Client::windowType(bool direct, int supportedTypes) const bool Client::decorationHasAlpha() const { +#if 0 if (!decoration || !decorationPlugin()->hasAlpha()) { // either no decoration or decoration has alpha disabled return false; @@ -2528,6 +2417,8 @@ bool Client::decorationHasAlpha() const // decoration has alpha enabled and does not support alpha announcement return true; } +#endif + return true; } void Client::cancelFocusOutTimer() @@ -2616,6 +2507,26 @@ void Client::sendKeybordKeyEvent(uint32_t key, InputRedirection::KeyboardKeyStat xcb_test_fake_input(connection(), type, key + 8, XCB_TIME_CURRENT_TIME, frameId(), 0, 0, 0); } +#define BORDER(which) \ + int Client::border##which() const \ + { \ + return m_decoration ? m_decoration->border##which() : 0; \ + } + +BORDER(Bottom) +BORDER(Left) +BORDER(Right) +BORDER(Top) +#undef BORDER + +Decoration::DecoratedClientImpl *Client::decoratedClient() +{ + if (!m_decoration) { + return nullptr; + } + return static_cast(m_decoration->client()->handle()); +} + } // namespace #include "client.moc" diff --git a/client.h b/client.h index 3a15cbbfd4..1fe2a561b0 100644 --- a/client.h +++ b/client.h @@ -44,6 +44,11 @@ class KStartupInfoId; struct xcb_sync_alarm_notify_event_t; +namespace KDecoration2 +{ +class Decoration; +} + namespace KWin { namespace TabBox @@ -52,8 +57,10 @@ namespace TabBox class TabBoxClientImpl; } -class Bridge; -class PaintRedirector; +namespace Decoration +{ +class DecoratedClientImpl; +} /** @@ -286,7 +293,6 @@ class Client public: explicit Client(); xcb_window_t wrapperId() const; - xcb_window_t decorationId() const; xcb_window_t inputId() const { return m_decoInputExtent; } virtual xcb_window_t frameId() const override; @@ -329,7 +335,6 @@ public: QPoint inputPos() const { return input_offset; } // Inside of geometry() bool windowEvent(xcb_generic_event_t *e); - virtual bool eventFilter(QObject* o, QEvent* e); void syncEvent(xcb_sync_alarm_notify_event_t* e); NET::WindowType windowType(bool direct = false, int supported_types = 0) const; @@ -438,9 +443,6 @@ public: } void demandAttention(bool set = true); - void setMask(const QRegion& r, int mode = XCB_CLIP_ORDERING_UNSORTED); - QRegion mask() const; - void updateDecoration(bool check_workspace_pos, bool force = false); bool checkBorderSizes(bool also_resize); void triggerDecorationRepaint(); @@ -589,29 +591,18 @@ public: } // Decorations <-> Effects - PaintRedirector *decorationPaintRedirector() { - return paintRedirector; + KDecoration2::Decoration *decoration() { + return m_decoration; } - - int paddingLeft() const { - return padding_left; - } - int paddingRight() const { - return padding_right; - } - int paddingTop() const { - return padding_top; - } - int paddingBottom() const { - return padding_bottom; + const KDecoration2::Decoration *decoration() const { + return m_decoration; } + Decoration::DecoratedClientImpl *decoratedClient(); QRect decorationRect() const; QRect transparentRect() const; - QRegion decorationPendingRegion() const; - bool decorationHasAlpha() const; bool isClientSideDecorated() const; @@ -683,10 +674,6 @@ private Q_SLOTS: void shadeHover(); void shadeUnhover(); -private: - friend class Bridge; // FRAME - virtual void processMousePressEvent(QMouseEvent* e); - private: // Use Workspace::createClient() virtual ~Client(); ///< Use destroyClient() or releaseWindow() @@ -789,6 +776,10 @@ Q_SIGNALS: void clientSideDecoratedChanged(); private: + int borderLeft() const; + int borderRight() const; + int borderTop() const; + int borderBottom() const; void exportMappingState(int s); // ICCCM 4.1.3.1, 4.1.4, NETWM 2.5.1 bool isManaged() const; ///< Returns false if this client is not yet managed void updateAllowedActions(bool force = false); @@ -869,8 +860,7 @@ private: Xcb::Window m_frame; // wrapper around m_frame to use as a parent for the decoration QScopedPointer m_frameWrapper; - KDecoration* decoration; - Bridge* bridge; + KDecoration2::Decoration *m_decoration; int desk; QStringList activityList; int m_activityUpdatesBlocked; @@ -991,15 +981,11 @@ private: QTimer *timeout, *failsafeTimeout; bool isPending; } syncRequest; - int border_left, border_right, border_top, border_bottom; - int padding_left, padding_right, padding_top, padding_bottom; - QRegion _mask; static bool check_active_modal; ///< \see Client::checkActiveModal() QKeySequence _shortcut; int sm_stacking_order; friend struct ResetupRulesProcedure; friend class GeometryUpdatesBlocker; - PaintRedirector* paintRedirector; QSharedPointer m_tabBoxClient; bool m_firstInTabBox; @@ -1050,14 +1036,6 @@ inline xcb_window_t Client::wrapperId() const return m_wrapper; } -inline xcb_window_t Client::decorationId() const -{ - if (decoration) { - return decoration->window()->winId(); - } - return XCB_WINDOW_NONE; -} - inline bool Client::isClientSideDecorated() const { return m_clientSideDecorated; @@ -1223,7 +1201,7 @@ inline bool Client::isManaged() const inline QPoint Client::clientPos() const { - return QPoint(border_left, border_top); + return QPoint(borderLeft(), borderTop()); } inline QSize Client::clientSize() const diff --git a/composite.cpp b/composite.cpp index 1913d1f10e..5408077f44 100644 --- a/composite.cpp +++ b/composite.cpp @@ -1106,10 +1106,6 @@ bool Client::setupCompositing() return false; } updateVisibility(); // for internalKeep() - if (isManaged()) { - // only create the decoration when a client is managed - updateDecoration(true, true); - } return true; } @@ -1118,8 +1114,7 @@ void Client::finishCompositing(ReleaseReason releaseReason) Toplevel::finishCompositing(releaseReason); updateVisibility(); if (!deleting) { - // only recreate the decoration if we are not shutting down completely - updateDecoration(true, true); + triggerDecorationRepaint(); } // for safety in case KWin is just resizing the window s_haveResizeEffect = false; diff --git a/decorations.cpp b/decorations.cpp deleted file mode 100644 index 2e66f18a3b..0000000000 --- a/decorations.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/******************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 1999, 2000 Daniel M. Duley -Copyright (C) 2003 Lubos Lunak - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#include "decorations.h" -#include "config-kwin.h" -#include "client.h" -#include "workspace.h" -#include - -#include -#include -#include - -namespace KWin -{ - -KWIN_SINGLETON_FACTORY(DecorationPlugin) - -DecorationPlugin::DecorationPlugin(QObject *parent) - : QObject(parent) - , KDecorationPlugins(KSharedConfig::openConfig()) - , m_disabled(false) -{ - defaultPlugin = QStringLiteral("Oxygen"); -#ifdef KWIN_BUILD_DECORATIONS - loadPlugin(QString()); // load the plugin specified in cfg file - connect(factory(), &KDecorationFactory::recreateDecorations, this, &DecorationPlugin::recreateDecorations); - connect(this, &DecorationPlugin::compositingToggled, options, &KDecorationOptions::compositingChanged); -#else - setDisabled(true); -#endif -} - -DecorationPlugin::~DecorationPlugin() -{ - s_self = NULL; -} - -void DecorationPlugin::error(const QString &error_msg) -{ - qWarning("%s", QString(i18n("KWin: ") + error_msg).toLocal8Bit().data()); - - setDisabled(true); -} - -bool DecorationPlugin::provides(Requirement) -{ - return false; -} - -void DecorationPlugin::setDisabled(bool disabled) -{ - m_disabled = disabled; -} - -bool DecorationPlugin::isDisabled() const -{ - return m_disabled; -} - -bool DecorationPlugin::hasShadows() const -{ - if (m_disabled) { - return false; - } - return factory()->supports(AbilityProvidesShadow); -} - -bool DecorationPlugin::hasAlpha() const -{ - if (m_disabled) { - return false; - } - return factory()->supports(AbilityUsesAlphaChannel); -} - -bool DecorationPlugin::supportsAnnounceAlpha() const -{ - if (m_disabled) { - return false; - } - return factory()->supports(AbilityAnnounceAlphaChannel); -} - -bool DecorationPlugin::supportsTabbing() const -{ - if (m_disabled) { - return false; - } - return factory()->supports(AbilityTabbing); -} - -bool DecorationPlugin::supportsFrameOverlap() const -{ - if (m_disabled) { - return false; - } - return factory()->supports(AbilityExtendIntoClientArea); -} - -bool DecorationPlugin::supportsBlurBehind() const -{ - if (m_disabled) { - return false; - } - return factory()->supports(AbilityUsesBlurBehind); -} - -Qt::Corner DecorationPlugin::closeButtonCorner() -{ - if (m_disabled) { - return Qt::TopRightCorner; - } - return factory()->closeButtonCorner(); -} - -QString DecorationPlugin::supportInformation() -{ - if (m_disabled) { - return QStringLiteral("Decoration Plugin disabled\n"); - } - QString support; - support.append(QStringLiteral("Current Plugin: ")); - support.append(currentPlugin()); - support.append(QStringLiteral("\n")); - - support.append(QStringLiteral("Shadows: ")); - support.append(hasShadows() ? QStringLiteral("yes\n") : QStringLiteral("no\n")); - - support.append(QStringLiteral("Alpha: ")); - support.append(hasAlpha() ? QStringLiteral("yes\n") : QStringLiteral("no\n")); - - support.append(QStringLiteral("Announces Alpha: ")); - support.append(supportsAnnounceAlpha() ? QStringLiteral("yes\n") : QStringLiteral("no\n")); - - support.append(QStringLiteral("Tabbing: ")); - support.append(supportsTabbing() ? QStringLiteral("yes\n") : QStringLiteral("no\n")); - - support.append(QStringLiteral("Frame Overlap: ")); - support.append(supportsFrameOverlap() ? QStringLiteral("yes\n") : QStringLiteral("no\n")); - - support.append(QStringLiteral("Blur Behind: ")); - support.append(supportsBlurBehind() ? QStringLiteral("yes\n") : QStringLiteral("no\n")); - // TODO: Qt5 - read support information from Factory - return support; -} - -void DecorationPlugin::recreateDecorations() -{ - if (m_disabled) { - return; - } - // Decorations need to be recreated - workspace()->forEachClient([](Client *c) { - c->updateDecoration(true, true); - }); - // If the new decoration doesn't supports tabs then ungroup clients - if (!supportsTabbing()) { - workspace()->forEachClient([](Client *c) { - c->untab(); - }); - } -} - -} // namespace diff --git a/decorations.h b/decorations.h deleted file mode 100644 index 694c2ca37b..0000000000 --- a/decorations.h +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 1999, 2000 Daniel M. Duley -Copyright (C) 2003 Lubos Lunak - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#ifndef KWIN_PLUGINS_H -#define KWIN_PLUGINS_H - -#include -#include - -namespace KWin -{ - -class DecorationPlugin - : public QObject, public KDecorationPlugins -{ - Q_OBJECT -public: - virtual ~DecorationPlugin(); - virtual bool provides(Requirement); - /** - * @returns @c true if there is no decoration plugin. - **/ - bool isDisabled() const; - - bool hasShadows() const; - bool hasAlpha() const; - bool supportsAnnounceAlpha() const; - bool supportsTabbing() const; - bool supportsFrameOverlap() const; - bool supportsBlurBehind() const; - Qt::Corner closeButtonCorner(); - - QString supportInformation(); - -Q_SIGNALS: - void compositingToggled(); - -public Q_SLOTS: - void recreateDecorations(); -protected: - virtual void error(const QString& error_msg); -private: - void setDisabled(bool noDecoration); - bool m_disabled; - KWIN_SINGLETON(DecorationPlugin) -}; - -inline DecorationPlugin *decorationPlugin() { - return DecorationPlugin::self(); -} - -} // namespace - -#endif diff --git a/decorations/decoratedclient.cpp b/decorations/decoratedclient.cpp new file mode 100644 index 0000000000..d69177c113 --- /dev/null +++ b/decorations/decoratedclient.cpp @@ -0,0 +1,201 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "decoratedclient.h" +#include "decorationrenderer.h" +#include "client.h" +#include "composite.h" +#include "cursor.h" +#include "options.h" +#include "scene.h" +#include "workspace.h" + +#include +#include + +#include + +namespace KWin +{ +namespace Decoration +{ + +DecoratedClientImpl::DecoratedClientImpl(Client *client, KDecoration2::DecoratedClient *decoratedClient, KDecoration2::Decoration *decoration) + : QObject() + , DecoratedClientPrivate(decoratedClient, decoration) + , m_client(client) + , m_renderer(nullptr) +{ + createRenderer(); + connect(client, &Client::activeChanged, this, + [decoratedClient, client]() { + emit decoratedClient->activeChanged(client->isActive()); + } + ); + connect(client, &Client::geometryChanged, this, + [decoratedClient, client]() { + emit decoratedClient->widthChanged(client->clientSize().width()); + emit decoratedClient->heightChanged(client->clientSize().height()); + } + ); + connect(client, &Client::desktopChanged, this, + [decoratedClient, client]() { + emit decoratedClient->onAllDesktopsChanged(client->isOnAllDesktops()); + } + ); + connect(client, &Client::captionChanged, this, + [decoratedClient, client]() { + emit decoratedClient->captionChanged(client->caption()); + } + ); + connect(client, &Client::iconChanged, this, + [decoratedClient, client]() { + emit decoratedClient->iconChanged(client->icon()); + } + ); + connect(client, &Client::shadeChanged, this, + [decoratedClient, client]() { + // TODO: geometry is wrong + emit decoratedClient->shadedChanged(client->isShade()); + } + ); + connect(client, &Client::keepAboveChanged, decoratedClient, &KDecoration2::DecoratedClient::keepAboveChanged); + connect(client, &Client::keepBelowChanged, decoratedClient, &KDecoration2::DecoratedClient::keepBelowChanged); + // closeable, etc. + connect(Compositor::self(), &Compositor::compositingToggled, this, + [this, decoration]() { + delete m_renderer; + m_renderer = nullptr; + createRenderer(); + decoration->update(); + } + ); +} + +DecoratedClientImpl::~DecoratedClientImpl() = default; + +#define DELEGATE(type, name) \ + type DecoratedClientImpl::name() const \ + { \ + return m_client->name(); \ + } + +DELEGATE(QString, caption) +DELEGATE(bool, isActive) +DELEGATE(bool, isCloseable) +DELEGATE(bool, isMaximizable) +DELEGATE(bool, isMinimizable) +DELEGATE(bool, isModal) +DELEGATE(bool, isMovable) +DELEGATE(bool, isResizable) +DELEGATE(bool, isShadeable) +DELEGATE(bool, providesContextHelp) +DELEGATE(int, desktop) +DELEGATE(bool, isOnAllDesktops) +DELEGATE(QPalette, palette) +DELEGATE(QIcon, icon) + +#undef DELEGATE + +#define DELEGATE(type, name, clientName) \ + type DecoratedClientImpl::name() const \ + { \ + return m_client->clientName(); \ + } + +DELEGATE(bool, isKeepAbove, keepAbove) +DELEGATE(bool, isKeepBelow, keepBelow) +DELEGATE(bool, isShaded, isShade) +DELEGATE(WId, windowId, window) +DELEGATE(WId, decorationId, frameId) + +#undef DELEGATE + +#define DELEGATE(name, op) \ + void DecoratedClientImpl::name() \ + { \ + Workspace::self()->performWindowOperation(m_client, KDecorationDefines::op); \ + } + +DELEGATE(requestToggleShade, ShadeOp) +DELEGATE(requestToggleOnAllDesktops, OnAllDesktopsOp) +DELEGATE(requestToggleKeepAbove, KeepAboveOp) +DELEGATE(requestToggleKeepBelow, KeepBelowOp) + +#undef DELEGATE + +#define DELEGATE(name, clientName) \ + void DecoratedClientImpl::name() \ + { \ + m_client->clientName(); \ + } + +DELEGATE(requestContextHelp, showContextHelp) +DELEGATE(requestMinimize, minimize) +DELEGATE(requestClose, closeWindow) + +#undef DELEGATE + +void DecoratedClientImpl::requestShowWindowMenu() +{ + // TODO: add rect to requestShowWindowMenu + Workspace::self()->showWindowMenu(QRect(Cursor::pos(), Cursor::pos()), m_client); +} + +void DecoratedClientImpl::requestMaximize(Qt::MouseButtons buttons) +{ + Workspace::self()->performWindowOperation(m_client, options->operationMaxButtonClick(buttons)); +} + +int DecoratedClientImpl::width() const +{ + return m_client->clientSize().width(); +} + +int DecoratedClientImpl::height() const +{ + return m_client->clientSize().height(); +} + +bool DecoratedClientImpl::isMaximizedVertically() const +{ + return m_client->maximizeMode() & KDecorationDefines::MaximizeVertical; +} + +bool DecoratedClientImpl::isMaximized() const +{ + return isMaximizedHorizontally() && isMaximizedVertically(); +} + +bool DecoratedClientImpl::isMaximizedHorizontally() const +{ + return m_client->maximizeMode() & KDecorationDefines::MaximizeHorizontal; +} + +void DecoratedClientImpl::createRenderer() +{ + if (Compositor::self()->hasScene()) { + m_renderer = Compositor::self()->scene()->createDecorationRenderer(this); + } else { + m_renderer = new X11Renderer(this); + } +} + +} +} diff --git a/decorations/decoratedclient.h b/decorations/decoratedclient.h new file mode 100644 index 0000000000..482853c914 --- /dev/null +++ b/decorations/decoratedclient.h @@ -0,0 +1,97 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_DECORATED_CLIENT_H +#define KWIN_DECORATED_CLIENT_H + +#include + +#include + +namespace KWin +{ + +class Client; + +namespace Decoration +{ + +class Renderer; + +class DecoratedClientImpl : public QObject, public KDecoration2::DecoratedClientPrivate +{ + Q_OBJECT +public: + explicit DecoratedClientImpl(Client *client, KDecoration2::DecoratedClient *decoratedClient, KDecoration2::Decoration *decoration); + virtual ~DecoratedClientImpl(); + QString caption() const override; + WId decorationId() const override; + int desktop() const override; + int height() const override; + QIcon icon() const override; + bool isActive() const override; + bool isCloseable() const override; + bool isKeepAbove() const override; + bool isKeepBelow() const override; + bool isMaximizable() const override; + bool isMaximized() const override; + bool isMaximizedHorizontally() const override; + bool isMaximizedVertically() const override; + bool isMinimizable() const override; + bool isModal() const override; + bool isMovable() const override; + bool isOnAllDesktops() const override; + bool isResizable() const override; + bool isShadeable() const override; + bool isShaded() const override; + QPalette palette() const override; + bool providesContextHelp() const override; + int width() const override; + WId windowId() const override; + + void requestClose() override; + void requestContextHelp() override; + void requestMaximize(Qt::MouseButtons buttons) override; + void requestMinimize() override; + void requestShowWindowMenu() override; + void requestToggleKeepAbove() override; + void requestToggleKeepBelow() override; + void requestToggleOnAllDesktops() override; + void requestToggleShade() override; + + Client *client() { + return m_client; + } + Renderer *renderer() { + return m_renderer; + } + KDecoration2::DecoratedClient *decoratedClient() { + return KDecoration2::DecoratedClientPrivate::client(); + } + +private: + void createRenderer(); + Client *m_client; + Renderer *m_renderer; +}; + +} +} + +#endif diff --git a/decorations/decorationbridge.cpp b/decorations/decorationbridge.cpp new file mode 100644 index 0000000000..2d43954a92 --- /dev/null +++ b/decorations/decorationbridge.cpp @@ -0,0 +1,113 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "decorationbridge.h" +#include "decoratedclient.h" +#include "decorationrenderer.h" +#include "settings.h" +// KWin core +#include "client.h" +#include "composite.h" +#include "scene.h" + +// KDecoration +#include +#include +#include + +// Frameworks +#include +#include + +// Qt +#include +#include + +namespace KWin +{ +namespace Decoration +{ + +static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2"); + +DecorationBridge::DecorationBridge(QObject *parent) + : QObject(parent) + , KDecoration2::DecorationBridge() + , m_factory(nullptr) +{ +} + +DecorationBridge::~DecorationBridge() = default; + +DecorationBridge *DecorationBridge::self() +{ + return static_cast(KDecoration2::DecorationBridge::self()); +} + +void DecorationBridge::init() +{ + KDecoration2::DecorationSettings::self(this); + + // TODO: configurable plugin + const auto offers = KPluginTrader::self()->query(s_pluginName, + s_pluginName, + QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(QStringLiteral("org.kde.breeze"))); + if (offers.isEmpty()) { + qWarning() << "Could not locate decoration plugin"; + return; + } + qDebug() << "Trying to load decoration plugin: " << offers.first().libraryPath(); + KPluginLoader loader(offers.first().libraryPath()); + KPluginFactory *factory = loader.factory(); + if (!factory) { + qWarning() << "Error loading plugin:" << loader.errorString(); + } else { + m_factory = factory; + } +} + +KDecoration2::DecoratedClientPrivate *DecorationBridge::createClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration) +{ + return new DecoratedClientImpl(static_cast(decoration->parent()), client, decoration); +} + +KDecoration2::DecorationSettingsPrivate *DecorationBridge::settings(KDecoration2::DecorationSettings *parent) +{ + return new SettingsImpl(parent); +} + +void DecorationBridge::update(KDecoration2::Decoration *decoration, const QRect &geometry) +{ + // TODO: remove check once all compositors implement it + if (Renderer *renderer = static_cast(decoration->client()->handle())->renderer()) { + renderer->schedule(geometry); + } +} + +KDecoration2::Decoration *DecorationBridge::createDecoration(Client *client) +{ + if (!m_factory) { + return nullptr; + } + return m_factory->create(client); +} + + +} // Decoration +} // KWin diff --git a/decorations/decorationbridge.h b/decorations/decorationbridge.h new file mode 100644 index 0000000000..c203de2146 --- /dev/null +++ b/decorations/decorationbridge.h @@ -0,0 +1,58 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_DECORATION_BRIDGE_H +#define KWIN_DECORATION_BRIDGE_H + +#include + +#include + +class KPluginFactory; + +namespace KWin +{ + +class Client; + +namespace Decoration +{ + +class DecorationBridge : public QObject, public KDecoration2::DecorationBridge +{ + Q_OBJECT +public: + explicit DecorationBridge(QObject *parent); + virtual ~DecorationBridge(); + + void init(); + KDecoration2::Decoration *createDecoration(Client *client); + + KDecoration2::DecoratedClientPrivate *createClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration) override; + KDecoration2::DecorationSettingsPrivate *settings(KDecoration2::DecorationSettings *parent) override; + void update(KDecoration2::Decoration *decoration, const QRect &geometry) override; + + static DecorationBridge *self(); +private: + KPluginFactory *m_factory; +}; +} // Decoration +} // KWin + +#endif diff --git a/decorations/decorationrenderer.cpp b/decorations/decorationrenderer.cpp new file mode 100644 index 0000000000..7a451afacd --- /dev/null +++ b/decorations/decorationrenderer.cpp @@ -0,0 +1,134 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "decorationrenderer.h" +#include "decoratedclient.h" +#include "client.h" + +#include + +#include +#include + +#include +#include +#include + +namespace KWin +{ +namespace Decoration +{ + +Renderer::Renderer(DecoratedClientImpl *client) + : QObject(client) + , m_client(client) + , m_imageSizesDirty(true) +{ + auto markImageSizesDirty = [this]{ m_imageSizesDirty = true; }; + connect(client->decoration(), &KDecoration2::Decoration::bordersChanged, this, markImageSizesDirty); + connect(client->decoratedClient(), &KDecoration2::DecoratedClient::widthChanged, this, markImageSizesDirty); + connect(client->decoratedClient(), &KDecoration2::DecoratedClient::heightChanged, this, markImageSizesDirty); +} + +Renderer::~Renderer() = default; + +void Renderer::schedule(const QRect &rect) +{ + m_scheduled = m_scheduled.united(rect); + emit renderScheduled(rect); +} + +QRegion Renderer::getScheduled() +{ + QRegion region = m_scheduled; + m_scheduled = QRegion(); + return region; +} + +QImage Renderer::renderToImage(const QRect &geo) +{ + QImage image(geo.width(), geo.height(), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::transparent); + QPainter p(&image); + p.setRenderHint(QPainter::Antialiasing); + p.setWindow(geo); + p.setClipRect(geo); + client()->decoration()->paint(&p); + return image; +} + +X11Renderer::X11Renderer(DecoratedClientImpl *client) + : Renderer(client) + , m_scheduleTimer(new QTimer(this)) + , m_gc(XCB_NONE) +{ + // delay any rendering to end of event cycle to catch multiple updates per cycle + m_scheduleTimer->setSingleShot(true); + m_scheduleTimer->setInterval(0); + connect(m_scheduleTimer, &QTimer::timeout, this, &X11Renderer::render); + connect(this, &Renderer::renderScheduled, m_scheduleTimer, static_cast(&QTimer::start)); +} + +X11Renderer::~X11Renderer() +{ + if (m_gc != XCB_NONE) { + xcb_free_gc(connection(), m_gc); + } +} + +void X11Renderer::render() +{ + const QRegion scheduled = getScheduled(); + if (scheduled.isEmpty()) { + return; + } + xcb_connection_t *c = connection(); + if (m_gc == XCB_NONE) { + m_gc = xcb_generate_id(c); + xcb_create_gc(c, m_gc, client()->client()->frameId(), 0, nullptr); + } + + QRect left, top, right, bottom; + client()->client()->layoutDecorationRects(left, top, right, bottom, Client::DecorationRelative); + + const QRect geometry = scheduled.boundingRect(); + left = left.intersected(geometry); + top = top.intersected(geometry); + right = right.intersected(geometry); + bottom = bottom.intersected(geometry); + + auto renderPart = [this, c](const QRect &geo) { + if (geo.isNull()) { + return; + } + QImage image = renderToImage(geo); + xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, client()->client()->frameId(), m_gc, + image.width(), image.height(), geo.x(), geo.y(), 0, 24, image.byteCount(), image.constBits()); + }; + renderPart(left); + renderPart(top); + renderPart(right); + renderPart(bottom); + + xcb_flush(c); + resetImageSizesDirty(); +} + +} +} diff --git a/decorations/decorationrenderer.h b/decorations/decorationrenderer.h new file mode 100644 index 0000000000..8242a05095 --- /dev/null +++ b/decorations/decorationrenderer.h @@ -0,0 +1,94 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_DECORATION_RENDERER_H +#define KWIN_DECORATION_RENDERER_H + +#include +#include + +#include + +class QTimer; + +namespace KWin +{ + +namespace Decoration +{ + +class DecoratedClientImpl; + +class Renderer : public QObject +{ + Q_OBJECT +public: + virtual ~Renderer(); + + void schedule(const QRect &rect); + +Q_SIGNALS: + void renderScheduled(const QRect &geo); + +protected: + explicit Renderer(DecoratedClientImpl *client); + /** + * @returns the scheduled paint region and resets + **/ + QRegion getScheduled(); + + virtual void render() = 0; + + DecoratedClientImpl *client() { + return m_client; + } + + bool areImageSizesDirty() const { + return m_imageSizesDirty; + } + void resetImageSizesDirty() { + m_imageSizesDirty = false; + } + QImage renderToImage(const QRect &geo); + +private: + DecoratedClientImpl *m_client; + QRegion m_scheduled; + bool m_imageSizesDirty; +}; + +class X11Renderer : public Renderer +{ + Q_OBJECT +public: + explicit X11Renderer(DecoratedClientImpl *client); + virtual ~X11Renderer(); + +protected: + void render() override; + +private: + QTimer *m_scheduleTimer; + xcb_gcontext_t m_gc; +}; + +} +} + +#endif diff --git a/decorations/settings.cpp b/decorations/settings.cpp new file mode 100644 index 0000000000..520e9a0ba4 --- /dev/null +++ b/decorations/settings.cpp @@ -0,0 +1,77 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "settings.h" +// KWin +#include "composite.h" +#include "virtualdesktops.h" + +#include + +namespace KWin +{ +namespace Decoration +{ +SettingsImpl::SettingsImpl(KDecoration2::DecorationSettings *parent) + : QObject() + , DecorationSettingsPrivate(parent) +{ + connect(Compositor::self(), &Compositor::compositingToggled, + parent, &KDecoration2::DecorationSettings::alphaChannelSupportedChanged); + connect(VirtualDesktopManager::self(), &VirtualDesktopManager::countChanged, this, + [parent](uint previous, uint current) { + if (previous != 1 && current != 1) { + return; + } + emit parent->onAllDesktopsAvailableChanged(current > 1); + } + ); +} + +SettingsImpl::~SettingsImpl() = default; + +bool SettingsImpl::isAlphaChannelSupported() const +{ + return Compositor::self()->compositing(); +} + +bool SettingsImpl::isOnAllDesktopsAvailable() const +{ + return VirtualDesktopManager::self()->count() > 1; +} + +QList< KDecoration2::DecorationButtonType > SettingsImpl::decorationButtonsLeft() const +{ + return QList({ + KDecoration2::DecorationButtonType::Menu, + KDecoration2::DecorationButtonType::OnAllDesktops + }); +} + +QList< KDecoration2::DecorationButtonType > SettingsImpl::decorationButtonsRight() const +{ + return QList({ + KDecoration2::DecorationButtonType::Minimize, + KDecoration2::DecorationButtonType::Maximize, + KDecoration2::DecorationButtonType::Close + }); +} + +} +} diff --git a/decorations/settings.h b/decorations/settings.h new file mode 100644 index 0000000000..51c0604f82 --- /dev/null +++ b/decorations/settings.h @@ -0,0 +1,46 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_DECORATION_SETTINGS_H +#define KWIN_DECORATION_SETTINGS_H + +#include + +#include + +namespace KWin +{ +namespace Decoration +{ + +class SettingsImpl : public QObject, public KDecoration2::DecorationSettingsPrivate +{ + Q_OBJECT +public: + explicit SettingsImpl(KDecoration2::DecorationSettings *parent); + virtual ~SettingsImpl(); + bool isAlphaChannelSupported() const override; + bool isOnAllDesktopsAvailable() const override; + QList< KDecoration2::DecorationButtonType > decorationButtonsLeft() const override; + QList< KDecoration2::DecorationButtonType > decorationButtonsRight() const override; +}; +} // Decoration +} // KWin + +#endif diff --git a/deleted.cpp b/deleted.cpp index a65aa64808..a092ccb71e 100644 --- a/deleted.cpp +++ b/deleted.cpp @@ -23,7 +23,6 @@ along with this program. If not, see . #include "workspace.h" #include "client.h" #include "netinfo.h" -#include "paintredirector.h" #include "shadow.h" #include @@ -43,7 +42,6 @@ Deleted::Deleted() , m_layer(UnknownLayer) , m_minimized(false) , m_modal(false) - , m_paintRedirector(NULL) , m_wasClient(false) { } @@ -88,21 +86,18 @@ void Deleted::copyToDeleted(Toplevel* c) if (client) { m_wasClient = true; no_border = client->noBorder(); +#if 0 padding_left = client->paddingLeft(); padding_right = client->paddingRight(); padding_bottom = client->paddingBottom(); padding_top = client->paddingTop(); +#endif if (!no_border) { client->layoutDecorationRects(decoration_left, decoration_top, decoration_right, decoration_bottom, Client::WindowRelative); - if (PaintRedirector *redirector = client->decorationPaintRedirector()) { - redirector->ensurePixmapsPainted(); - redirector->reparent(this); - m_paintRedirector = redirector; - } } m_minimized = client->isMinimized(); m_modal = client->isModal(); diff --git a/deleted.h b/deleted.h index acaebe8e6b..79b631100e 100644 --- a/deleted.h +++ b/deleted.h @@ -25,7 +25,6 @@ along with this program. If not, see . namespace KWin { -class PaintRedirector; class Deleted : public Toplevel @@ -64,9 +63,6 @@ public: return m_mainClients; } NET::WindowType windowType(bool direct = false, int supported_types = 0) const; - PaintRedirector *decorationPaintRedirector() { - return m_paintRedirector; - } bool wasClient() const { return m_wasClient; } @@ -97,7 +93,6 @@ private: bool m_minimized; bool m_modal; ClientList m_mainClients; - PaintRedirector *m_paintRedirector; bool m_wasClient; }; diff --git a/effects.cpp b/effects.cpp index 8680023201..bc3c0be732 100644 --- a/effects.cpp +++ b/effects.cpp @@ -26,7 +26,6 @@ along with this program. If not, see . #ifdef KWIN_BUILD_ACTIVITIES #include "activities.h" #endif -#include "decorations.h" #include "deleted.h" #include "client.h" #include "cursor.h" @@ -492,17 +491,17 @@ void EffectsHandlerImpl::buildQuads(EffectWindow* w, WindowQuadList& quadList) bool EffectsHandlerImpl::hasDecorationShadows() const { - return decorationPlugin()->hasShadows(); + return false; } bool EffectsHandlerImpl::decorationsHaveAlpha() const { - return decorationPlugin()->hasAlpha(); + return true; } bool EffectsHandlerImpl::decorationSupportsBlurBehind() const { - return decorationPlugin()->supportsBlurBehind(); + return true; } // start another painting pass @@ -1441,7 +1440,7 @@ QVariant EffectsHandlerImpl::kwinOption(KWinOption kwopt) { switch (kwopt) { case CloseButtonCorner: - return decorationPlugin()->closeButtonCorner(); + return Qt::TopRightCorner; #ifdef KWIN_BUILD_SCREENEDGES case SwitchDesktopOnScreenEdge: return ScreenEdges::self()->isDesktopSwitching(); diff --git a/events.cpp b/events.cpp index 7736e614e1..63dddddd75 100644 --- a/events.cpp +++ b/events.cpp @@ -27,7 +27,6 @@ along with this program. If not, see . #include "client.h" #include "cursor.h" -#include "decorations.h" #include "focuschain.h" #include "netinfo.h" #include "workspace.h" @@ -47,6 +46,8 @@ along with this program. If not, see . #include "screens.h" #include "xcbutils.h" +#include + #include #include #include @@ -312,25 +313,8 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e) } } if (movingClient) { - if (eventType == XCB_BUTTON_PRESS || eventType == XCB_BUTTON_RELEASE) { - Client *c = movingClient; + if (eventType == XCB_BUTTON_PRESS || eventType == XCB_BUTTON_RELEASE || eventType == XCB_MOTION_NOTIFY) { if (movingClient->moveResizeGrabWindow() == reinterpret_cast(e)->event && movingClient->windowEvent(e)) { - // we need to pass the button release event to the decoration, otherwise Qt still thinks the button is pressed. - if (eventType == XCB_BUTTON_RELEASE && c->decorationId() != XCB_WINDOW_NONE) { - // the event is for the moveResizeGrabWindow and Qt doesn't forward that to the decoration - // so we need to send the event to the decoration ourselves - // TODO check whether m_moveResizeWindow can be offscreen and XAllowEvents be sufficient here - xcb_button_release_event_t event = *(reinterpret_cast(e)); - event.event = c->decorationId(); - event.child = XCB_WINDOW_NONE; - event.event_x = event.root_x - c->x() + c->paddingLeft(); - event.event_y = event.root_y - c->y() + c->paddingTop(); - xcb_send_event(connection(), false, c->decorationId(), XCB_EVENT_MASK_BUTTON_RELEASE, reinterpret_cast(&event)); - } - return true; - } - } else if (eventType == XCB_MOTION_NOTIFY) { - if (movingClient->moveResizeGrabWindow() == reinterpret_cast(e)->event && movingClient->windowEvent(e)) { return true; } } @@ -686,6 +670,14 @@ bool Client::windowEvent(xcb_generic_event_t *e) case XCB_CLIENT_MESSAGE: clientMessageEvent(reinterpret_cast(e)); break; + case XCB_EXPOSE: { + xcb_expose_event_t *event = reinterpret_cast(e); + if (event->window == frameId() && !Compositor::self()->isActive()) { + // TODO: only repaint required areas + triggerDecorationRepaint(); + } + break; + } default: if (eventType == Xcb::Extensions::self()->shapeNotifyEvent() && reinterpret_cast(e)->affected_window == window()) { detectShape(window()); // workaround for #19644 @@ -1036,65 +1028,6 @@ void Client::updateMouseGrab() } } -// Qt propagates mouse events up the widget hierachy, which means events -// for the decoration window cannot be (easily) intercepted as X11 events -bool Client::eventFilter(QObject* o, QEvent* e) -{ - if (decoration == NULL - || (o != decoration->widget() && o != decoration->window())) - return false; - if (e->type() == QEvent::MouseButtonPress && decoration->widget()) { - QMouseEvent* ev = static_cast< QMouseEvent* >(e); - return buttonPressEvent(decorationId(), qtToX11Button(ev->button()), qtToX11State(ev->buttons(), ev->modifiers()), - ev->x(), ev->y(), ev->globalX(), ev->globalY()); - } - if (e->type() == QEvent::MouseButtonRelease) { - QMouseEvent* ev = static_cast< QMouseEvent* >(e); - return buttonReleaseEvent(decorationId(), qtToX11Button(ev->button()), qtToX11State(ev->buttons(), ev->modifiers()), - ev->x(), ev->y(), ev->globalX(), ev->globalY()); - } - if (e->type() == QEvent::MouseMove) { // FRAME i fake z enter/leave? - QMouseEvent* ev = static_cast< QMouseEvent* >(e); - return motionNotifyEvent(decorationId(), qtToX11State(ev->buttons(), ev->modifiers()), - ev->x(), ev->y(), ev->globalX(), ev->globalY()); - } - if (e->type() == QEvent::Wheel) { - QWheelEvent* ev = static_cast< QWheelEvent* >(e); - bool r = buttonPressEvent(decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State(ev->buttons(), ev->modifiers()), - ev->x(), ev->y(), ev->globalX(), ev->globalY()); - r = r || buttonReleaseEvent(decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State(ev->buttons(), ev->modifiers()), - ev->x(), ev->y(), ev->globalX(), ev->globalY()); - return r; - } - if (e->type() == QEvent::Resize && decoration->widget()) { - QResizeEvent* ev = static_cast< QResizeEvent* >(e); - // Filter out resize events that inform about size different than frame size. - // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync. - // These events only seem to be delayed events from initial resizing before show() was called - // on the decoration widget. - if (ev->size() != (size() + QSize(padding_left + padding_right, padding_top + padding_bottom))) - return true; - // HACK: Avoid decoration redraw delays. On resize Qt sets WA_WStateConfigPending - // which delays all painting until a matching ConfigureNotify event comes. - // But this process itself is the window manager, so it's not needed - // to wait for that event, the geometry is known. - // Note that if Qt in the future changes how this flag is handled and what it - // triggers then this may potentionally break things. See mainly QETWidget::translateConfigEvent(). - decoration->widget()->setAttribute(Qt::WA_WState_ConfigPending, false); - decoration->widget()->update(); - return false; - } - if (e->type() == QEvent::ZOrderChange) { - // when the user actions menu is closed by clicking on the window decoration (which is not unlikely) - // Qt will raise the decoration window and thus the decoration window is above the actual Client - // see QWidgetWindow::handleMouseEvent (qtbase/src/widgets/kernel/qwidgetwindow.cpp) - // when this happens also a ZOrderChange event is sent, we intercept all of them and make sure that - // the window is lowest in stack again. - Xcb::lowerWindow(decorationId()); - } - return false; -} - static bool modKeyDown(int state) { const uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ? KKeyServer::modXMeta() : KKeyServer::modXAlt(); @@ -1111,7 +1044,7 @@ bool Client::buttonPressEvent(xcb_window_t w, int button, int state, int x, int return true; } - if (w == wrapperId() || w == frameId() || w == decorationId() || w == inputId()) { + if (w == wrapperId() || w == frameId() || w == inputId()) { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace updateUserTime(time); workspace()->setWasUserInteraction(); @@ -1189,16 +1122,22 @@ bool Client::buttonPressEvent(xcb_window_t w, int button, int state, int x, int return true; } if (w == inputId()) { - x = x_root - geometry().x() + padding_left; - y = y_root - geometry().y() + padding_top; + x = x_root - geometry().x(); + y = y_root - geometry().y(); // New API processes core events FIRST and only passes unused ones to the decoration return processDecorationButtonPress(button, state, x, y, x_root, y_root, true); } - if (w == decorationId()) { - return false; + if (w == frameId() && m_decoration) { + qDebug() << "Button press on frame"; + QMouseEvent event(QEvent::MouseButtonPress, QPointF(x, y), QPointF(x_root, y_root), + x11ToQtMouseButton(button), x11ToQtMouseButtons(state), x11ToQtKeyboardModifiers(state)); + event.setAccepted(false); + QCoreApplication::sendEvent(m_decoration, &event); + if (!event.isAccepted()) { + processDecorationButtonPress(button, state, x, y, x_root, y_root); + } + return true; } - if (w == frameId()) - processDecorationButtonPress(button, state, x, y, x_root, y_root); return true; } @@ -1225,7 +1164,7 @@ bool Client::processDecorationButtonPress(int button, int /*state*/, int x, int && com != Options::MouseDragTab) { mode = mousePosition(QPoint(x, y)); buttonDown = true; - moveOffset = QPoint(x - padding_left, y - padding_top); + moveOffset = QPoint(x/* - padding_left*/, y/* - padding_top*/); invertedMoveOffset = rect().bottomRight() - moveOffset; unrestrictedMoveResize = false; startDelayedMoveResize(); @@ -1246,40 +1185,19 @@ bool Client::processDecorationButtonPress(int button, int /*state*/, int x, int com == Options::MouseNothing); } -// called from decoration -void Client::processMousePressEvent(QMouseEvent* e) -{ - if (e->type() != QEvent::MouseButtonPress) { - qWarning() << "processMousePressEvent()" ; - return; - } - int button; - switch(e->button()) { - case Qt::LeftButton: - button = XCB_BUTTON_INDEX_1; - break; - case Qt::MidButton: - button = XCB_BUTTON_INDEX_2; - break; - case Qt::RightButton: - button = XCB_BUTTON_INDEX_3; - break; - default: - return; - } - processDecorationButtonPress(button, e->buttons(), e->x(), e->y(), e->globalX(), e->globalY()); -} - // return value matters only when filtering events before decoration gets them bool Client::buttonReleaseEvent(xcb_window_t w, int button, int state, int x, int y, int x_root, int y_root) { - if (w == decorationId() && !buttonDown) - return false; + if (w == frameId() && m_decoration) { + qDebug() << "Button release on frame"; + QMouseEvent event(QEvent::MouseButtonRelease, QPointF(x, y), QPointF(x_root, y_root), x11ToQtMouseButton(button), x11ToQtMouseButtons(state), x11ToQtKeyboardModifiers(state)); + QCoreApplication::sendEvent(m_decoration, &event); + } if (w == wrapperId()) { xcb_allow_events(connection(), XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); //xTime()); return true; } - if (w != frameId() && w != decorationId() && w != inputId() && w != moveResizeGrabWindow()) + if (w != frameId() && w != inputId() && w != moveResizeGrabWindow()) return true; x = this->x(); // translate from grab window to local coords y = this->y(); @@ -1299,10 +1217,9 @@ bool Client::buttonReleaseEvent(xcb_window_t w, int button, int state, int x, in if (moveResizeMode) { finishMoveResize(false); // mouse position is still relative to old Client position, adjust it - QPoint mousepos(x_root - x + padding_left, y_root - y + padding_top); + QPoint mousepos(x_root - x, y_root - y); mode = mousePosition(mousepos); - } else if (decorationPlugin()->supportsTabbing()) - return false; + } updateCursor(); } return true; @@ -1342,15 +1259,18 @@ void Client::checkQuickTilingMaximizationZones(int xroot, int yroot) // return value matters only when filtering events before decoration gets them bool Client::motionNotifyEvent(xcb_window_t w, int state, int x, int y, int x_root, int y_root) { - if (w != frameId() && w != decorationId() && w != inputId() && w != moveResizeGrabWindow()) + if (w == frameId() && m_decoration) { + // TODO Mouse move event dependent on state + QHoverEvent event(QEvent::HoverMove, QPointF(x, y), QPointF(x, y)); + QCoreApplication::instance()->sendEvent(m_decoration, &event); + } + if (w != frameId() && w != inputId() && w != moveResizeGrabWindow()) return true; // care only about the whole frame if (!buttonDown) { QPoint mousePos(x, y); - if (w == frameId()) - mousePos += QPoint(padding_left, padding_top); if (w == inputId()) { - int x = x_root - geometry().x() + padding_left; - int y = y_root - geometry().y() + padding_top; + int x = x_root - geometry().x();// + padding_left; + int y = y_root - geometry().y();// + padding_top; mousePos = QPoint(x, y); } Position newmode = modKeyDown(state) ? PositionCenter : mousePosition(mousePos); diff --git a/geometry.cpp b/geometry.cpp index 8e7e59d156..196d1abb2c 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -48,6 +48,9 @@ along with this program. If not, see . #include "outline.h" +#include +#include + namespace KWin { @@ -1239,8 +1242,8 @@ void Client::checkOffscreenPosition(QRect* geom, const QRect& screenArea) QSize Client::adjustedSize(const QSize& frame, Sizemode mode) const { // first, get the window size for the given frame size s - QSize wsize(frame.width() - (border_left + border_right), - frame.height() - (border_top + border_bottom)); + QSize wsize(frame.width() - (borderLeft() + borderRight()), + frame.height() - (borderTop() + borderBottom())); if (wsize.isEmpty()) wsize = QSize(1, 1); @@ -1276,9 +1279,9 @@ QSize Client::sizeForClientSize(const QSize& wsize, Sizemode mode, bool noframe) // even if they're not set in flags - see getWmNormalHints() QSize min_size = tabGroup() ? tabGroup()->minSize() : minSize(); QSize max_size = tabGroup() ? tabGroup()->maxSize() : maxSize(); - if (decoration != NULL) { - QSize decominsize = decoration->minimumSize(); - QSize border_size(border_left + border_right, border_top + border_bottom); + if (m_decoration != NULL) { + QSize decominsize(0, 0); + QSize border_size(borderLeft() + borderRight(), borderTop() + borderBottom()); if (border_size.width() > decominsize.width()) // just in case decominsize.setWidth(border_size.width()); if (border_size.height() > decominsize.height()) @@ -1424,8 +1427,8 @@ QSize Client::sizeForClientSize(const QSize& wsize, Sizemode mode, bool noframe) } if (!noframe) { - w += border_left + border_right; - h += border_top + border_bottom; + w += borderLeft() + borderRight(); + h += borderTop() + borderBottom(); } return rules()->checkSize(QSize(w, h)); } @@ -1556,19 +1559,19 @@ const QPoint Client::calculateGravitation(bool invert, int gravity) const switch(gravity) { case NorthWestGravity: // move down right default: - dx = border_left; - dy = border_top; + dx = borderLeft(); + dy = borderTop(); break; case NorthGravity: // move right dx = 0; - dy = border_top; + dy = borderTop(); break; case NorthEastGravity: // move down left - dx = -border_right; - dy = border_top; + dx = -borderRight(); + dy = borderTop(); break; case WestGravity: // move right - dx = border_left; + dx = borderLeft(); dy = 0; break; case CenterGravity: @@ -1578,30 +1581,30 @@ const QPoint Client::calculateGravitation(bool invert, int gravity) const dy = 0; break; case EastGravity: // move left - dx = -border_right; + dx = -borderRight(); dy = 0; break; case SouthWestGravity: // move up right - dx = border_left ; - dy = -border_bottom; + dx = borderLeft() ; + dy = -borderBottom(); break; case SouthGravity: // move up dx = 0; - dy = -border_bottom; + dy = -borderBottom(); break; case SouthEastGravity: // move up left - dx = -border_right; - dy = -border_bottom; + dx = -borderRight(); + dy = -borderBottom(); break; } if (gravity != CenterGravity) { // translate from client movement to frame movement - dx -= border_left; - dy -= border_top; + dx -= borderLeft(); + dy -= borderTop(); } else { // center of the frame will be at the same position client center without frame would be - dx = - (border_left + border_right) / 2; - dy = - (border_top + border_bottom) / 2; + dx = - (borderLeft() + borderRight()) / 2; + dy = - (borderTop() + borderBottom()) / 2; } if (!invert) return QPoint(x() + dx, y() + dy); @@ -1740,7 +1743,7 @@ void Client::resizeWithChecks(int w, int h, ForceGeometry_t force) { assert(!shade_geometry_change); if (isShade()) { - if (h == border_top + border_bottom) { + if (h == borderTop() + borderBottom()) { qWarning() << "Shaded geometry passed for size:" ; } } @@ -1892,14 +1895,14 @@ void Client::setGeometry(int x, int y, int w, int h, ForceGeometry_t force) if (shade_geometry_change) ; // nothing else if (isShade()) { - if (h == border_top + border_bottom) { + if (h == borderTop() + borderBottom()) { qDebug() << "Shaded geometry passed for size:"; } else { - client_size = QSize(w - border_left - border_right, h - border_top - border_bottom); - h = border_top + border_bottom; + client_size = QSize(w - borderLeft() - borderRight(), h - borderTop() - borderBottom()); + h = borderTop() + borderBottom(); } } else { - client_size = QSize(w - border_left - border_right, h - border_top - border_bottom); + client_size = QSize(w - borderLeft() - borderRight(), h - borderTop() - borderBottom()); } QRect g(x, y, w, h); if (block_geometry_updates == 0 && g != rules()->checkGeometry(g)) { @@ -1980,14 +1983,14 @@ void Client::plainResize(int w, int h, ForceGeometry_t force) if (shade_geometry_change) ; // nothing else if (isShade()) { - if (h == border_top + border_bottom) { + if (h == borderTop() + borderBottom()) { qDebug() << "Shaded geometry passed for size:"; } else { - client_size = QSize(w - border_left - border_right, h - border_top - border_bottom); - h = border_top + border_bottom; + client_size = QSize(w - borderLeft() - borderRight(), h - borderTop() - borderBottom()); + h = borderTop() + borderBottom(); } } else { - client_size = QSize(w - border_left - border_right, h - border_top - border_bottom); + client_size = QSize(w - borderLeft() - borderRight(), h - borderTop() - borderBottom()); } QSize s(w, h); if (block_geometry_updates == 0 && s != rules()->checkSize(s)) { @@ -2208,6 +2211,19 @@ void Client::changeMaximize(bool vertical, bool horizontal, bool adjust) changeMaximize(false, false, false); // restore } + // call into decoration update borders + if (m_decoration) { + if ((max_mode & KDecorationDefines::MaximizeVertical) != (old_mode & KDecorationDefines::MaximizeVertical)) { + emit m_decoration->client()->maximizedVerticallyChanged(max_mode & KDecorationDefines::MaximizeVertical); + } + if ((max_mode & KDecorationDefines::MaximizeHorizontal) != (old_mode & KDecorationDefines::MaximizeHorizontal)) { + emit m_decoration->client()->maximizedHorizontallyChanged(max_mode & KDecorationDefines::MaximizeHorizontal); + } + if ((max_mode == KDecorationDefines::MaximizeFull) != (old_mode == KDecorationDefines::MaximizeFull)) { + emit m_decoration->client()->maximizedChanged(max_mode & KDecorationDefines::MaximizeFull); + } + } + // save sizes for restoring, if maximalizing QSize sz; if (isShade()) @@ -2234,7 +2250,7 @@ void Client::changeMaximize(bool vertical, bool horizontal, bool adjust) changeMaximizeRecursion = false; } - const ForceGeometry_t geom_mode = decoration && checkBorderSizes(false) ? ForceGeometrySet : NormalGeometrySet; + const ForceGeometry_t geom_mode = m_decoration ? ForceGeometrySet : NormalGeometrySet; // Conditional quick tiling exit points if (quick_tile_mode != QuickTileNone) { @@ -2692,12 +2708,12 @@ void Client::checkUnrestrictedMoveResize() int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge; // restricted move/resize - keep at least part of the titlebar always visible // how much must remain visible when moved away in that direction - left_marge = qMin(100 + border_right, moveResizeGeom.width()); - right_marge = qMin(100 + border_left, moveResizeGeom.width()); + left_marge = qMin(100 + borderRight(), moveResizeGeom.width()); + right_marge = qMin(100 + borderLeft(), moveResizeGeom.width()); // width/height change with opaque resizing, use the initial ones titlebar_marge = initialMoveResizeGeom.height(); - top_marge = border_bottom; - bottom_marge = border_top; + top_marge = borderBottom(); + bottom_marge = borderTop(); if (isResize()) { if (moveResizeGeom.bottom() < desktopArea.top() + top_marge) unrestrictedMoveResize = true; @@ -2760,7 +2776,7 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root) return; if (!moveResizeMode) { - QPoint p(QPoint(x - padding_left, y - padding_top) - moveOffset); + QPoint p(QPoint(x/* - padding_left*/, y/* - padding_top*/) - moveOffset); if (p.manhattanLength() >= QApplication::startDragDistance()) { if (!startMoveResize()) { buttonDown = false; @@ -2787,7 +2803,7 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root) // When doing a restricted move we must always keep 100px of the titlebar // visible to allow the user to be able to move it again. - const int frameTop = border_top; + const int frameTop = borderTop(); int titlebarArea = qMin(frameTop * 100, moveResizeGeom.width() * moveResizeGeom.height()); bool update = false; @@ -3033,7 +3049,7 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root) syncRequest.isPending = true; // limit the resizes to 30Hz to take pointless load from X11 syncRequest.timeout->start(33); // and the client, the mouse is still moved at full speed } // and no human can control faster resizes anyway - m_client.setGeometry(0, 0, moveResizeGeom.width() - (border_left + border_right), moveResizeGeom.height() - (border_top + border_bottom)); + m_client.setGeometry(0, 0, moveResizeGeom.width() - (borderLeft() + borderRight()), moveResizeGeom.height() - (borderTop() + borderBottom())); } else performMoveResize(); @@ -3156,7 +3172,7 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard) if (mode != QuickTileNone) { quick_tile_mode = mode; // decorations may turn off some borders when tiled - const ForceGeometry_t geom_mode = decoration && checkBorderSizes(false) ? ForceGeometrySet : NormalGeometrySet; + const ForceGeometry_t geom_mode = m_decoration ? ForceGeometrySet : NormalGeometrySet; quick_tile_mode = QuickTileNone; // Temporary, so the maximize code doesn't get all confused setGeometry(electricBorderMaximizeGeometry(keyboard ? geometry().center() : Cursor::pos(), desktop()), geom_mode); } @@ -3220,7 +3236,7 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard) if (mode != QuickTileNone) { quick_tile_mode = mode; // decorations may turn off some borders when tiled - const ForceGeometry_t geom_mode = decoration && checkBorderSizes(false) ? ForceGeometrySet : NormalGeometrySet; + const ForceGeometry_t geom_mode = m_decoration ? ForceGeometrySet : NormalGeometrySet; // Temporary, so the maximize code doesn't get all confused quick_tile_mode = QuickTileNone; setGeometry(electricBorderMaximizeGeometry(whichScreen, desktop()), geom_mode); @@ -3238,7 +3254,7 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard) if (!geom_restore.isValid()) // invalid if we started maximized and wait for placement geom_restore = geometry(); // decorations may turn off some borders when tiled - const ForceGeometry_t geom_mode = decoration && checkBorderSizes(false) ? ForceGeometrySet : NormalGeometrySet; + const ForceGeometry_t geom_mode = m_decoration ? ForceGeometrySet : NormalGeometrySet; setGeometry(geom_restore, geom_mode); checkWorkspacePosition(); // Just in case it's a different screen } diff --git a/manage.cpp b/manage.cpp index b8c1454ba7..4763006548 100644 --- a/manage.cpp +++ b/manage.cpp @@ -29,7 +29,6 @@ along with this program. If not, see . #include "activities.h" #endif #include "cursor.h" -#include "decorations.h" #include #include "rules.h" #include "group.h" @@ -321,7 +320,7 @@ bool Client::manage(xcb_window_t w, bool isMapped) // Create client group if the window will have a decoration bool dontKeepInArea = false; setTabGroup(NULL); - if (!noBorder() && DecorationPlugin::self()->supportsTabbing()) { + if (!noBorder() && false) { const bool autogrouping = rules()->checkAutogrouping(options->isAutogroupSimilarWindows()); const bool autogroupInFg = rules()->checkAutogroupInForeground(options->isAutogroupInForeground()); // Automatically add to previous groups on session restore @@ -678,7 +677,7 @@ void Client::embedClient(xcb_window_t w, xcb_visualid_t visualid, xcb_colormap_t XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; - const uint32_t frame_event_mask = common_event_mask | XCB_EVENT_MASK_PROPERTY_CHANGE; + const uint32_t frame_event_mask = common_event_mask | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_VISIBILITY_CHANGE; const uint32_t wrapper_event_mask = common_event_mask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; const uint32_t client_event_mask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE | diff --git a/netinfo.cpp b/netinfo.cpp index 85983b478b..9f4bb9c100 100644 --- a/netinfo.cpp +++ b/netinfo.cpp @@ -25,7 +25,6 @@ along with this program. If not, see . #include // kwin #include "client.h" -#include "decorations.h" #include "virtualdesktops.h" #include "workspace.h" // Qt @@ -121,10 +120,6 @@ RootInfo *RootInfo::create() NET::ActionChangeDesktop | NET::ActionClose; - DecorationPlugin *deco = DecorationPlugin::self(); - if (!deco->isDisabled() && deco->factory()->supports(KDecorationDefines::AbilityExtendIntoClientArea)) - properties2 |= NET::WM2FrameOverlap; - s_self = new RootInfo(supportWindow, "KWin", properties, types, states, properties2, actions, screen_number); return s_self; } diff --git a/paintredirector.cpp b/paintredirector.cpp deleted file mode 100644 index 4e1f95631b..0000000000 --- a/paintredirector.cpp +++ /dev/null @@ -1,561 +0,0 @@ -/***************************************************************** -This file is part of the KDE project. - -Copyright (C) 2009 Lubos Lunak -Copyright (C) 2012 Martin Gräßlin - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -******************************************************************/ - -#include "paintredirector.h" - -#include "client.h" -#include "deleted.h" -#include "effects.h" -#include -#include -#include -#include -#include -#include -#include - -namespace KWin -{ - -PaintRedirector *PaintRedirector::create(Client *c, KDecoration *deco) -{ - if (effects->isOpenGLCompositing()) { - return new OpenGLPaintRedirector(c, deco); - } else if (effects->compositingType() == XRenderCompositing) { - return new RasterXRenderPaintRedirector(c, deco); - } else if (effects->compositingType() == QPainterCompositing) { - return new QImagePaintRedirector(c, deco); - } - return NULL; -} - -PaintRedirector::PaintRedirector(Client *c, KDecoration *deco) - : QObject(deco) - , widget(deco->widget()) - , recursionCheck(false) - , m_client(c) - , m_decoration(deco) - , m_requiresRepaint(false) -{ - added(deco->widget()); -} - -PaintRedirector::~PaintRedirector() -{ -} - -void PaintRedirector::reparent(Deleted *d) -{ - setParent(d); - widget = NULL; - m_client = NULL; - m_decoration = NULL; -} - -static int align(int value, int align) -{ - return (value + align - 1) & ~(align - 1); -} - -void PaintRedirector::performPendingPaint() -{ - if (!widget && !m_decoration->window()) { - return; - } - //qDebug() << "### performing paint, pending:" << pending.boundingRect(); - const QSize size = pending.boundingRect().size(); - QPaintDevice *scratch = this->scratch(); - if (scratch->width() < size.width() || scratch->height() < size.height()) { - int w = align(size.width(), 128); - int h = align(size.height(), 128); - scratch = recreateScratch(QSize(qMax(scratch->width(), w), qMax(scratch->height(), h))); - } - fillScratch(Qt::transparent); - recursionCheck = true; - m_decoration->render(scratch, pending.boundingRect()); - recursionCheck = false; - cleanupTimer.start(2000, this); -} - -bool PaintRedirector::isToolTip(QWidget *object) const -{ - // ### We need a more reliable way of doing this - return object->windowFlags() & Qt::ToolTip; -} - -bool PaintRedirector::eventFilter(QObject* o, QEvent* e) -{ - if (!widget || !m_client) { - return false; - } - switch(e->type()) { - case QEvent::ChildAdded: { - QChildEvent* c = static_cast< QChildEvent* >(e); - if (c->child()->isWidgetType() && !isToolTip(static_cast< QWidget* >(c->child()))) - added(static_cast< QWidget* >(c->child())); - break; - } - case QEvent::ChildRemoved: { - QChildEvent* c = static_cast< QChildEvent* >(e); - if (c->child()->isWidgetType()) - removed(static_cast< QWidget* >(c->child())); - break; - } - case QEvent::Paint: { - if (!recursionCheck) { - QPaintEvent* pe = static_cast< QPaintEvent* >(e); - QWidget* w = static_cast< QWidget* >(o); - pending |= pe->region().translated(w->mapTo(widget, QPoint(0, 0))); - scheduled = pending; - - // schedule repaint - const int paddingLeft = m_client->paddingLeft(); - const int paddingTop = m_client->paddingTop(); - const bool needsTranslate = (paddingLeft != 0 || paddingTop != 0); - m_client->addRepaint(needsTranslate ? pending.translated(-paddingLeft, -paddingTop) : pending); - m_requiresRepaint = true; - return true; // filter out - } - } - default: - break; - } - return false; -} - -void PaintRedirector::addRepaint(const QRegion ®ion) -{ - pending |= region; - scheduled = pending; - - // schedule repaint - const int paddingLeft = m_client->paddingLeft(); - const int paddingTop = m_client->paddingTop(); - const bool needsTranslate = (paddingLeft != 0 || paddingTop != 0); - m_client->addRepaint(needsTranslate ? pending.translated(-paddingLeft, -paddingTop) : pending); - m_requiresRepaint = true; -} - -QRegion PaintRedirector::pendingRegion() const -{ - return pending; -} - -QRegion PaintRedirector::scheduledRepaintRegion() -{ - QRegion tempRegion = scheduled; - scheduled = QRegion(); - return tempRegion; -} - -void PaintRedirector::added(QWidget* w) -{ - if (!w) { - return; - } - w->installEventFilter(this); - foreach (QObject * o, w->children()) { - if (o->isWidgetType() && !isToolTip(static_cast< QWidget* >(o))) - added(static_cast< QWidget* >(o)); - } -} - -void PaintRedirector::removed(QWidget* w) -{ - foreach (QObject * o, w->children()) { - if (o->isWidgetType()) - removed(static_cast< QWidget* >(o)); - } - w->installEventFilter(this); -} - -void PaintRedirector::timerEvent(QTimerEvent* event) -{ - if (event->timerId() == cleanupTimer.timerId()) { - cleanupTimer.stop(); - discardScratch(); - } -} - -void PaintRedirector::ensurePixmapsPainted() -{ - if (pending.isEmpty() || !m_client) - return; - - performPendingPaint(); - - QRect rects[PixmapCount]; - m_client->layoutDecorationRects(rects[LeftPixmap], rects[TopPixmap], rects[RightPixmap], rects[BottomPixmap], Client::DecorationRelative); - - updatePixmaps(rects, pending); - - pending = QRegion(); - scheduled = QRegion(); - - xcb_flush(connection()); -} - -void PaintRedirector::updatePixmaps(const QRect *rects, const QRegion ®ion) -{ - for (int i = 0; i < PixmapCount; ++i) { - if (!rects[i].isValid()) - continue; - - const QRect bounding = region.boundingRect(); - const QRegion reg = region & rects[i]; - - if (reg.isEmpty()) - continue; - - paint(DecorationPixmap(i), rects[i], bounding, reg); - } -} - -void PaintRedirector::preparePaint(const QPixmap &pending) -{ - Q_UNUSED(pending) -} - -void PaintRedirector::resizePixmaps() -{ - QRect rects[PixmapCount]; - m_client->layoutDecorationRects(rects[LeftPixmap], rects[TopPixmap], rects[RightPixmap], rects[BottomPixmap], Client::DecorationRelative); - - resizePixmaps(rects); - - // repaint - if (widget) { - widget->update(); - } -} - -void PaintRedirector::resizePixmaps(const QRect *rects) -{ - for (int i = 0; i < PixmapCount; ++i) { - resize(DecorationPixmap(i), rects[i].size()); - } -} - -GLTexture *PaintRedirector::texture(PaintRedirector::DecorationPixmap border) const -{ - Q_UNUSED(border) - return NULL; -} - -xcb_render_picture_t PaintRedirector::picture(PaintRedirector::DecorationPixmap border) const -{ - Q_UNUSED(border) - return XCB_RENDER_PICTURE_NONE; -} - -const QImage *PaintRedirector::image(PaintRedirector::DecorationPixmap border) const -{ - Q_UNUSED(border) - return NULL; -} - -void PaintRedirector::resize(DecorationPixmap border, const QSize &size) -{ - Q_UNUSED(border) - Q_UNUSED(size) -} - -void PaintRedirector::paint(DecorationPixmap border, const QRect& r, const QRect &b, const QRegion ®) -{ - Q_UNUSED(border) - Q_UNUSED(r) - Q_UNUSED(b) - Q_UNUSED(reg) -} - - - - -// ------------------------------------------------------------------ - - - - -ImageBasedPaintRedirector::ImageBasedPaintRedirector(Client *c, KDecoration *deco) - : PaintRedirector(c, deco) -{ -} - -ImageBasedPaintRedirector::~ImageBasedPaintRedirector() -{ -} - -QPaintDevice *ImageBasedPaintRedirector::recreateScratch(const QSize &size) -{ - m_scratchImage = QImage(size, QImage::Format_ARGB32_Premultiplied); - return &m_scratchImage; -} - -QPaintDevice *ImageBasedPaintRedirector::scratch() -{ - return &m_scratchImage; -} - -void ImageBasedPaintRedirector::fillScratch(Qt::GlobalColor color) -{ - m_scratchImage.fill(color); -} - -void ImageBasedPaintRedirector::discardScratch() -{ - m_scratchImage = QImage(); -} - - - -// ------------------------------------------------------------------ - - -OpenGLPaintRedirector::OpenGLPaintRedirector(Client *c, KDecoration *deco) - : ImageBasedPaintRedirector(c, deco), - m_texture(nullptr) -{ - PaintRedirector::resizePixmaps(); -} - -OpenGLPaintRedirector::~OpenGLPaintRedirector() -{ - delete m_texture; -} - -void OpenGLPaintRedirector::resizePixmaps(const QRect *rects) -{ - QSize size; - - size.rwidth() = qMax(qMax(rects[TopPixmap].width(), rects[BottomPixmap].width()), - qMax(rects[LeftPixmap].height(), rects[RightPixmap].height())); - size.rheight() = rects[TopPixmap].height() + rects[BottomPixmap].height() + - rects[LeftPixmap].width() + rects[RightPixmap].width() + 3; - - size.rwidth() = align(size.width(), 128); - - effects->makeOpenGLContextCurrent(); - if (!GLTexture::NPOTTextureSupported()) { - size.rwidth() = nearestPowerOfTwo(size.width()); - size.rheight() = nearestPowerOfTwo(size.height()); - } - - if (m_texture && m_texture->size() == size) - return; - - delete m_texture; - m_texture = 0; - - if (!size.isEmpty()) { - m_texture = new GLTexture(size.width(), size.height()); - m_texture->setYInverted(true); - m_texture->setWrapMode(GL_CLAMP_TO_EDGE); - m_texture->clear(); - } -} - -// Rotates the given source rect 90° counter-clockwise, -// and flips it vertically -static QImage rotate(const QImage &srcImage, const QRect &srcRect) -{ - QImage image(srcRect.height(), srcRect.width(), srcImage.format()); - - const uint32_t *src = reinterpret_cast(srcImage.bits()); - uint32_t *dst = reinterpret_cast(image.bits()); - - for (int x = 0; x < image.width(); x++) { - const uint32_t *s = src + (srcRect.y() + x) * srcImage.width() + srcRect.x(); - uint32_t *d = dst + x; - - for (int y = 0; y < image.height(); y++) { - *d = s[y]; - d += image.width(); - } - } - - return image; -} - -void OpenGLPaintRedirector::updatePixmaps(const QRect *rects, const QRegion ®ion) -{ - const QImage &image = scratchImage(); - const QRect bounding = region.boundingRect(); - - if (!m_texture) - return; - - // Top, Right, Bottom, Left - Qt::Orientation orientations[4] = { Qt::Horizontal, Qt::Vertical, Qt::Horizontal, Qt::Vertical }; - - const int topHeight = rects[TopPixmap].height(); - const int bottomHeight = rects[BottomPixmap].height(); - const int leftWidth = rects[RightPixmap].width(); - - const QPoint offsets[4] = { - QPoint(0, 0), // Top - QPoint(0, topHeight + bottomHeight + leftWidth + 3), // Right - QPoint(0, topHeight + 1), // Bottom - QPoint(0, topHeight + bottomHeight + 2) // Left - }; - - for (int i = 0; i < 4; i++) { - const QRect dirty = (region & rects[i]).boundingRect(); - if (dirty.isEmpty()) - continue; - - const QPoint dst = dirty.topLeft() - rects[i].topLeft() + offsets[i]; - const QRect src(dirty.topLeft() - bounding.topLeft(), dirty.size()); - - if (orientations[i] == Qt::Horizontal) { - m_texture->update(image, dst, src); - } else { - // We have to rotate the src image - const QImage im = rotate(image, src); - m_texture->update(im, dst); - } - } -} - - - - -// ------------------------------------------------------------------ - - - - -RasterXRenderPaintRedirector::RasterXRenderPaintRedirector(Client *c, KDecoration *deco) - : ImageBasedPaintRedirector(c, deco) - , m_gc(0) -{ - for (int i=0; i -Copyright (C) 2012 Martin Gräßlin - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -******************************************************************/ - -#ifndef PAINTREDIRECTOR_H -#define PAINTREDIRECTOR_H - -#include -#include -#include -#include -// xcb -#include - -class KDecoration; - -namespace KWin -{ - -// forward declarations -class Client; -class Deleted; -class XRenderPicture; -class GLTexture; - -// This class redirects all painting of a given widget (including its children) -// into a paint device (QPixmap). -class PaintRedirector - : public QObject -{ - Q_OBJECT -public: - enum DecorationPixmap { - TopPixmap, - RightPixmap, - BottomPixmap, - LeftPixmap, - PixmapCount - }; - virtual ~PaintRedirector(); - virtual bool eventFilter(QObject* o, QEvent* e); - QRegion pendingRegion() const; - QRegion scheduledRepaintRegion(); - - void markAsRepainted() { - m_requiresRepaint = false; - } - bool requiresRepaint() const { - return m_requiresRepaint; - } - void resizePixmaps(); - - template - T topDecoPixmap() const; - template - T leftDecoPixmap() const; - template - T bottomDecoPixmap() const; - template - T rightDecoPixmap() const; - - /** - * Used by Deleted::copyToDeleted() to move the PaintRedirector to the Deleted. - * The actual redirecting ends as the decoration gets destroyed after the Deleted - * is created. - **/ - void reparent(Deleted *d); - static PaintRedirector *create(Client *c, KDecoration *deco); - - void addRepaint(const QRegion ®ion); - -public Q_SLOTS: - void ensurePixmapsPainted(); -protected: - PaintRedirector(Client *c, KDecoration *deco); - virtual xcb_render_picture_t picture(DecorationPixmap border) const; - virtual GLTexture *texture(DecorationPixmap border) const; - virtual const QImage *image(DecorationPixmap border) const; - virtual void resizePixmaps(const QRect *rects); - virtual void resize(DecorationPixmap border, const QSize &size); - virtual void preparePaint(const QPixmap &pending); - virtual void updatePixmaps(const QRect *rects, const QRegion ®ion); - virtual void paint(DecorationPixmap border, const QRect& r, const QRect &b, const QRegion ®); - virtual QPaintDevice *scratch() = 0; - virtual QPaintDevice *recreateScratch(const QSize &size) = 0; - virtual void fillScratch(Qt::GlobalColor color) = 0; - virtual void discardScratch() = 0; - -private: - void added(QWidget* widget); - void removed(QWidget* widget); - bool isToolTip(QWidget* widget) const; - void timerEvent(QTimerEvent* event); - - void performPendingPaint(); - void repaintPixmap(DecorationPixmap border, const QRect& r, QRegion reg); - QWidget* widget; - QRegion pending; - QRegion scheduled; - bool recursionCheck; - QBasicTimer cleanupTimer; - - Client *m_client; - KDecoration *m_decoration; - bool m_requiresRepaint; -}; - -class ImageBasedPaintRedirector : public PaintRedirector -{ - Q_OBJECT -public: - virtual ~ImageBasedPaintRedirector(); -protected: - ImageBasedPaintRedirector(Client *c, KDecoration *deco); - virtual QPaintDevice *recreateScratch(const QSize &size); - virtual QPaintDevice *scratch(); - virtual void fillScratch(Qt::GlobalColor color); - virtual void discardScratch(); - const QImage &scratchImage() const; -private: - QImage m_scratchImage; -}; - -class OpenGLPaintRedirector : public ImageBasedPaintRedirector -{ - Q_OBJECT - -public: - OpenGLPaintRedirector(Client *c, KDecoration *deco); - virtual ~OpenGLPaintRedirector(); - - GLTexture *decorationTexture() const { return m_texture; } - -protected: - virtual void resizePixmaps(const QRect *rects); - virtual void updatePixmaps(const QRect *rects, const QRegion ®ion); - -private: - GLTexture *m_texture; -}; - -class RasterXRenderPaintRedirector : public ImageBasedPaintRedirector -{ - Q_OBJECT -public: - RasterXRenderPaintRedirector(Client *c, KDecoration *deco); - virtual ~RasterXRenderPaintRedirector(); - -protected: - virtual xcb_render_picture_t picture(DecorationPixmap border) const; - virtual void resize(DecorationPixmap border, const QSize &size); - virtual void paint(DecorationPixmap border, const QRect &r, const QRect &b, const QRegion ®); - virtual void preparePaint(const QPixmap &pending); -private: - QSize m_sizes[PixmapCount]; - xcb_pixmap_t m_pixmaps[PixmapCount]; - xcb_gcontext_t m_gc; - XRenderPicture* m_pictures[PixmapCount]; - QImage m_tempImage; -}; - -class QImagePaintRedirector : public ImageBasedPaintRedirector -{ - Q_OBJECT -public: - QImagePaintRedirector(Client *c, KDecoration *deco); - virtual ~QImagePaintRedirector(); - -protected: - virtual void resize(DecorationPixmap border, const QSize &size) override; - virtual void paint(DecorationPixmap border, const QRect &r, const QRect &b, const QRegion ®) override; - virtual const QImage* image(DecorationPixmap border) const override; -private: - QImage m_images[PixmapCount]; -}; - -template <> -inline -GLTexture *PaintRedirector::bottomDecoPixmap() const -{ - return texture(BottomPixmap); -} - -template <> -inline -GLTexture *PaintRedirector::leftDecoPixmap() const -{ - return texture(LeftPixmap); -} - -template <> -inline -GLTexture *PaintRedirector::rightDecoPixmap() const -{ - return texture(RightPixmap); -} - -template <> -inline -GLTexture *PaintRedirector::topDecoPixmap() const -{ - return texture(TopPixmap); -} - -template <> -inline -xcb_render_picture_t PaintRedirector::bottomDecoPixmap() const -{ - return picture(BottomPixmap); -} - -template <> -inline -xcb_render_picture_t PaintRedirector::leftDecoPixmap() const -{ - return picture(LeftPixmap); -} - -template <> -inline -xcb_render_picture_t PaintRedirector::rightDecoPixmap() const -{ - return picture(RightPixmap); -} - -template <> -inline -xcb_render_picture_t PaintRedirector::topDecoPixmap() const -{ - return picture(TopPixmap); -} - -template <> -inline -const QImage *PaintRedirector::bottomDecoPixmap() const -{ - return image(BottomPixmap); -} - -template <> -inline -const QImage *PaintRedirector::leftDecoPixmap() const -{ - return image(LeftPixmap); -} - -template <> -inline -const QImage *PaintRedirector::rightDecoPixmap() const -{ - return image(RightPixmap); -} - -template <> -inline -const QImage *PaintRedirector::topDecoPixmap() const -{ - return image(TopPixmap); -} - -inline -const QImage &ImageBasedPaintRedirector::scratchImage() const -{ - return m_scratchImage; -} - -} // namespace - -#endif diff --git a/scene.cpp b/scene.cpp index 46aa72f01d..2b6a6414b7 100644 --- a/scene.cpp +++ b/scene.cpp @@ -72,7 +72,6 @@ along with this program. If not, see . #include #include "client.h" -#include "decorations.h" #include "deleted.h" #include "effects.h" #include "overlaywindow.h" @@ -264,7 +263,6 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region) w->resetPaintingEnabled(); data.paint = region; data.paint |= topw->repaints(); - data.paint |= topw->decorationPendingRegion(); // Reset the repaint_region. // This has to be done here because many effects schedule a repaint for @@ -703,8 +701,7 @@ void Scene::Window::discardShape() const QRegion &Scene::Window::shape() const { if (!shape_valid) { - Client* c = dynamic_cast< Client* >(toplevel); - if (toplevel->shape() || (c != NULL && !c->mask().isEmpty())) { + if (toplevel->shape()) { auto cookie = xcb_shape_get_rectangles_unchecked(connection(), toplevel->frameId(), XCB_SHAPE_SK_BOUNDING); ScopedCPointer reply(xcb_shape_get_rectangles_reply(connection(), cookie, nullptr)); if (!reply.isNull()) { @@ -809,7 +806,7 @@ WindowQuadList Scene::Window::buildQuads(bool force) const Client *client = dynamic_cast(toplevel); QRegion contents = clientShape(); QRegion center = toplevel->transparentRect(); - QRegion decoration = (client && decorationPlugin()->hasAlpha() ? + QRegion decoration = (client && true ? QRegion(client->decorationRect()) : shape()) - center; ret = makeQuads(WindowQuadContents, contents); diff --git a/scene.h b/scene.h index 09689c2da7..10b9d28393 100644 --- a/scene.h +++ b/scene.h @@ -30,6 +30,12 @@ along with this program. If not, see . namespace KWin { +namespace Decoration +{ +class DecoratedClientImpl; +class Renderer; +} + class AbstractThumbnailItem; class Workspace; class Deleted; @@ -134,6 +140,8 @@ public: */ virtual bool isLastFrameRendered() const = 0; + virtual Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *) = 0; + public Q_SLOTS: // a window has been destroyed void windowDeleted(KWin::Deleted*); diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 4d02abee95..16fdcd8fce 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -44,9 +44,9 @@ along with this program. If not, see . #include "lanczosfilter.h" #include "main.h" #include "overlaywindow.h" -#include "paintredirector.h" #include "screens.h" #include "workspace.h" +#include "decorations/decoratedclient.h" #include #include @@ -569,6 +569,11 @@ Shadow *SceneOpenGL::createShadow(Toplevel *toplevel) return new SceneOpenGLShadow(toplevel); } +Decoration::Renderer *SceneOpenGL::createDecorationRenderer(Decoration::DecoratedClientImpl *impl) +{ + return new SceneOpenGLDecorationRenderer(impl); +} + //**************************************** // SceneOpenGL2 //**************************************** @@ -963,39 +968,23 @@ void SceneOpenGL::Window::endRenderWindow() } } - -OpenGLPaintRedirector *SceneOpenGL::Window::paintRedirector() const -{ - if (toplevel->isClient()) { - Client *client = static_cast(toplevel); - if (client->noBorder()) - return 0; - - return static_cast(client->decorationPaintRedirector()); - } - - if (toplevel->isDeleted()) { - Deleted *deleted = static_cast(toplevel); - if (deleted->noBorder()) - return 0; - - return static_cast(deleted->decorationPaintRedirector()); - } - - return 0; -} - GLTexture *SceneOpenGL::Window::getDecorationTexture() const { - OpenGLPaintRedirector *redirector = paintRedirector(); - if (!redirector) - return 0; + // TODO: deleted + if (toplevel->isClient()) { + Client *client = static_cast(toplevel); + if (client->noBorder()) { + return nullptr; + } - redirector->ensurePixmapsPainted(); - GLTexture *texture = redirector->decorationTexture(); - redirector->markAsRepainted(); - - return texture; + if (Decoration::DecoratedClientImpl *impl = client->decoratedClient()) { + if (SceneOpenGLDecorationRenderer *renderer = static_cast(impl->renderer())) { + renderer->render(); + return renderer->texture(); + } + } + } + return nullptr; } void SceneOpenGL::Window::paintDecorations(const WindowPaintData &data, const QRegion ®ion) @@ -2009,4 +1998,104 @@ char SwapProfiler::end() return 0; } +SceneOpenGLDecorationRenderer::SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl *client) + : Renderer(client) + , m_texture() +{ + connect(this, &Renderer::renderScheduled, client->client(), static_cast(&Client::addRepaint)); +} + +SceneOpenGLDecorationRenderer::~SceneOpenGLDecorationRenderer() = default; + +// Rotates the given source rect 90° counter-clockwise, +// and flips it vertically +static QImage rotate(const QImage &srcImage, const QRect &srcRect) +{ + QImage image(srcRect.height(), srcRect.width(), srcImage.format()); + + const uint32_t *src = reinterpret_cast(srcImage.bits()); + uint32_t *dst = reinterpret_cast(image.bits()); + + for (int x = 0; x < image.width(); x++) { + const uint32_t *s = src + (srcRect.y() + x) * srcImage.width() + srcRect.x(); + uint32_t *d = dst + x; + + for (int y = 0; y < image.height(); y++) { + *d = s[y]; + d += image.width(); + } + } + + return image; +} + +void SceneOpenGLDecorationRenderer::render() +{ + const QRegion scheduled = getScheduled(); + if (scheduled.isEmpty()) { + return; + } + if (areImageSizesDirty()) { + resizeTexture(); + resetImageSizesDirty(); + } + + QRect left, top, right, bottom; + client()->client()->layoutDecorationRects(left, top, right, bottom, Client::DecorationRelative); + + const QRect geometry = scheduled.boundingRect(); + + auto renderPart = [this](const QRect &geo, const QRect &partRect, const QPoint &offset, bool rotated = false) { + if (geo.isNull()) { + return; + } + QImage image = renderToImage(geo); + if (rotated) { + // TODO: get this done directly when rendering to the image + image = rotate(image, QRect(geo.topLeft() - partRect.topLeft(), geo.size())); + } + m_texture->update(image, geo.topLeft() - partRect.topLeft() + offset); + }; + renderPart(left.intersected(geometry), left, QPoint(0, top.height() + bottom.height() + 2), true); + renderPart(top.intersected(geometry), top, QPoint(0, 0)); + renderPart(right.intersected(geometry), right, QPoint(0, top.height() + bottom.height() + left.width() + 3), true); + renderPart(bottom.intersected(geometry), bottom, QPoint(0, top.height() + 1)); +} + +static int align(int value, int align) +{ + return (value + align - 1) & ~(align - 1); +} + +void SceneOpenGLDecorationRenderer::resizeTexture() +{ + QRect left, top, right, bottom; + client()->client()->layoutDecorationRects(left, top, right, bottom, Client::DecorationRelative); + QSize size; + + size.rwidth() = qMax(qMax(top.width(), bottom.width()), + qMax(left.height(), right.height())); + size.rheight() = top.height() + bottom.height() + + left.width() + right.width() + 3; + + size.rwidth() = align(size.width(), 128); + + if (!GLTexture::NPOTTextureSupported()) { + size.rwidth() = nearestPowerOfTwo(size.width()); + size.rheight() = nearestPowerOfTwo(size.height()); + } + + if (m_texture && m_texture->size() == size) + return; + + if (!size.isEmpty()) { + m_texture.reset(new GLTexture(size.width(), size.height())); + m_texture->setYInverted(true); + m_texture->setWrapMode(GL_CLAMP_TO_EDGE); + m_texture->clear(); + } else { + m_texture.reset(); + } +} + } // namespace diff --git a/scene_opengl.h b/scene_opengl.h index f39007cf27..d1b2a4fc64 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -28,12 +28,13 @@ along with this program. If not, see . #include "kwinglutils.h" #include "kwingltexture_p.h" +#include "decorations/decorationrenderer.h" + namespace KWin { class ColorCorrection; class LanczosFilter; class OpenGLBackend; -class OpenGLPaintRedirector; class SceneOpenGL : public Scene @@ -58,6 +59,7 @@ public: virtual bool makeOpenGLContextCurrent() override; virtual void doneOpenGLContextCurrent() override; virtual bool isLastFrameRendered() const override; + Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override; void idle(); @@ -238,9 +240,6 @@ protected: protected: SceneOpenGL *m_scene; bool m_hardwareClipping; - -private: - OpenGLPaintRedirector *paintRedirector() const; }; class SceneOpenGL2Window : public SceneOpenGL::Window @@ -617,6 +616,31 @@ private: QElapsedTimer m_renderTimer; }; +class SceneOpenGLDecorationRenderer : public Decoration::Renderer +{ + Q_OBJECT +public: + enum class DecorationPart : int { + Left, + Top, + Right, + Bottom, + Count + }; + explicit SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl *client); + virtual ~SceneOpenGLDecorationRenderer(); + + void render() override; + + GLTexture *texture() { + return m_texture.data(); + } + +private: + void resizeTexture(); + QScopedPointer m_texture; +}; + inline bool SceneOpenGL::hasPendingFlush() const { return m_backend->hasPendingFlush(); diff --git a/scene_qpainter.cpp b/scene_qpainter.cpp index 551ab58dc0..493381cd8b 100644 --- a/scene_qpainter.cpp +++ b/scene_qpainter.cpp @@ -24,16 +24,17 @@ along with this program. If not, see . #include "deleted.h" #include "effects.h" #include "main.h" -#include "paintredirector.h" #include "toplevel.h" #if HAVE_WAYLAND #include "wayland_backend.h" #endif #include "workspace.h" #include "xcbutils.h" +#include "decorations/decoratedclient.h" // Qt #include #include +#include namespace KWin { @@ -442,33 +443,31 @@ void SceneQPainter::Window::renderWindowDecorations(QPainter *painter) } bool noBorder = true; - PaintRedirector *redirector = NULL; + SceneQPainterDecorationRenderer *renderer = nullptr; QRect dtr, dlr, drr, dbr; if (client && !client->noBorder()) { - redirector = client->decorationPaintRedirector(); + if (Decoration::DecoratedClientImpl *impl = client->decoratedClient()) { + if (SceneQPainterDecorationRenderer *r = static_cast(impl->renderer())) { + renderer = r; + } + } client->layoutDecorationRects(dlr, dtr, drr, dbr, Client::WindowRelative); noBorder = false; } else if (deleted && !deleted->noBorder()) { noBorder = false; - redirector = deleted->decorationPaintRedirector(); + // TODO: renderer deleted->layoutDecorationRects(dlr, dtr, drr, dbr); } - if (noBorder || !redirector) { + if (noBorder || !renderer) { return; } - redirector->ensurePixmapsPainted(); - const QImage *left = redirector->leftDecoPixmap(); - const QImage *top = redirector->topDecoPixmap(); - const QImage *right = redirector->rightDecoPixmap(); - const QImage *bottom = redirector->bottomDecoPixmap(); + renderer->render(); - painter->drawImage(dtr, *top); - painter->drawImage(dlr, *left); - painter->drawImage(drr, *right); - painter->drawImage(dbr, *bottom); - - redirector->markAsRepainted(); + painter->drawImage(dtr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Top)); + painter->drawImage(dlr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Left)); + painter->drawImage(drr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Right)); + painter->drawImage(dbr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Bottom)); } WindowPixmap *SceneQPainter::Window::createWindowPixmap() @@ -476,6 +475,11 @@ WindowPixmap *SceneQPainter::Window::createWindowPixmap() return new QPainterWindowPixmap(this); } +Decoration::Renderer *SceneQPainter::createDecorationRenderer(Decoration::DecoratedClientImpl *impl) +{ + return new SceneQPainterDecorationRenderer(impl); +} + //**************************************** // QPainterWindowPixmap //**************************************** @@ -615,4 +619,77 @@ bool SceneQPainterShadow::prepareBackend() return true; } +//**************************************** +// QPainterDecorationRenderer +//**************************************** +SceneQPainterDecorationRenderer::SceneQPainterDecorationRenderer(Decoration::DecoratedClientImpl *client) + : Renderer(client) +{ + connect(this, &Renderer::renderScheduled, client->client(), static_cast(&Client::addRepaint)); +} + +SceneQPainterDecorationRenderer::~SceneQPainterDecorationRenderer() = default; + +QImage SceneQPainterDecorationRenderer::image(SceneQPainterDecorationRenderer::DecorationPart part) const +{ + Q_ASSERT(part != DecorationPart::Count); + return m_images[int(part)]; +} + +void SceneQPainterDecorationRenderer::render() +{ + const QRegion scheduled = getScheduled(); + if (scheduled.isEmpty()) { + return; + } + if (areImageSizesDirty()) { + resizeImages(); + resetImageSizesDirty(); + } + + const QRect top(QPoint(0, 0), m_images[int(DecorationPart::Top)].size()); + const QRect left(QPoint(0, top.height()), m_images[int(DecorationPart::Left)].size()); + const QRect right(QPoint(top.width() - m_images[int(DecorationPart::Right)].size().width(), top.height()), m_images[int(DecorationPart::Right)].size()); + const QRect bottom(QPoint(0, left.y() + left.height()), m_images[int(DecorationPart::Bottom)].size()); + + const QRect geometry = scheduled.boundingRect(); + auto renderPart = [this](const QRect &rect, const QRect &partRect, int index) { + if (rect.isEmpty()) { + return; + } + QPainter painter(&m_images[index]); + painter.setRenderHint(QPainter::Antialiasing); + painter.setWindow(partRect); + painter.setClipRect(rect); + painter.save(); + // clear existing part + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(rect, Qt::red); + painter.restore(); + client()->decoration()->paint(&painter); + }; + + renderPart(left.intersected(geometry), left, int(DecorationPart::Left)); + renderPart(top.intersected(geometry), top, int(DecorationPart::Top)); + renderPart(right.intersected(geometry), right, int(DecorationPart::Right)); + renderPart(bottom.intersected(geometry), bottom, int(DecorationPart::Bottom)); +} + +void SceneQPainterDecorationRenderer::resizeImages() +{ + QRect left, top, right, bottom; + client()->client()->layoutDecorationRects(left, top, right, bottom, Client::DecorationRelative); + + auto checkAndCreate = [this](int index, const QSize &size) { + if (m_images[index].size() != size) { + m_images[index] = QImage(size, QImage::Format_ARGB32_Premultiplied); + m_images[index].fill(Qt::transparent); + } + }; + checkAndCreate(int(DecorationPart::Left), left.size()); + checkAndCreate(int(DecorationPart::Right), right.size()); + checkAndCreate(int(DecorationPart::Top), top.size()); + checkAndCreate(int(DecorationPart::Bottom), bottom.size()); +} + } // KWin diff --git a/scene_qpainter.h b/scene_qpainter.h index 5846eba97e..c5103667f5 100644 --- a/scene_qpainter.h +++ b/scene_qpainter.h @@ -23,6 +23,8 @@ along with this program. If not, see . #include "scene.h" #include "shadow.h" +#include "decorations/decorationrenderer.h" + namespace KWin { namespace Xcb { @@ -143,6 +145,7 @@ public: virtual bool initFailed() const override; virtual EffectFrame *createEffectFrame(EffectFrameImpl *frame) override; virtual Shadow *createShadow(Toplevel *toplevel) override; + Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override; QPainter *painter(); @@ -227,6 +230,29 @@ protected: virtual bool prepareBackend() override; }; +class SceneQPainterDecorationRenderer : public Decoration::Renderer +{ + Q_OBJECT +public: + enum class DecorationPart : int { + Left, + Top, + Right, + Bottom, + Count + }; + explicit SceneQPainterDecorationRenderer(Decoration::DecoratedClientImpl *client); + virtual ~SceneQPainterDecorationRenderer(); + + void render() override; + + QImage image(DecorationPart part) const; + +private: + void resizeImages(); + QImage m_images[int(DecorationPart::Count)]; +}; + inline bool SceneQPainter::usesOverlayWindow() const { diff --git a/scene_xrender.cpp b/scene_xrender.cpp index ed45a8fb82..2871cc3f3c 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -26,18 +26,17 @@ along with this program. If not, see . #include "toplevel.h" #include "client.h" #include "composite.h" -#include "decorations.h" #include "deleted.h" #include "effects.h" #include "main.h" #include "overlaywindow.h" -#include "paintredirector.h" #include "workspace.h" #include "xcbutils.h" #include "kwinxrenderutils.h" #if HAVE_WAYLAND #include "wayland_backend.h" #endif +#include "decorations/decoratedclient.h" #include @@ -466,6 +465,11 @@ Shadow *SceneXrender::createShadow(Toplevel *toplevel) return new SceneXRenderShadow(toplevel); } +Decoration::Renderer *SceneXrender::createDecorationRenderer(Decoration::DecoratedClientImpl* client) +{ + return new SceneXRenderDecorationRenderer(client); +} + //**************************************** // SceneXrender::Window //**************************************** @@ -611,7 +615,7 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat Deleted *deleted = dynamic_cast(toplevel); const QRect decorationRect = toplevel->decorationRect(); if (((client && !client->noBorder()) || (deleted && !deleted->noBorder())) && - decorationPlugin()->hasAlpha()) { + true) { // decorated client transformed_shape = decorationRect; if (toplevel->shape()) { @@ -717,32 +721,30 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat xcb_render_picture_t top = XCB_RENDER_PICTURE_NONE; xcb_render_picture_t right = XCB_RENDER_PICTURE_NONE; xcb_render_picture_t bottom = XCB_RENDER_PICTURE_NONE; - PaintRedirector *redirector = NULL; QRect dtr, dlr, drr, dbr; - if (client || deleted) { + SceneXRenderDecorationRenderer *renderer = nullptr; + // TODO: deleted + if (client) { if (client && !client->noBorder()) { - redirector = client->decorationPaintRedirector(); + if (Decoration::DecoratedClientImpl *impl = client->decoratedClient()) { + renderer = static_cast(impl->renderer()); + } noBorder = client->noBorder(); client->layoutDecorationRects(dlr, dtr, drr, dbr, Client::WindowRelative); } - if (deleted && !deleted->noBorder()) { - noBorder = deleted->noBorder(); - redirector = deleted->decorationPaintRedirector(); - deleted->layoutDecorationRects(dlr, dtr, drr, dbr); - } - if (redirector) { - redirector->ensurePixmapsPainted(); - left = redirector->leftDecoPixmap(); - top = redirector->topDecoPixmap(); - right = redirector->rightDecoPixmap(); - bottom = redirector->bottomDecoPixmap(); - } - if (!noBorder) { - MAP_RECT_TO_TARGET(dtr); - MAP_RECT_TO_TARGET(dlr); - MAP_RECT_TO_TARGET(drr); - MAP_RECT_TO_TARGET(dbr); - } + } + if (renderer) { + renderer->render(); + left = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Left); + top = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Top); + right = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Right); + bottom = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Bottom); + } + if (!noBorder) { + MAP_RECT_TO_TARGET(dtr); + MAP_RECT_TO_TARGET(dlr); + MAP_RECT_TO_TARGET(drr); + MAP_RECT_TO_TARGET(dbr); } //END deco preparations @@ -860,9 +862,6 @@ xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, m_xrenderShadow->pic renderDeco(right, drr); renderDeco(bottom, dbr); } - if (redirector) { - redirector->markAsRepainted(); - } } if (data.brightness() != 1.0) { @@ -1307,6 +1306,115 @@ xcb_render_picture_t SceneXRenderShadow::picture(Shadow::ShadowElements element) return *m_pictures[element]; } +SceneXRenderDecorationRenderer::SceneXRenderDecorationRenderer(Decoration::DecoratedClientImpl *client) + : Renderer(client) + , m_gc(XCB_NONE) +{ + connect(this, &Renderer::renderScheduled, client->client(), static_cast(&Client::addRepaint)); + for (int i = 0; i < int(DecorationPart::Count); ++i) { + m_pixmaps[i] = XCB_PIXMAP_NONE; + m_pictures[i] = nullptr; + } +} + +SceneXRenderDecorationRenderer::~SceneXRenderDecorationRenderer() +{ + for (int i = 0; i < int(DecorationPart::Count); ++i) { + if (m_pixmaps[i] != XCB_PIXMAP_NONE) { + xcb_free_pixmap(connection(), m_pixmaps[i]); + } + delete m_pictures[i]; + } + if (m_gc != 0) { + xcb_free_gc(connection(), m_gc); + } +} + +void SceneXRenderDecorationRenderer::render() +{ + const QRegion scheduled = getScheduled(); + if (scheduled.isEmpty()) { + return; + } + if (areImageSizesDirty()) { + resizePixmaps(); + resetImageSizesDirty(); + } + + const QRect top(QPoint(0, 0), m_sizes[int(DecorationPart::Top)]); + const QRect left(QPoint(0, top.height()), m_sizes[int(DecorationPart::Left)]); + const QRect right(QPoint(top.width() - m_sizes[int(DecorationPart::Right)].width(), top.height()), m_sizes[int(DecorationPart::Right)]); + const QRect bottom(QPoint(0, left.y() + left.height()), m_sizes[int(DecorationPart::Bottom)]); + + xcb_connection_t *c = connection(); + if (m_gc == 0) { + m_gc = xcb_generate_id(connection()); + xcb_create_gc(c, m_gc, m_pixmaps[int(DecorationPart::Top)], 0, nullptr); + } + auto renderPart = [this, c](const QRect &geo, const QPoint &offset, int index) { + if (geo.isNull()) { + return; + } + QImage image = renderToImage(geo); + xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, m_pixmaps[index], m_gc, + image.width(), image.height(), geo.x() - offset.x(), geo.y() - offset.y(), 0, 32, + image.byteCount(), image.constBits()); + }; + const QRect geometry = scheduled.boundingRect(); + renderPart(left.intersected(geometry), left.topLeft(), int(DecorationPart::Left)); + renderPart(top.intersected(geometry), top.topLeft(), int(DecorationPart::Top)); + renderPart(right.intersected(geometry), right.topLeft(), int(DecorationPart::Right)); + renderPart(bottom.intersected(geometry), bottom.topLeft(), int(DecorationPart::Bottom)); + xcb_flush(c); +} + +void SceneXRenderDecorationRenderer::resizePixmaps() +{ + QRect left, top, right, bottom; + client()->client()->layoutDecorationRects(left, top, right, bottom, Client::DecorationRelative); + + xcb_connection_t *c = connection(); + auto checkAndCreate = [this, c](int border, const QRect &rect) { + const QSize size = rect.size(); + if (m_sizes[border] != size) { + m_sizes[border] = size; + if (m_pixmaps[border] != XCB_PIXMAP_NONE) { + xcb_free_pixmap(c, m_pixmaps[border]); + } + delete m_pictures[border]; + if (!size.isEmpty()) { + m_pixmaps[border] = xcb_generate_id(connection()); + xcb_create_pixmap(connection(), 32, m_pixmaps[border], rootWindow(), size.width(), size.height()); + m_pictures[border] = new XRenderPicture(m_pixmaps[border], 32); + } else { + m_pixmaps[border] = XCB_PIXMAP_NONE; + m_pictures[border] = nullptr; + } + } + if (!m_pictures[border]) { + return; + } + // fill transparent + xcb_rectangle_t r = {0, 0, uint16_t(size.width()), uint16_t(size.height())}; + xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, *m_pictures[border], preMultiply(Qt::transparent), 1, &r); + }; + + checkAndCreate(int(DecorationPart::Left), left); + checkAndCreate(int(DecorationPart::Top), top); + checkAndCreate(int(DecorationPart::Right), right); + checkAndCreate(int(DecorationPart::Bottom), bottom); +} + +xcb_render_picture_t SceneXRenderDecorationRenderer::picture(SceneXRenderDecorationRenderer::DecorationPart part) const +{ + Q_ASSERT(part != DecorationPart::Count); + XRenderPicture *picture = m_pictures[int(part)]; + if (!picture) { + return XCB_RENDER_PICTURE_NONE; + } + return *picture; +} + #undef DOUBLE_TO_FIXED #undef FIXED_TO_DOUBLE diff --git a/scene_xrender.h b/scene_xrender.h index 42e965f86f..fe0e5a1a0c 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -23,6 +23,7 @@ along with this program. If not, see . #include "scene.h" #include "shadow.h" +#include "decorations/decorationrenderer.h" #ifdef KWIN_HAVE_XRENDER_COMPOSITING @@ -196,6 +197,7 @@ public: virtual bool isLastFrameRendered() const { return m_backend->isLastFrameRendered(); } + Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *client); static SceneXrender *createScene(); protected: @@ -337,6 +339,32 @@ private: XRenderPicture* m_pictures[ShadowElementsCount]; }; +class SceneXRenderDecorationRenderer : public Decoration::Renderer +{ + Q_OBJECT +public: + enum class DecorationPart : int { + Left, + Top, + Right, + Bottom, + Count + }; + explicit SceneXRenderDecorationRenderer(Decoration::DecoratedClientImpl *client); + virtual ~SceneXRenderDecorationRenderer(); + + void render() override; + + xcb_render_picture_t picture(DecorationPart part) const; + +private: + void resizePixmaps(); + QSize m_sizes[int(DecorationPart::Count)]; + xcb_pixmap_t m_pixmaps[int(DecorationPart::Count)]; + xcb_gcontext_t m_gc; + XRenderPicture* m_pictures[int(DecorationPart::Count)]; +}; + } // namespace #endif diff --git a/tabgroup.cpp b/tabgroup.cpp index 1b5503eaf6..c8f2d48218 100644 --- a/tabgroup.cpp +++ b/tabgroup.cpp @@ -21,7 +21,6 @@ along with this program. If not, see . #include "tabgroup.h" #include "client.h" -#include "decorations.h" #include "effects.h" #include "workspace.h" @@ -63,7 +62,7 @@ bool TabGroup::add(Client* c, Client *other, bool after, bool becomeVisible) { Q_ASSERT(!c->tabGroup()); - if (!decorationPlugin()->supportsTabbing() || contains(c) || !contains(other)) + if (contains(c) || !contains(other)) return false; // Tabbed windows MUST have a decoration diff --git a/toplevel.h b/toplevel.h index 73e8242802..b11a2b2c9b 100644 --- a/toplevel.h +++ b/toplevel.h @@ -205,7 +205,6 @@ public: virtual QRect visibleRect() const; // the area the window occupies on the screen virtual QRect decorationRect() const; // rect including the decoration shadows virtual QRect transparentRect() const = 0; - virtual QRegion decorationPendingRegion() const; // decoration region that needs to be repainted virtual bool isClient() const; virtual bool isDeleted() const; @@ -511,11 +510,6 @@ inline QRect Toplevel::rect() const return QRect(0, 0, width(), height()); } -inline QRegion Toplevel::decorationPendingRegion() const -{ - return QRegion(); -} - inline bool Toplevel::readyForPainting() const { return ready_for_painting; diff --git a/useractions.cpp b/useractions.cpp index 305930bd26..12947079be 100755 --- a/useractions.cpp +++ b/useractions.cpp @@ -34,7 +34,6 @@ along with this program. If not, see . #include "useractions.h" #include "cursor.h" #include "client.h" -#include "decorations.h" #include "input.h" #include "workspace.h" #include "effects.h" @@ -337,7 +336,7 @@ void UserActionsMenu::init() m_menu->addSeparator(); // Actions for window tabbing - if (decorationPlugin()->supportsTabbing()) { + if (false) { m_removeFromTabGroup = m_menu->addAction(i18n("&Untab")); setShortcut(m_removeFromTabGroup, QStringLiteral("Untab")); m_removeFromTabGroup->setData(Options::RemoveTabFromGroupOp); @@ -409,7 +408,7 @@ void UserActionsMenu::menuAboutToShow() m_minimizeOperation->setEnabled(m_client.data()->isMinimizable()); m_closeOperation->setEnabled(m_client.data()->isCloseable()); - if (decorationPlugin()->supportsTabbing()) { + if (false) { initTabbingPopups(); m_addTabsMenu->setPalette(m_client.data()->palette()); } else { diff --git a/workspace.cpp b/workspace.cpp index 14606fd902..711df6243f 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -36,7 +36,6 @@ along with this program. If not, see . #include "composite.h" #include "cursor.h" #include "dbusinterface.h" -#include "decorations.h" #include "deleted.h" #include "effects.h" #include "focuschain.h" @@ -63,6 +62,7 @@ along with this program. If not, see . #endif #include "xcbutils.h" #include "main.h" +#include "decorations/decorationbridge.h" // KDE #include #include @@ -171,7 +171,6 @@ Workspace::Workspace(bool restore) options->loadConfig(); options->loadCompositingConfig(false); - DecorationPlugin::create(this); ColorMapper *colormaps = new ColorMapper(this); connect(this, SIGNAL(clientActivated(KWin::Client*)), colormaps, SLOT(update())); @@ -213,7 +212,9 @@ Workspace::Workspace(bool restore) XRenderUtils::init(connection(), rootWindow()); m_compositor = Compositor::create(this); connect(this, SIGNAL(currentDesktopChanged(int,KWin::Client*)), m_compositor, SLOT(addRepaintFull())); - connect(m_compositor, &Compositor::compositingToggled, decorationPlugin(), &DecorationPlugin::compositingToggled); + + new Decoration::DecorationBridge(this); + Decoration::DecorationBridge::self()->init(); new DBusInterface(this); @@ -784,18 +785,6 @@ void Workspace::slotReconfigure() m_userActionsMenu->discard(); updateToolWindows(true); - DecorationPlugin *deco = DecorationPlugin::self(); - if (!deco->isDisabled() && deco->reset()) { - deco->recreateDecorations(); - deco->destroyPreviousPlugin(); - connect(deco->factory(), &KDecorationFactory::recreateDecorations, deco, &DecorationPlugin::recreateDecorations); - } else { - foreach (Client * c, clients) { - c->checkBorderSizes(true); - c->triggerDecorationRepaint(); - } - } - RuleBook::self()->load(); for (ClientList::Iterator it = clients.begin(); it != clients.end(); @@ -816,12 +805,6 @@ void Workspace::slotReconfigure() (*it)->checkNoBorder(); } } - - if (!deco->isDisabled()) { - rootInfo()->setSupported(NET::WM2FrameOverlap, deco->factory()->supports(AbilityExtendIntoClientArea)); - } else { - rootInfo()->setSupported(NET::WM2FrameOverlap, false); - } } /** @@ -1412,9 +1395,6 @@ QString Workspace::supportInformation() const .arg(geo.width()) .arg(geo.height())); } - support.append(QStringLiteral("\nDecoration\n")); - support.append(QStringLiteral( "==========\n")); - support.append(decorationPlugin()->supportInformation()); support.append(QStringLiteral("\nCompositing\n")); support.append(QStringLiteral( "===========\n")); if (effects) {