Initial import of support for new KDecoration2 based decorations

NOTE: this is not working completely yet, lots of code is still ifdefed
other parts are still broken.

The main difference for the new decoration API is that it is neither
QWidget nor QWindow based. It's just a QObject which processes input
events and has a paint method to render the decoration. This means all
the workarounds for the QWidget interception are removed. Also the paint
redirector is removed. Instead each compositor has now its own renderer
which can be optimized for the specific case. E.g. the OpenGL compositor
renders to a scratch image which gets copied into the combined texture,
the XRender compositor copies into the XPixmaps.

Input events are also changed. The events are composed into QMouseEvents
and passed through the decoration, which might accept them. If they are
not accpted we assume that it's a press on the decoration area allowing
us to resize/move the window. Input events are not completely working
yet, e.g. wheel events are not yet processed and double click on deco
is not yet working.

Overall KDecoration2 is way more stateful and KWin core needs more
adjustments for it. E.g. borders are allowed to be disabled at any time.
This commit is contained in:
Martin Gräßlin 2014-07-22 13:11:19 +02:00
parent 2c78ff8bfd
commit 0030eb7f84
37 changed files with 1502 additions and 2144 deletions

View file

@ -97,6 +97,8 @@ set_package_properties(KF5DocTools PROPERTIES
) )
add_feature_info("KF5DocTools" KF5DocTools_FOUND "Enable building documentation") add_feature_info("KF5DocTools" KF5DocTools_FOUND "Enable building documentation")
find_package(KDecoration2 CONFIG REQUIRED)
if(${Qt5Gui_OPENGL_IMPLEMENTATION} STREQUAL "GL") if(${Qt5Gui_OPENGL_IMPLEMENTATION} STREQUAL "GL")
find_package(OpenGL) find_package(OpenGL)
set_package_properties(OpenGL PROPERTIES DESCRIPTION "The OpenGL libraries" set_package_properties(OpenGL PROPERTIES DESCRIPTION "The OpenGL libraries"
@ -313,7 +315,6 @@ set(kwin_KDEINIT_SRCS
main.cpp main.cpp
options.cpp options.cpp
outline.cpp outline.cpp
decorations.cpp
events.cpp events.cpp
killwindow.cpp killwindow.cpp
geometrytip.cpp geometrytip.cpp
@ -321,7 +322,6 @@ set(kwin_KDEINIT_SRCS
shadow.cpp shadow.cpp
sm.cpp sm.cpp
group.cpp group.cpp
bridge.cpp
manage.cpp manage.cpp
overlaywindow.cpp overlaywindow.cpp
activation.cpp activation.cpp
@ -342,7 +342,6 @@ set(kwin_KDEINIT_SRCS
effects.cpp effects.cpp
effectloader.cpp effectloader.cpp
compositingprefs.cpp compositingprefs.cpp
paintredirector.cpp
virtualdesktops.cpp virtualdesktops.cpp
xcbutils.cpp xcbutils.cpp
scripting/scripting.cpp scripting/scripting.cpp
@ -354,6 +353,10 @@ set(kwin_KDEINIT_SRCS
scripting/scripting_model.cpp scripting/scripting_model.cpp
scripting/dbuscall.cpp scripting/dbuscall.cpp
scripting/screenedgeitem.cpp scripting/screenedgeitem.cpp
decorations/decoratedclient.cpp
decorations/decorationbridge.cpp
decorations/settings.cpp
decorations/decorationrenderer.cpp
) )
if(KWIN_BUILD_TABBOX) if(KWIN_BUILD_TABBOX)
@ -445,6 +448,8 @@ set(kwin_KDE_LIBS
KF5::Service KF5::Service
KF5::Plasma KF5::Plasma
KF5::WindowSystem KF5::WindowSystem
KDecoration2::KDecoration
KDecoration2::KDecoration2Private
) )
set(kwin_XLIB_LIBS set(kwin_XLIB_LIBS

View file

@ -1,380 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "bridge.h"
#include "client.h"
#include "cursor.h"
#include "options.h"
#include <kconfiggroup.h>
#include "composite.h"
#include "paintredirector.h"
#include "virtualdesktops.h"
#include "workspace.h"
#include <QDebug>
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<Client*>(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 &region)
{
if (c->paintRedirector) {
c->paintRedirector->addRepaint(region);
}
}
//BEGIN TABBING
Client *Bridge::clientForId(long id) const
{
Client* client = reinterpret_cast<Client*>(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

113
bridge.h
View file

@ -1,113 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_BRIDGE_H
#define KWIN_BRIDGE_H
#include <kdecorationbridge.h>
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 &region) 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<long>(c);
}
Client* c;
};
} // namespace
#endif

View file

@ -28,21 +28,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "appmenu.h" #include "appmenu.h"
#endif #endif
#include "atoms.h" #include "atoms.h"
#include "bridge.h"
#include "client_machine.h" #include "client_machine.h"
#include "composite.h" #include "composite.h"
#include "cursor.h" #include "cursor.h"
#include "decorations.h"
#include "deleted.h" #include "deleted.h"
#include "focuschain.h" #include "focuschain.h"
#include "group.h" #include "group.h"
#include "paintredirector.h"
#include "shadow.h" #include "shadow.h"
#ifdef KWIN_BUILD_TABBOX #ifdef KWIN_BUILD_TABBOX
#include "tabbox.h" #include "tabbox.h"
#endif #endif
#include "workspace.h" #include "workspace.h"
#include "screenedge.h" #include "screenedge.h"
#include "decorations/decorationbridge.h"
#include "decorations/decoratedclient.h"
#include <KDecoration2/Decoration>
#include <KDecoration2/DecoratedClient>
// KDE // KDE
#include <KWindowSystem> #include <KWindowSystem>
#include <KColorScheme> #include <KColorScheme>
@ -181,8 +182,7 @@ Client::Client()
, m_client() , m_client()
, m_wrapper() , m_wrapper()
, m_frame() , m_frame()
, decoration(NULL) , m_decoration(nullptr)
, bridge(new Bridge(this))
, m_activityUpdatesBlocked(false) , m_activityUpdatesBlocked(false)
, m_blockedActivityUpdatesRequireTransients(false) , m_blockedActivityUpdatesRequireTransients(false)
, m_moveResizeGrabWindow() , m_moveResizeGrabWindow()
@ -211,16 +211,7 @@ Client::Client()
, block_geometry_updates(0) , block_geometry_updates(0)
, pending_geometry_update(PendingGeometryNone) , pending_geometry_update(PendingGeometryNone)
, shade_geometry_change(false) , 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) , sm_stacking_order(-1)
, paintRedirector(0)
, m_firstInTabBox(false) , m_firstInTabBox(false)
, electricMaximizing(false) , electricMaximizing(false)
, activitiesDefined(false) , activitiesDefined(false)
@ -306,12 +297,6 @@ Client::Client()
connect(clientMachine(), &ClientMachine::localhostChanged, this, &Client::updateCaption); connect(clientMachine(), &ClientMachine::localhostChanged, this, &Client::updateCaption);
connect(options, &Options::condensedTitleChanged, 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?? // SELI TODO: Initialize xsizehints??
} }
@ -331,10 +316,9 @@ Client::~Client()
assert(m_client == XCB_WINDOW_NONE); assert(m_client == XCB_WINDOW_NONE);
assert(m_wrapper == XCB_WINDOW_NONE); assert(m_wrapper == XCB_WINDOW_NONE);
//assert( frameId() == None ); //assert( frameId() == None );
assert(decoration == NULL); Q_ASSERT(m_decoration == nullptr);
assert(block_geometry_updates == 0); assert(block_geometry_updates == 0);
assert(!check_active_modal); assert(!check_active_modal);
delete bridge;
for (auto it = m_connections.constBegin(); it != m_connections.constEnd(); ++it) { for (auto it = m_connections.constBegin(); it != m_connections.constEnd(); ++it) {
disconnect(*it); disconnect(*it);
} }
@ -461,6 +445,7 @@ void Client::updateInputWindow()
QRegion region; QRegion region;
#if 0
if (!noBorder()) { if (!noBorder()) {
// This function is implemented as a slot to avoid breaking binary // This function is implemented as a slot to avoid breaking binary
// compatibility // compatibility
@ -468,6 +453,7 @@ void Client::updateInputWindow()
Q_RETURN_ARG(QRegion, region), Q_RETURN_ARG(QRegion, region),
Q_ARG(KDecorationDefines::Region, KDecorationDefines::ExtendedBorderRegion)); Q_ARG(KDecorationDefines::Region, KDecorationDefines::ExtendedBorderRegion));
} }
#endif
if (region.isEmpty()) { if (region.isEmpty()) {
m_decoInputExtent.reset(); m_decoInputExtent.reset();
@ -507,7 +493,7 @@ void Client::updateInputWindow()
void Client::updateDecoration(bool check_workspace_pos, bool force) void Client::updateDecoration(bool check_workspace_pos, bool force)
{ {
if (!force && if (!force &&
((decoration == NULL && noBorder()) || (decoration != NULL && !noBorder()))) ((m_decoration == NULL && noBorder()) || (m_decoration != NULL && !noBorder())))
return; return;
QRect oldgeom = geometry(); QRect oldgeom = geometry();
blockGeometryUpdates(true); blockGeometryUpdates(true);
@ -521,55 +507,19 @@ void Client::updateDecoration(bool check_workspace_pos, bool force)
checkWorkspacePosition(oldgeom); checkWorkspacePosition(oldgeom);
updateInputWindow(); updateInputWindow();
blockGeometryUpdates(false); blockGeometryUpdates(false);
if (!noBorder())
decoration->show();
updateFrameExtents(); updateFrameExtents();
} }
void Client::createDecoration(const QRect& oldgeom) void Client::createDecoration(const QRect& oldgeom)
{ {
setMask(QRegion()); // Reset shape mask m_decoration = Decoration::DecorationBridge::self()->createDecoration(this);
if (decorationPlugin()->isDisabled()) { if (m_decoration) {
decoration = NULL; m_decoration->update();
return;
} else {
decoration = decorationPlugin()->createDecoration(bridge);
} }
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<void (Client::*)(Client*, KDecorationDefines::MaximizeMode)>(&Client::clientMaximizedStateChanged);
connect(this, signalMaximizeChanged, decoration, &KDecoration::maximizeChanged);
auto slotKeepAbove = static_cast<void(KDecoration::*)(bool)>(&KDecoration::keepAboveChanged);
connect(this, &Client::keepAboveChanged, decoration, slotKeepAbove);
auto slotKeepBelow = static_cast<void(KDecoration::*)(bool)>(&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)); move(calculateGravitation(false));
plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); plainResize(sizeForClientSize(clientSize()), ForceGeometrySet);
if (Compositor::compositing()) { if (Compositor::compositing()) {
paintRedirector = PaintRedirector::create(this, decoration);
discardWindowPixmap(); discardWindowPixmap();
} }
emit geometryShapeChanged(this, oldgeom); emit geometryShapeChanged(this, oldgeom);
@ -578,13 +528,10 @@ void Client::createDecoration(const QRect& oldgeom)
void Client::destroyDecoration() void Client::destroyDecoration()
{ {
QRect oldgeom = geometry(); QRect oldgeom = geometry();
if (decoration != NULL) { if (m_decoration) {
delete decoration; delete m_decoration;
decoration = NULL; m_decoration = nullptr;
paintRedirector = NULL;
QPoint grav = calculateGravitation(true); QPoint grav = calculateGravitation(true);
border_left = border_right = border_top = border_bottom = 0;
setMask(QRegion()); // Reset shape mask
plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); plainResize(sizeForClientSize(clientSize()), ForceGeometrySet);
move(grav); move(grav);
if (compositing()) if (compositing())
@ -598,6 +545,7 @@ void Client::destroyDecoration()
bool Client::checkBorderSizes(bool also_resize) bool Client::checkBorderSizes(bool also_resize)
{ {
#if 0
if (decoration == NULL) if (decoration == NULL)
return false; return false;
@ -630,25 +578,28 @@ bool Client::checkBorderSizes(bool also_resize)
QRect oldgeom = geometry(); QRect oldgeom = geometry();
plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); plainResize(sizeForClientSize(clientSize()), ForceGeometrySet);
checkWorkspacePosition(oldgeom); checkWorkspacePosition(oldgeom);
#endif
return true; return true;
} }
void Client::triggerDecorationRepaint() void Client::triggerDecorationRepaint()
{ {
if (decoration && decoration->widget()) if (m_decoration) {
decoration->widget()->update(); m_decoration->update();
}
} }
void Client::layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom, Client::CoordinateMode mode) const void Client::layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom, Client::CoordinateMode mode) const
{ {
QRect r = decoration->rect(); if (!m_decoration) {
if (mode == WindowRelative) return;
r.translate(-padding_left, -padding_top); }
QRect r = m_decoration->rect();
NETStrut strut = info->frameOverlap(); NETStrut strut = info->frameOverlap();
// Ignore the overlap strut when compositing is disabled // Ignore the overlap strut when compositing is disabled
if (!compositing() || !decorationPlugin()->supportsFrameOverlap()) if (!compositing())
strut.left = strut.top = strut.right = strut.bottom = 0; strut.left = strut.top = strut.right = strut.bottom = 0;
else if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1) { 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); 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; return;
} }
top = QRect(r.x(), r.y(), r.width(), padding_top + border_top + strut.top); top = QRect(r.x(), r.y(), r.width(), borderTop() + strut.top);
bottom = QRect(r.x(), r.y() + r.height() - padding_bottom - border_bottom - strut.bottom, bottom = QRect(r.x(), r.y() + r.height() - borderBottom() - strut.bottom,
r.width(), padding_bottom + border_bottom + strut.bottom); r.width(), borderBottom() + strut.bottom);
left = QRect(r.x(), r.y() + top.height(), left = QRect(r.x(), r.y() + top.height(),
padding_left + border_left + strut.left, r.height() - top.height() - bottom.height()); borderLeft() + strut.left, r.height() - top.height() - bottom.height());
right = QRect(r.x() + r.width() - padding_right - border_right - strut.right, r.y() + top.height(), right = QRect(r.x() + r.width() - borderRight() - strut.right, r.y() + top.height(),
padding_right + border_right + strut.right, r.height() - top.height() - bottom.height()); borderRight() + 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);
} }
QRect Client::transparentRect() const QRect Client::transparentRect() const
@ -681,7 +625,7 @@ QRect Client::transparentRect() const
NETStrut strut = info->frameOverlap(); NETStrut strut = info->frameOverlap();
// Ignore the strut when compositing is disabled or the decoration doesn't support it // 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; strut.left = strut.top = strut.right = strut.bottom = 0;
else if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1) else if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1)
return QRect(); return QRect();
@ -733,10 +677,10 @@ void Client::detectNoBorder()
void Client::updateFrameExtents() void Client::updateFrameExtents()
{ {
NETStrut strut; NETStrut strut;
strut.left = border_left; strut.left = borderLeft();
strut.right = border_right; strut.right = borderRight();
strut.top = border_top; strut.top = borderTop();
strut.bottom = border_bottom; strut.bottom = borderBottom();
info->setFrameExtents(strut); info->setFrameExtents(strut);
} }
@ -756,32 +700,16 @@ void Client::detectGtkFrameExtents()
*/ */
void Client::resizeDecoration(const QSize& s) void Client::resizeDecoration(const QSize& s)
{ {
if (decoration == NULL) if (m_decoration) {
return; m_decoration->update();
QSize newSize = s + QSize(padding_left + padding_right, padding_top + padding_bottom); updateInputWindow();
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();
} }
Xcb::moveWindow(decoration->window()->winId(), -padding_left, -padding_top);
updateInputWindow(); updateInputWindow();
} }
bool Client::noBorder() const bool Client::noBorder() const
{ {
return decorationPlugin()->isDisabled() || noborder || isFullScreen(); return noborder || isFullScreen();
} }
bool Client::userCanSetNoBorder() const 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<uint16_t>(clientSize().width()),
static_cast<uint16_t>(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) void Client::hideClient(bool hide)
{ {
if (hidden == hide) if (hidden == hide)
@ -1066,8 +941,10 @@ void Client::setShade(ShadeMode mode)
// Decorations may turn off some borders when shaded // Decorations may turn off some borders when shaded
// this has to happen _before_ the tab alignment since it will restrict the minimum geometry // this has to happen _before_ the tab alignment since it will restrict the minimum geometry
#if 0
if (decoration) if (decoration)
decoration->borders(border_left, border_right, border_top, border_bottom); decoration->borders(border_left, border_right, border_top, border_bottom);
#endif
// Update states of all other windows in this group // Update states of all other windows in this group
if (tabGroup()) if (tabGroup())
@ -1079,7 +956,7 @@ void Client::setShade(ShadeMode mode)
return; // No real change in shaded state 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); GeometryUpdatesBlocker blocker(this);
// TODO: All this unmapping, resizing etc. feels too much duplicated from elsewhere // TODO: All this unmapping, resizing etc. feels too much duplicated from elsewhere
@ -1089,7 +966,7 @@ void Client::setShade(ShadeMode mode)
// Shade // Shade
shade_geometry_change = true; shade_geometry_change = true;
QSize s(sizeForClientSize(QSize(clientSize()))); QSize s(sizeForClientSize(QSize(clientSize())));
s.setHeight(border_top + border_bottom); s.setHeight(borderTop() + borderBottom());
m_wrapper.selectInput(ClientWinMask); // Avoid getting UnmapNotify m_wrapper.selectInput(ClientWinMask); // Avoid getting UnmapNotify
m_wrapper.unmap(); m_wrapper.unmap();
m_client.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 // for use in effects, but now we want to have access to the new pixmap
if (compositing()) if (compositing())
discardWindowPixmap(); discardWindowPixmap();
if (decoration != NULL)
decoration->show(); // Not really necessary, but let it know the state
m_frame.map(); m_frame.map();
if (!isShade()) { if (!isShade()) {
m_wrapper.map(); m_wrapper.map();
@ -1343,8 +1218,6 @@ void Client::unmap()
m_client.unmap(); m_client.unmap();
m_decoInputExtent.unmap(); m_decoInputExtent.unmap();
m_wrapper.selectInput(ClientWinMask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY); 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); 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 motif_may_close = mclose; // Motif apps like to crash when they set this hint and WM closes them anyway
if (isManaged()) if (isManaged())
updateDecoration(true); // Check if noborder state has changed updateDecoration(true); // Check if noborder state has changed
#if 0
if (decoration && closabilityChanged) if (decoration && closabilityChanged)
emit decoration->decorationButtonsChanged(); emit decoration->decorationButtonsChanged();
#endif
} }
void Client::getIcons() void Client::getIcons()
@ -2302,8 +2177,6 @@ void Client::updateCursor()
if (c == m_cursor) if (c == m_cursor)
return; return;
m_cursor = c; m_cursor = c;
if (decoration != NULL)
decoration->window()->setCursor(m_cursor);
xcb_cursor_t nativeCursor = Cursor::x11Cursor(m_cursor); xcb_cursor_t nativeCursor = Cursor::x11Cursor(m_cursor);
m_frame.defineCursor(nativeCursor); m_frame.defineCursor(nativeCursor);
if (m_decoInputExtent.isValid()) if (m_decoInputExtent.isValid())
@ -2326,8 +2199,29 @@ void Client::setBlockingCompositing(bool block)
Client::Position Client::mousePosition(const QPoint& p) const Client::Position Client::mousePosition(const QPoint& p) const
{ {
if (decoration != NULL) Q_UNUSED(p)
return decoration->mousePosition(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; 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) // 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); const NET::Actions relevant = ~(NET::ActionMove|NET::ActionResize);
#if 0
if (decoration && (allowed_actions & relevant) != (old_allowed_actions & relevant)) if (decoration && (allowed_actions & relevant) != (old_allowed_actions & relevant))
emit decoration->decorationButtonsChanged(); emit decoration->decorationButtonsChanged();
#endif
} }
void Client::autoRaise() void Client::autoRaise()
@ -2433,21 +2329,13 @@ void Client::setSessionInteract(bool needed)
QRect Client::decorationRect() const QRect Client::decorationRect() const
{ {
if (decoration) { return QRect(0, 0, width(), height());
return decoration->rect().translated(-padding_left, -padding_top);
} else {
return QRect(0, 0, width(), height());
}
} }
KDecorationDefines::Position Client::titlebarPosition() const KDecorationDefines::Position Client::titlebarPosition() const
{ {
Position titlePos = PositionCenter; // PositionTop is returned by the default implementation // TODO: still needed, remove?
// this will hint errors in the metaobject usage ;-) return PositionTop;
if (decoration)
QMetaObject::invokeMethod(decoration, "titlebarPosition", Qt::DirectConnection,
Q_RETURN_ARG(KDecorationDefines::Position, titlePos));
return titlePos;
} }
void Client::updateFirstInTabBox() void Client::updateFirstInTabBox()
@ -2518,6 +2406,7 @@ NET::WindowType Client::windowType(bool direct, int supportedTypes) const
bool Client::decorationHasAlpha() const bool Client::decorationHasAlpha() const
{ {
#if 0
if (!decoration || !decorationPlugin()->hasAlpha()) { if (!decoration || !decorationPlugin()->hasAlpha()) {
// either no decoration or decoration has alpha disabled // either no decoration or decoration has alpha disabled
return false; return false;
@ -2528,6 +2417,8 @@ bool Client::decorationHasAlpha() const
// decoration has alpha enabled and does not support alpha announcement // decoration has alpha enabled and does not support alpha announcement
return true; return true;
} }
#endif
return true;
} }
void Client::cancelFocusOutTimer() 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); 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<Decoration::DecoratedClientImpl*>(m_decoration->client()->handle());
}
} // namespace } // namespace
#include "client.moc" #include "client.moc"

View file

@ -44,6 +44,11 @@ class KStartupInfoId;
struct xcb_sync_alarm_notify_event_t; struct xcb_sync_alarm_notify_event_t;
namespace KDecoration2
{
class Decoration;
}
namespace KWin namespace KWin
{ {
namespace TabBox namespace TabBox
@ -52,8 +57,10 @@ namespace TabBox
class TabBoxClientImpl; class TabBoxClientImpl;
} }
class Bridge; namespace Decoration
class PaintRedirector; {
class DecoratedClientImpl;
}
/** /**
@ -286,7 +293,6 @@ class Client
public: public:
explicit Client(); explicit Client();
xcb_window_t wrapperId() const; xcb_window_t wrapperId() const;
xcb_window_t decorationId() const;
xcb_window_t inputId() const { return m_decoInputExtent; } xcb_window_t inputId() const { return m_decoInputExtent; }
virtual xcb_window_t frameId() const override; virtual xcb_window_t frameId() const override;
@ -329,7 +335,6 @@ public:
QPoint inputPos() const { return input_offset; } // Inside of geometry() QPoint inputPos() const { return input_offset; } // Inside of geometry()
bool windowEvent(xcb_generic_event_t *e); bool windowEvent(xcb_generic_event_t *e);
virtual bool eventFilter(QObject* o, QEvent* e);
void syncEvent(xcb_sync_alarm_notify_event_t* e); void syncEvent(xcb_sync_alarm_notify_event_t* e);
NET::WindowType windowType(bool direct = false, int supported_types = 0) const; NET::WindowType windowType(bool direct = false, int supported_types = 0) const;
@ -438,9 +443,6 @@ public:
} }
void demandAttention(bool set = true); 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); void updateDecoration(bool check_workspace_pos, bool force = false);
bool checkBorderSizes(bool also_resize); bool checkBorderSizes(bool also_resize);
void triggerDecorationRepaint(); void triggerDecorationRepaint();
@ -589,29 +591,18 @@ public:
} }
// Decorations <-> Effects // Decorations <-> Effects
PaintRedirector *decorationPaintRedirector() { KDecoration2::Decoration *decoration() {
return paintRedirector; return m_decoration;
} }
const KDecoration2::Decoration *decoration() const {
int paddingLeft() const { return m_decoration;
return padding_left;
}
int paddingRight() const {
return padding_right;
}
int paddingTop() const {
return padding_top;
}
int paddingBottom() const {
return padding_bottom;
} }
Decoration::DecoratedClientImpl *decoratedClient();
QRect decorationRect() const; QRect decorationRect() const;
QRect transparentRect() const; QRect transparentRect() const;
QRegion decorationPendingRegion() const;
bool decorationHasAlpha() const; bool decorationHasAlpha() const;
bool isClientSideDecorated() const; bool isClientSideDecorated() const;
@ -683,10 +674,6 @@ private Q_SLOTS:
void shadeHover(); void shadeHover();
void shadeUnhover(); void shadeUnhover();
private:
friend class Bridge; // FRAME
virtual void processMousePressEvent(QMouseEvent* e);
private: private:
// Use Workspace::createClient() // Use Workspace::createClient()
virtual ~Client(); ///< Use destroyClient() or releaseWindow() virtual ~Client(); ///< Use destroyClient() or releaseWindow()
@ -789,6 +776,10 @@ Q_SIGNALS:
void clientSideDecoratedChanged(); void clientSideDecoratedChanged();
private: 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 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 bool isManaged() const; ///< Returns false if this client is not yet managed
void updateAllowedActions(bool force = false); void updateAllowedActions(bool force = false);
@ -869,8 +860,7 @@ private:
Xcb::Window m_frame; Xcb::Window m_frame;
// wrapper around m_frame to use as a parent for the decoration // wrapper around m_frame to use as a parent for the decoration
QScopedPointer<QWindow> m_frameWrapper; QScopedPointer<QWindow> m_frameWrapper;
KDecoration* decoration; KDecoration2::Decoration *m_decoration;
Bridge* bridge;
int desk; int desk;
QStringList activityList; QStringList activityList;
int m_activityUpdatesBlocked; int m_activityUpdatesBlocked;
@ -991,15 +981,11 @@ private:
QTimer *timeout, *failsafeTimeout; QTimer *timeout, *failsafeTimeout;
bool isPending; bool isPending;
} syncRequest; } 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() static bool check_active_modal; ///< \see Client::checkActiveModal()
QKeySequence _shortcut; QKeySequence _shortcut;
int sm_stacking_order; int sm_stacking_order;
friend struct ResetupRulesProcedure; friend struct ResetupRulesProcedure;
friend class GeometryUpdatesBlocker; friend class GeometryUpdatesBlocker;
PaintRedirector* paintRedirector;
QSharedPointer<TabBox::TabBoxClientImpl> m_tabBoxClient; QSharedPointer<TabBox::TabBoxClientImpl> m_tabBoxClient;
bool m_firstInTabBox; bool m_firstInTabBox;
@ -1050,14 +1036,6 @@ inline xcb_window_t Client::wrapperId() const
return m_wrapper; 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 inline bool Client::isClientSideDecorated() const
{ {
return m_clientSideDecorated; return m_clientSideDecorated;
@ -1223,7 +1201,7 @@ inline bool Client::isManaged() const
inline QPoint Client::clientPos() const inline QPoint Client::clientPos() const
{ {
return QPoint(border_left, border_top); return QPoint(borderLeft(), borderTop());
} }
inline QSize Client::clientSize() const inline QSize Client::clientSize() const

View file

@ -1106,10 +1106,6 @@ bool Client::setupCompositing()
return false; return false;
} }
updateVisibility(); // for internalKeep() updateVisibility(); // for internalKeep()
if (isManaged()) {
// only create the decoration when a client is managed
updateDecoration(true, true);
}
return true; return true;
} }
@ -1118,8 +1114,7 @@ void Client::finishCompositing(ReleaseReason releaseReason)
Toplevel::finishCompositing(releaseReason); Toplevel::finishCompositing(releaseReason);
updateVisibility(); updateVisibility();
if (!deleting) { if (!deleting) {
// only recreate the decoration if we are not shutting down completely triggerDecorationRepaint();
updateDecoration(true, true);
} }
// for safety in case KWin is just resizing the window // for safety in case KWin is just resizing the window
s_haveResizeEffect = false; s_haveResizeEffect = false;

View file

@ -1,183 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 1999, 2000 Daniel M. Duley <mosfet@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "decorations.h"
#include "config-kwin.h"
#include "client.h"
#include "workspace.h"
#include <kdecorationfactory.h>
#include <KLocalizedString>
#include <stdlib.h>
#include <QPixmap>
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

View file

@ -1,72 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 1999, 2000 Daniel M. Duley <mosfet@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_PLUGINS_H
#define KWIN_PLUGINS_H
#include <kdecoration_plugins_p.h>
#include <kwinglobals.h>
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

View file

@ -0,0 +1,201 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#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 <KDecoration2/DecoratedClient>
#include <KDecoration2/Decoration>
#include <QDebug>
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);
}
}
}
}

View file

@ -0,0 +1,97 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_DECORATED_CLIENT_H
#define KWIN_DECORATED_CLIENT_H
#include <KDecoration2/Private/DecoratedClientPrivate>
#include <QObject>
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

View file

@ -0,0 +1,113 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#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 <KDecoration2/Decoration>
#include <KDecoration2/DecoratedClient>
#include <KDecoration2/DecorationSettings>
// Frameworks
#include <KPluginTrader>
#include <KPluginLoader>
// Qt
#include <QDebug>
#include <QPainter>
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<KWin::Decoration::DecorationBridge*>(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<Client*>(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<DecoratedClientImpl*>(decoration->client()->handle())->renderer()) {
renderer->schedule(geometry);
}
}
KDecoration2::Decoration *DecorationBridge::createDecoration(Client *client)
{
if (!m_factory) {
return nullptr;
}
return m_factory->create<KDecoration2::Decoration>(client);
}
} // Decoration
} // KWin

View file

@ -0,0 +1,58 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_DECORATION_BRIDGE_H
#define KWIN_DECORATION_BRIDGE_H
#include <KDecoration2/Private/DecorationBridge>
#include <QObject>
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

View file

@ -0,0 +1,134 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "decorationrenderer.h"
#include "decoratedclient.h"
#include "client.h"
#include <kwinglobals.h>
#include <KDecoration2/Decoration>
#include <KDecoration2/DecoratedClient>
#include <QDebug>
#include <QPainter>
#include <QTimer>
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<void (QTimer::*)()>(&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();
}
}
}

View file

@ -0,0 +1,94 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_DECORATION_RENDERER_H
#define KWIN_DECORATION_RENDERER_H
#include <QObject>
#include <QRegion>
#include <xcb/xcb.h>
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

77
decorations/settings.cpp Normal file
View file

@ -0,0 +1,77 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "settings.h"
// KWin
#include "composite.h"
#include "virtualdesktops.h"
#include <KDecoration2/DecorationSettings>
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 >({
KDecoration2::DecorationButtonType::Menu,
KDecoration2::DecorationButtonType::OnAllDesktops
});
}
QList< KDecoration2::DecorationButtonType > SettingsImpl::decorationButtonsRight() const
{
return QList<KDecoration2::DecorationButtonType >({
KDecoration2::DecorationButtonType::Minimize,
KDecoration2::DecorationButtonType::Maximize,
KDecoration2::DecorationButtonType::Close
});
}
}
}

46
decorations/settings.h Normal file
View file

@ -0,0 +1,46 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_DECORATION_SETTINGS_H
#define KWIN_DECORATION_SETTINGS_H
#include <KDecoration2/Private/DecorationSettingsPrivate>
#include <QObject>
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

View file

@ -23,7 +23,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "workspace.h" #include "workspace.h"
#include "client.h" #include "client.h"
#include "netinfo.h" #include "netinfo.h"
#include "paintredirector.h"
#include "shadow.h" #include "shadow.h"
#include <QDebug> #include <QDebug>
@ -43,7 +42,6 @@ Deleted::Deleted()
, m_layer(UnknownLayer) , m_layer(UnknownLayer)
, m_minimized(false) , m_minimized(false)
, m_modal(false) , m_modal(false)
, m_paintRedirector(NULL)
, m_wasClient(false) , m_wasClient(false)
{ {
} }
@ -88,21 +86,18 @@ void Deleted::copyToDeleted(Toplevel* c)
if (client) { if (client) {
m_wasClient = true; m_wasClient = true;
no_border = client->noBorder(); no_border = client->noBorder();
#if 0
padding_left = client->paddingLeft(); padding_left = client->paddingLeft();
padding_right = client->paddingRight(); padding_right = client->paddingRight();
padding_bottom = client->paddingBottom(); padding_bottom = client->paddingBottom();
padding_top = client->paddingTop(); padding_top = client->paddingTop();
#endif
if (!no_border) { if (!no_border) {
client->layoutDecorationRects(decoration_left, client->layoutDecorationRects(decoration_left,
decoration_top, decoration_top,
decoration_right, decoration_right,
decoration_bottom, decoration_bottom,
Client::WindowRelative); Client::WindowRelative);
if (PaintRedirector *redirector = client->decorationPaintRedirector()) {
redirector->ensurePixmapsPainted();
redirector->reparent(this);
m_paintRedirector = redirector;
}
} }
m_minimized = client->isMinimized(); m_minimized = client->isMinimized();
m_modal = client->isModal(); m_modal = client->isModal();

View file

@ -25,7 +25,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin namespace KWin
{ {
class PaintRedirector;
class Deleted class Deleted
: public Toplevel : public Toplevel
@ -64,9 +63,6 @@ public:
return m_mainClients; return m_mainClients;
} }
NET::WindowType windowType(bool direct = false, int supported_types = 0) const; NET::WindowType windowType(bool direct = false, int supported_types = 0) const;
PaintRedirector *decorationPaintRedirector() {
return m_paintRedirector;
}
bool wasClient() const { bool wasClient() const {
return m_wasClient; return m_wasClient;
} }
@ -97,7 +93,6 @@ private:
bool m_minimized; bool m_minimized;
bool m_modal; bool m_modal;
ClientList m_mainClients; ClientList m_mainClients;
PaintRedirector *m_paintRedirector;
bool m_wasClient; bool m_wasClient;
}; };

View file

@ -26,7 +26,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef KWIN_BUILD_ACTIVITIES #ifdef KWIN_BUILD_ACTIVITIES
#include "activities.h" #include "activities.h"
#endif #endif
#include "decorations.h"
#include "deleted.h" #include "deleted.h"
#include "client.h" #include "client.h"
#include "cursor.h" #include "cursor.h"
@ -492,17 +491,17 @@ void EffectsHandlerImpl::buildQuads(EffectWindow* w, WindowQuadList& quadList)
bool EffectsHandlerImpl::hasDecorationShadows() const bool EffectsHandlerImpl::hasDecorationShadows() const
{ {
return decorationPlugin()->hasShadows(); return false;
} }
bool EffectsHandlerImpl::decorationsHaveAlpha() const bool EffectsHandlerImpl::decorationsHaveAlpha() const
{ {
return decorationPlugin()->hasAlpha(); return true;
} }
bool EffectsHandlerImpl::decorationSupportsBlurBehind() const bool EffectsHandlerImpl::decorationSupportsBlurBehind() const
{ {
return decorationPlugin()->supportsBlurBehind(); return true;
} }
// start another painting pass // start another painting pass
@ -1441,7 +1440,7 @@ QVariant EffectsHandlerImpl::kwinOption(KWinOption kwopt)
{ {
switch (kwopt) { switch (kwopt) {
case CloseButtonCorner: case CloseButtonCorner:
return decorationPlugin()->closeButtonCorner(); return Qt::TopRightCorner;
#ifdef KWIN_BUILD_SCREENEDGES #ifdef KWIN_BUILD_SCREENEDGES
case SwitchDesktopOnScreenEdge: case SwitchDesktopOnScreenEdge:
return ScreenEdges::self()->isDesktopSwitching(); return ScreenEdges::self()->isDesktopSwitching();

View file

@ -27,7 +27,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "client.h" #include "client.h"
#include "cursor.h" #include "cursor.h"
#include "decorations.h"
#include "focuschain.h" #include "focuschain.h"
#include "netinfo.h" #include "netinfo.h"
#include "workspace.h" #include "workspace.h"
@ -47,6 +46,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "screens.h" #include "screens.h"
#include "xcbutils.h" #include "xcbutils.h"
#include <KDecoration2/Decoration>
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
#include <QWhatsThis> #include <QWhatsThis>
@ -312,25 +313,8 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
} }
} }
if (movingClient) { if (movingClient) {
if (eventType == XCB_BUTTON_PRESS || eventType == XCB_BUTTON_RELEASE) { if (eventType == XCB_BUTTON_PRESS || eventType == XCB_BUTTON_RELEASE || eventType == XCB_MOTION_NOTIFY) {
Client *c = movingClient;
if (movingClient->moveResizeGrabWindow() == reinterpret_cast<xcb_button_press_event_t*>(e)->event && movingClient->windowEvent(e)) { if (movingClient->moveResizeGrabWindow() == reinterpret_cast<xcb_button_press_event_t*>(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<xcb_button_release_event_t*>(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<const char*>(&event));
}
return true;
}
} else if (eventType == XCB_MOTION_NOTIFY) {
if (movingClient->moveResizeGrabWindow() == reinterpret_cast<xcb_motion_notify_event_t*>(e)->event && movingClient->windowEvent(e)) {
return true; return true;
} }
} }
@ -686,6 +670,14 @@ bool Client::windowEvent(xcb_generic_event_t *e)
case XCB_CLIENT_MESSAGE: case XCB_CLIENT_MESSAGE:
clientMessageEvent(reinterpret_cast<xcb_client_message_event_t*>(e)); clientMessageEvent(reinterpret_cast<xcb_client_message_event_t*>(e));
break; break;
case XCB_EXPOSE: {
xcb_expose_event_t *event = reinterpret_cast<xcb_expose_event_t*>(e);
if (event->window == frameId() && !Compositor::self()->isActive()) {
// TODO: only repaint required areas
triggerDecorationRepaint();
}
break;
}
default: default:
if (eventType == Xcb::Extensions::self()->shapeNotifyEvent() && reinterpret_cast<xcb_shape_notify_event_t*>(e)->affected_window == window()) { if (eventType == Xcb::Extensions::self()->shapeNotifyEvent() && reinterpret_cast<xcb_shape_notify_event_t*>(e)->affected_window == window()) {
detectShape(window()); // workaround for #19644 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) { static bool modKeyDown(int state) {
const uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ? const uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
KKeyServer::modXMeta() : KKeyServer::modXAlt(); KKeyServer::modXMeta() : KKeyServer::modXAlt();
@ -1111,7 +1044,7 @@ bool Client::buttonPressEvent(xcb_window_t w, int button, int state, int x, int
return true; 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 // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
updateUserTime(time); updateUserTime(time);
workspace()->setWasUserInteraction(); workspace()->setWasUserInteraction();
@ -1189,16 +1122,22 @@ bool Client::buttonPressEvent(xcb_window_t w, int button, int state, int x, int
return true; return true;
} }
if (w == inputId()) { if (w == inputId()) {
x = x_root - geometry().x() + padding_left; x = x_root - geometry().x();
y = y_root - geometry().y() + padding_top; y = y_root - geometry().y();
// New API processes core events FIRST and only passes unused ones to the decoration // 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); return processDecorationButtonPress(button, state, x, y, x_root, y_root, true);
} }
if (w == decorationId()) { if (w == frameId() && m_decoration) {
return false; 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; return true;
} }
@ -1225,7 +1164,7 @@ bool Client::processDecorationButtonPress(int button, int /*state*/, int x, int
&& com != Options::MouseDragTab) { && com != Options::MouseDragTab) {
mode = mousePosition(QPoint(x, y)); mode = mousePosition(QPoint(x, y));
buttonDown = true; buttonDown = true;
moveOffset = QPoint(x - padding_left, y - padding_top); moveOffset = QPoint(x/* - padding_left*/, y/* - padding_top*/);
invertedMoveOffset = rect().bottomRight() - moveOffset; invertedMoveOffset = rect().bottomRight() - moveOffset;
unrestrictedMoveResize = false; unrestrictedMoveResize = false;
startDelayedMoveResize(); startDelayedMoveResize();
@ -1246,40 +1185,19 @@ bool Client::processDecorationButtonPress(int button, int /*state*/, int x, int
com == Options::MouseNothing); 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 // 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) 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) if (w == frameId() && m_decoration) {
return false; 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()) { if (w == wrapperId()) {
xcb_allow_events(connection(), XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); //xTime()); xcb_allow_events(connection(), XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); //xTime());
return true; return true;
} }
if (w != frameId() && w != decorationId() && w != inputId() && w != moveResizeGrabWindow()) if (w != frameId() && w != inputId() && w != moveResizeGrabWindow())
return true; return true;
x = this->x(); // translate from grab window to local coords x = this->x(); // translate from grab window to local coords
y = this->y(); y = this->y();
@ -1299,10 +1217,9 @@ bool Client::buttonReleaseEvent(xcb_window_t w, int button, int state, int x, in
if (moveResizeMode) { if (moveResizeMode) {
finishMoveResize(false); finishMoveResize(false);
// mouse position is still relative to old Client position, adjust it // 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); mode = mousePosition(mousepos);
} else if (decorationPlugin()->supportsTabbing()) }
return false;
updateCursor(); updateCursor();
} }
return true; return true;
@ -1342,15 +1259,18 @@ void Client::checkQuickTilingMaximizationZones(int xroot, int yroot)
// return value matters only when filtering events before decoration gets them // 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) 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 return true; // care only about the whole frame
if (!buttonDown) { if (!buttonDown) {
QPoint mousePos(x, y); QPoint mousePos(x, y);
if (w == frameId())
mousePos += QPoint(padding_left, padding_top);
if (w == inputId()) { if (w == inputId()) {
int x = x_root - geometry().x() + padding_left; int x = x_root - geometry().x();// + padding_left;
int y = y_root - geometry().y() + padding_top; int y = y_root - geometry().y();// + padding_top;
mousePos = QPoint(x, y); mousePos = QPoint(x, y);
} }
Position newmode = modKeyDown(state) ? PositionCenter : mousePosition(mousePos); Position newmode = modKeyDown(state) ? PositionCenter : mousePosition(mousePos);

View file

@ -48,6 +48,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "outline.h" #include "outline.h"
#include <KDecoration2/Decoration>
#include <KDecoration2/DecoratedClient>
namespace KWin namespace KWin
{ {
@ -1239,8 +1242,8 @@ void Client::checkOffscreenPosition(QRect* geom, const QRect& screenArea)
QSize Client::adjustedSize(const QSize& frame, Sizemode mode) const QSize Client::adjustedSize(const QSize& frame, Sizemode mode) const
{ {
// first, get the window size for the given frame size s // first, get the window size for the given frame size s
QSize wsize(frame.width() - (border_left + border_right), QSize wsize(frame.width() - (borderLeft() + borderRight()),
frame.height() - (border_top + border_bottom)); frame.height() - (borderTop() + borderBottom()));
if (wsize.isEmpty()) if (wsize.isEmpty())
wsize = QSize(1, 1); 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() // even if they're not set in flags - see getWmNormalHints()
QSize min_size = tabGroup() ? tabGroup()->minSize() : minSize(); QSize min_size = tabGroup() ? tabGroup()->minSize() : minSize();
QSize max_size = tabGroup() ? tabGroup()->maxSize() : maxSize(); QSize max_size = tabGroup() ? tabGroup()->maxSize() : maxSize();
if (decoration != NULL) { if (m_decoration != NULL) {
QSize decominsize = decoration->minimumSize(); QSize decominsize(0, 0);
QSize border_size(border_left + border_right, border_top + border_bottom); QSize border_size(borderLeft() + borderRight(), borderTop() + borderBottom());
if (border_size.width() > decominsize.width()) // just in case if (border_size.width() > decominsize.width()) // just in case
decominsize.setWidth(border_size.width()); decominsize.setWidth(border_size.width());
if (border_size.height() > decominsize.height()) if (border_size.height() > decominsize.height())
@ -1424,8 +1427,8 @@ QSize Client::sizeForClientSize(const QSize& wsize, Sizemode mode, bool noframe)
} }
if (!noframe) { if (!noframe) {
w += border_left + border_right; w += borderLeft() + borderRight();
h += border_top + border_bottom; h += borderTop() + borderBottom();
} }
return rules()->checkSize(QSize(w, h)); return rules()->checkSize(QSize(w, h));
} }
@ -1556,19 +1559,19 @@ const QPoint Client::calculateGravitation(bool invert, int gravity) const
switch(gravity) { switch(gravity) {
case NorthWestGravity: // move down right case NorthWestGravity: // move down right
default: default:
dx = border_left; dx = borderLeft();
dy = border_top; dy = borderTop();
break; break;
case NorthGravity: // move right case NorthGravity: // move right
dx = 0; dx = 0;
dy = border_top; dy = borderTop();
break; break;
case NorthEastGravity: // move down left case NorthEastGravity: // move down left
dx = -border_right; dx = -borderRight();
dy = border_top; dy = borderTop();
break; break;
case WestGravity: // move right case WestGravity: // move right
dx = border_left; dx = borderLeft();
dy = 0; dy = 0;
break; break;
case CenterGravity: case CenterGravity:
@ -1578,30 +1581,30 @@ const QPoint Client::calculateGravitation(bool invert, int gravity) const
dy = 0; dy = 0;
break; break;
case EastGravity: // move left case EastGravity: // move left
dx = -border_right; dx = -borderRight();
dy = 0; dy = 0;
break; break;
case SouthWestGravity: // move up right case SouthWestGravity: // move up right
dx = border_left ; dx = borderLeft() ;
dy = -border_bottom; dy = -borderBottom();
break; break;
case SouthGravity: // move up case SouthGravity: // move up
dx = 0; dx = 0;
dy = -border_bottom; dy = -borderBottom();
break; break;
case SouthEastGravity: // move up left case SouthEastGravity: // move up left
dx = -border_right; dx = -borderRight();
dy = -border_bottom; dy = -borderBottom();
break; break;
} }
if (gravity != CenterGravity) { if (gravity != CenterGravity) {
// translate from client movement to frame movement // translate from client movement to frame movement
dx -= border_left; dx -= borderLeft();
dy -= border_top; dy -= borderTop();
} else { } else {
// center of the frame will be at the same position client center without frame would be // center of the frame will be at the same position client center without frame would be
dx = - (border_left + border_right) / 2; dx = - (borderLeft() + borderRight()) / 2;
dy = - (border_top + border_bottom) / 2; dy = - (borderTop() + borderBottom()) / 2;
} }
if (!invert) if (!invert)
return QPoint(x() + dx, y() + dy); return QPoint(x() + dx, y() + dy);
@ -1740,7 +1743,7 @@ void Client::resizeWithChecks(int w, int h, ForceGeometry_t force)
{ {
assert(!shade_geometry_change); assert(!shade_geometry_change);
if (isShade()) { if (isShade()) {
if (h == border_top + border_bottom) { if (h == borderTop() + borderBottom()) {
qWarning() << "Shaded geometry passed for size:" ; 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) if (shade_geometry_change)
; // nothing ; // nothing
else if (isShade()) { else if (isShade()) {
if (h == border_top + border_bottom) { if (h == borderTop() + borderBottom()) {
qDebug() << "Shaded geometry passed for size:"; qDebug() << "Shaded geometry passed for size:";
} else { } else {
client_size = QSize(w - border_left - border_right, h - border_top - border_bottom); client_size = QSize(w - borderLeft() - borderRight(), h - borderTop() - borderBottom());
h = border_top + border_bottom; h = borderTop() + borderBottom();
} }
} else { } 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); QRect g(x, y, w, h);
if (block_geometry_updates == 0 && g != rules()->checkGeometry(g)) { 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) if (shade_geometry_change)
; // nothing ; // nothing
else if (isShade()) { else if (isShade()) {
if (h == border_top + border_bottom) { if (h == borderTop() + borderBottom()) {
qDebug() << "Shaded geometry passed for size:"; qDebug() << "Shaded geometry passed for size:";
} else { } else {
client_size = QSize(w - border_left - border_right, h - border_top - border_bottom); client_size = QSize(w - borderLeft() - borderRight(), h - borderTop() - borderBottom());
h = border_top + border_bottom; h = borderTop() + borderBottom();
} }
} else { } 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); QSize s(w, h);
if (block_geometry_updates == 0 && s != rules()->checkSize(s)) { 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 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 // save sizes for restoring, if maximalizing
QSize sz; QSize sz;
if (isShade()) if (isShade())
@ -2234,7 +2250,7 @@ void Client::changeMaximize(bool vertical, bool horizontal, bool adjust)
changeMaximizeRecursion = false; 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 // Conditional quick tiling exit points
if (quick_tile_mode != QuickTileNone) { if (quick_tile_mode != QuickTileNone) {
@ -2692,12 +2708,12 @@ void Client::checkUnrestrictedMoveResize()
int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge; int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
// restricted move/resize - keep at least part of the titlebar always visible // restricted move/resize - keep at least part of the titlebar always visible
// how much must remain visible when moved away in that direction // how much must remain visible when moved away in that direction
left_marge = qMin(100 + border_right, moveResizeGeom.width()); left_marge = qMin(100 + borderRight(), moveResizeGeom.width());
right_marge = qMin(100 + border_left, moveResizeGeom.width()); right_marge = qMin(100 + borderLeft(), moveResizeGeom.width());
// width/height change with opaque resizing, use the initial ones // width/height change with opaque resizing, use the initial ones
titlebar_marge = initialMoveResizeGeom.height(); titlebar_marge = initialMoveResizeGeom.height();
top_marge = border_bottom; top_marge = borderBottom();
bottom_marge = border_top; bottom_marge = borderTop();
if (isResize()) { if (isResize()) {
if (moveResizeGeom.bottom() < desktopArea.top() + top_marge) if (moveResizeGeom.bottom() < desktopArea.top() + top_marge)
unrestrictedMoveResize = true; unrestrictedMoveResize = true;
@ -2760,7 +2776,7 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root)
return; return;
if (!moveResizeMode) { 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 (p.manhattanLength() >= QApplication::startDragDistance()) {
if (!startMoveResize()) { if (!startMoveResize()) {
buttonDown = false; 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 // 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. // 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()); int titlebarArea = qMin(frameTop * 100, moveResizeGeom.width() * moveResizeGeom.height());
bool update = false; 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.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 syncRequest.timeout->start(33); // and the client, the mouse is still moved at full speed
} // and no human can control faster resizes anyway } // 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 } else
performMoveResize(); performMoveResize();
@ -3156,7 +3172,7 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard)
if (mode != QuickTileNone) { if (mode != QuickTileNone) {
quick_tile_mode = mode; quick_tile_mode = mode;
// decorations may turn off some borders when tiled // 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 quick_tile_mode = QuickTileNone; // Temporary, so the maximize code doesn't get all confused
setGeometry(electricBorderMaximizeGeometry(keyboard ? geometry().center() : Cursor::pos(), desktop()), geom_mode); setGeometry(electricBorderMaximizeGeometry(keyboard ? geometry().center() : Cursor::pos(), desktop()), geom_mode);
} }
@ -3220,7 +3236,7 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard)
if (mode != QuickTileNone) { if (mode != QuickTileNone) {
quick_tile_mode = mode; quick_tile_mode = mode;
// decorations may turn off some borders when tiled // 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 // Temporary, so the maximize code doesn't get all confused
quick_tile_mode = QuickTileNone; quick_tile_mode = QuickTileNone;
setGeometry(electricBorderMaximizeGeometry(whichScreen, desktop()), geom_mode); 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 if (!geom_restore.isValid()) // invalid if we started maximized and wait for placement
geom_restore = geometry(); geom_restore = geometry();
// decorations may turn off some borders when tiled // 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); setGeometry(geom_restore, geom_mode);
checkWorkspacePosition(); // Just in case it's a different screen checkWorkspacePosition(); // Just in case it's a different screen
} }

View file

@ -29,7 +29,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "activities.h" #include "activities.h"
#endif #endif
#include "cursor.h" #include "cursor.h"
#include "decorations.h"
#include <QX11Info> #include <QX11Info>
#include "rules.h" #include "rules.h"
#include "group.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 // Create client group if the window will have a decoration
bool dontKeepInArea = false; bool dontKeepInArea = false;
setTabGroup(NULL); setTabGroup(NULL);
if (!noBorder() && DecorationPlugin::self()->supportsTabbing()) { if (!noBorder() && false) {
const bool autogrouping = rules()->checkAutogrouping(options->isAutogroupSimilarWindows()); const bool autogrouping = rules()->checkAutogrouping(options->isAutogroupSimilarWindows());
const bool autogroupInFg = rules()->checkAutogroupInForeground(options->isAutogroupInForeground()); const bool autogroupInFg = rules()->checkAutogroupInForeground(options->isAutogroupInForeground());
// Automatically add to previous groups on session restore // 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_EXPOSURE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; 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 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 | const uint32_t client_event_mask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE |

View file

@ -25,7 +25,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kdecorationfactory.h> #include <kdecorationfactory.h>
// kwin // kwin
#include "client.h" #include "client.h"
#include "decorations.h"
#include "virtualdesktops.h" #include "virtualdesktops.h"
#include "workspace.h" #include "workspace.h"
// Qt // Qt
@ -121,10 +120,6 @@ RootInfo *RootInfo::create()
NET::ActionChangeDesktop | NET::ActionChangeDesktop |
NET::ActionClose; 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); s_self = new RootInfo(supportWindow, "KWin", properties, types, states, properties2, actions, screen_number);
return s_self; return s_self;
} }

View file

@ -1,561 +0,0 @@
/*****************************************************************
This file is part of the KDE project.
Copyright (C) 2009 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
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 <kwinglplatform.h>
#include <kwinglutils.h>
#include <kwinxrenderutils.h>
#include <QPaintEngine>
#include <qevent.h>
#include <qpainter.h>
#include <qmath.h>
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 &region)
{
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 &region)
{
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 &reg)
{
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<const uint32_t *>(srcImage.bits());
uint32_t *dst = reinterpret_cast<uint32_t *>(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 &region)
{
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<PixmapCount; ++i) {
m_pixmaps[i] = XCB_PIXMAP_NONE;
m_pictures[i] = NULL;
}
resizePixmaps();
}
RasterXRenderPaintRedirector::~RasterXRenderPaintRedirector()
{
for (int i=0; i<PixmapCount; ++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);
}
}
xcb_render_picture_t RasterXRenderPaintRedirector::picture(PaintRedirector::DecorationPixmap border) const
{
XRenderPicture *picture = m_pictures[border];
if (!picture) {
return XCB_RENDER_PICTURE_NONE;
}
return *picture;
}
void RasterXRenderPaintRedirector::resize(PaintRedirector::DecorationPixmap border, const QSize &size)
{
if (m_sizes[border] != size) {
m_sizes[border] = size;
if (m_pixmaps[border] != XCB_PIXMAP_NONE) {
xcb_free_pixmap(connection(), 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 rect = {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, &rect);
}
void RasterXRenderPaintRedirector::preparePaint(const QPixmap &pending)
{
m_tempImage = pending.toImage();
}
void RasterXRenderPaintRedirector::paint(PaintRedirector::DecorationPixmap border, const QRect &r, const QRect &b, const QRegion &reg)
{
// clip the sub area
const QRect bounding = reg.boundingRect();
const QPoint offset = bounding.topLeft() - r.topLeft();
if (m_gc == 0) {
m_gc = xcb_generate_id(connection());
xcb_create_gc(connection(), m_gc, m_pixmaps[border], 0, NULL);
}
const QImage img(scratchImage().copy(QRect(bounding.topLeft() - b.topLeft(), bounding.size())));
xcb_put_image(connection(), XCB_IMAGE_FORMAT_Z_PIXMAP, m_pixmaps[border], m_gc,
img.width(), img.height(), offset.x(), offset.y(), 0, 32, img.byteCount(), img.constBits());
}
QImagePaintRedirector::QImagePaintRedirector(Client *c, KDecoration *deco)
: ImageBasedPaintRedirector(c, deco)
{
resizePixmaps();
}
QImagePaintRedirector::~QImagePaintRedirector()
{
}
void QImagePaintRedirector::paint(PaintRedirector::DecorationPixmap border, const QRect &r, const QRect &b, const QRegion &reg)
{
// clip the sub area
const QRect bounding = reg.boundingRect();
const QPoint offset = bounding.topLeft() - r.topLeft();
QPainter painter(&m_images[border]);
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.drawImage(offset, scratchImage(), QRect(bounding.topLeft() - b.topLeft(), bounding.size()));
}
void QImagePaintRedirector::resize(PaintRedirector::DecorationPixmap border, const QSize &size)
{
m_images[border] = QImage(size, QImage::Format_ARGB32_Premultiplied);
m_images[border].fill(Qt::transparent);
}
const QImage *QImagePaintRedirector::image(PaintRedirector::DecorationPixmap border) const
{
return &m_images[border];
}
} // namespace
#include "paintredirector.moc"

View file

@ -1,290 +0,0 @@
/*****************************************************************
This file is part of the KDE project.
Copyright (C) 2009 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
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 <qregion.h>
#include <qtimer.h>
#include <qwidget.h>
#include <qbasictimer.h>
// xcb
#include <xcb/render.h>
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 <typename T>
T topDecoPixmap() const;
template <typename T>
T leftDecoPixmap() const;
template <typename T>
T bottomDecoPixmap() const;
template <typename T>
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 &region);
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 &region);
virtual void paint(DecorationPixmap border, const QRect& r, const QRect &b, const QRegion &reg);
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 &region);
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 &reg);
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 &reg) 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

View file

@ -72,7 +72,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QVector2D> #include <QVector2D>
#include "client.h" #include "client.h"
#include "decorations.h"
#include "deleted.h" #include "deleted.h"
#include "effects.h" #include "effects.h"
#include "overlaywindow.h" #include "overlaywindow.h"
@ -264,7 +263,6 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
w->resetPaintingEnabled(); w->resetPaintingEnabled();
data.paint = region; data.paint = region;
data.paint |= topw->repaints(); data.paint |= topw->repaints();
data.paint |= topw->decorationPendingRegion();
// Reset the repaint_region. // Reset the repaint_region.
// This has to be done here because many effects schedule a repaint for // 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 const QRegion &Scene::Window::shape() const
{ {
if (!shape_valid) { if (!shape_valid) {
Client* c = dynamic_cast< Client* >(toplevel); if (toplevel->shape()) {
if (toplevel->shape() || (c != NULL && !c->mask().isEmpty())) {
auto cookie = xcb_shape_get_rectangles_unchecked(connection(), toplevel->frameId(), XCB_SHAPE_SK_BOUNDING); auto cookie = xcb_shape_get_rectangles_unchecked(connection(), toplevel->frameId(), XCB_SHAPE_SK_BOUNDING);
ScopedCPointer<xcb_shape_get_rectangles_reply_t> reply(xcb_shape_get_rectangles_reply(connection(), cookie, nullptr)); ScopedCPointer<xcb_shape_get_rectangles_reply_t> reply(xcb_shape_get_rectangles_reply(connection(), cookie, nullptr));
if (!reply.isNull()) { if (!reply.isNull()) {
@ -809,7 +806,7 @@ WindowQuadList Scene::Window::buildQuads(bool force) const
Client *client = dynamic_cast<Client*>(toplevel); Client *client = dynamic_cast<Client*>(toplevel);
QRegion contents = clientShape(); QRegion contents = clientShape();
QRegion center = toplevel->transparentRect(); QRegion center = toplevel->transparentRect();
QRegion decoration = (client && decorationPlugin()->hasAlpha() ? QRegion decoration = (client && true ?
QRegion(client->decorationRect()) : shape()) - center; QRegion(client->decorationRect()) : shape()) - center;
ret = makeQuads(WindowQuadContents, contents); ret = makeQuads(WindowQuadContents, contents);

View file

@ -30,6 +30,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin namespace KWin
{ {
namespace Decoration
{
class DecoratedClientImpl;
class Renderer;
}
class AbstractThumbnailItem; class AbstractThumbnailItem;
class Workspace; class Workspace;
class Deleted; class Deleted;
@ -134,6 +140,8 @@ public:
*/ */
virtual bool isLastFrameRendered() const = 0; virtual bool isLastFrameRendered() const = 0;
virtual Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *) = 0;
public Q_SLOTS: public Q_SLOTS:
// a window has been destroyed // a window has been destroyed
void windowDeleted(KWin::Deleted*); void windowDeleted(KWin::Deleted*);

View file

@ -44,9 +44,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "lanczosfilter.h" #include "lanczosfilter.h"
#include "main.h" #include "main.h"
#include "overlaywindow.h" #include "overlaywindow.h"
#include "paintredirector.h"
#include "screens.h" #include "screens.h"
#include "workspace.h" #include "workspace.h"
#include "decorations/decoratedclient.h"
#include <cmath> #include <cmath>
#include <unistd.h> #include <unistd.h>
@ -569,6 +569,11 @@ Shadow *SceneOpenGL::createShadow(Toplevel *toplevel)
return new SceneOpenGLShadow(toplevel); return new SceneOpenGLShadow(toplevel);
} }
Decoration::Renderer *SceneOpenGL::createDecorationRenderer(Decoration::DecoratedClientImpl *impl)
{
return new SceneOpenGLDecorationRenderer(impl);
}
//**************************************** //****************************************
// SceneOpenGL2 // SceneOpenGL2
//**************************************** //****************************************
@ -963,39 +968,23 @@ void SceneOpenGL::Window::endRenderWindow()
} }
} }
OpenGLPaintRedirector *SceneOpenGL::Window::paintRedirector() const
{
if (toplevel->isClient()) {
Client *client = static_cast<Client *>(toplevel);
if (client->noBorder())
return 0;
return static_cast<OpenGLPaintRedirector *>(client->decorationPaintRedirector());
}
if (toplevel->isDeleted()) {
Deleted *deleted = static_cast<Deleted *>(toplevel);
if (deleted->noBorder())
return 0;
return static_cast<OpenGLPaintRedirector *>(deleted->decorationPaintRedirector());
}
return 0;
}
GLTexture *SceneOpenGL::Window::getDecorationTexture() const GLTexture *SceneOpenGL::Window::getDecorationTexture() const
{ {
OpenGLPaintRedirector *redirector = paintRedirector(); // TODO: deleted
if (!redirector) if (toplevel->isClient()) {
return 0; Client *client = static_cast<Client *>(toplevel);
if (client->noBorder()) {
return nullptr;
}
redirector->ensurePixmapsPainted(); if (Decoration::DecoratedClientImpl *impl = client->decoratedClient()) {
GLTexture *texture = redirector->decorationTexture(); if (SceneOpenGLDecorationRenderer *renderer = static_cast<SceneOpenGLDecorationRenderer*>(impl->renderer())) {
redirector->markAsRepainted(); renderer->render();
return renderer->texture();
return texture; }
}
}
return nullptr;
} }
void SceneOpenGL::Window::paintDecorations(const WindowPaintData &data, const QRegion &region) void SceneOpenGL::Window::paintDecorations(const WindowPaintData &data, const QRegion &region)
@ -2009,4 +1998,104 @@ char SwapProfiler::end()
return 0; return 0;
} }
SceneOpenGLDecorationRenderer::SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl *client)
: Renderer(client)
, m_texture()
{
connect(this, &Renderer::renderScheduled, client->client(), static_cast<void (Client::*)(const QRect&)>(&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<const uint32_t *>(srcImage.bits());
uint32_t *dst = reinterpret_cast<uint32_t *>(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 } // namespace

View file

@ -28,12 +28,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "kwinglutils.h" #include "kwinglutils.h"
#include "kwingltexture_p.h" #include "kwingltexture_p.h"
#include "decorations/decorationrenderer.h"
namespace KWin namespace KWin
{ {
class ColorCorrection; class ColorCorrection;
class LanczosFilter; class LanczosFilter;
class OpenGLBackend; class OpenGLBackend;
class OpenGLPaintRedirector;
class SceneOpenGL class SceneOpenGL
: public Scene : public Scene
@ -58,6 +59,7 @@ public:
virtual bool makeOpenGLContextCurrent() override; virtual bool makeOpenGLContextCurrent() override;
virtual void doneOpenGLContextCurrent() override; virtual void doneOpenGLContextCurrent() override;
virtual bool isLastFrameRendered() const override; virtual bool isLastFrameRendered() const override;
Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override;
void idle(); void idle();
@ -238,9 +240,6 @@ protected:
protected: protected:
SceneOpenGL *m_scene; SceneOpenGL *m_scene;
bool m_hardwareClipping; bool m_hardwareClipping;
private:
OpenGLPaintRedirector *paintRedirector() const;
}; };
class SceneOpenGL2Window : public SceneOpenGL::Window class SceneOpenGL2Window : public SceneOpenGL::Window
@ -617,6 +616,31 @@ private:
QElapsedTimer m_renderTimer; 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<GLTexture> m_texture;
};
inline bool SceneOpenGL::hasPendingFlush() const inline bool SceneOpenGL::hasPendingFlush() const
{ {
return m_backend->hasPendingFlush(); return m_backend->hasPendingFlush();

View file

@ -24,16 +24,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "deleted.h" #include "deleted.h"
#include "effects.h" #include "effects.h"
#include "main.h" #include "main.h"
#include "paintredirector.h"
#include "toplevel.h" #include "toplevel.h"
#if HAVE_WAYLAND #if HAVE_WAYLAND
#include "wayland_backend.h" #include "wayland_backend.h"
#endif #endif
#include "workspace.h" #include "workspace.h"
#include "xcbutils.h" #include "xcbutils.h"
#include "decorations/decoratedclient.h"
// Qt // Qt
#include <QDebug> #include <QDebug>
#include <QPainter> #include <QPainter>
#include <KDecoration2/Decoration>
namespace KWin namespace KWin
{ {
@ -442,33 +443,31 @@ void SceneQPainter::Window::renderWindowDecorations(QPainter *painter)
} }
bool noBorder = true; bool noBorder = true;
PaintRedirector *redirector = NULL; SceneQPainterDecorationRenderer *renderer = nullptr;
QRect dtr, dlr, drr, dbr; QRect dtr, dlr, drr, dbr;
if (client && !client->noBorder()) { if (client && !client->noBorder()) {
redirector = client->decorationPaintRedirector(); if (Decoration::DecoratedClientImpl *impl = client->decoratedClient()) {
if (SceneQPainterDecorationRenderer *r = static_cast<SceneQPainterDecorationRenderer *>(impl->renderer())) {
renderer = r;
}
}
client->layoutDecorationRects(dlr, dtr, drr, dbr, Client::WindowRelative); client->layoutDecorationRects(dlr, dtr, drr, dbr, Client::WindowRelative);
noBorder = false; noBorder = false;
} else if (deleted && !deleted->noBorder()) { } else if (deleted && !deleted->noBorder()) {
noBorder = false; noBorder = false;
redirector = deleted->decorationPaintRedirector(); // TODO: renderer
deleted->layoutDecorationRects(dlr, dtr, drr, dbr); deleted->layoutDecorationRects(dlr, dtr, drr, dbr);
} }
if (noBorder || !redirector) { if (noBorder || !renderer) {
return; return;
} }
redirector->ensurePixmapsPainted(); renderer->render();
const QImage *left = redirector->leftDecoPixmap<const QImage *>();
const QImage *top = redirector->topDecoPixmap<const QImage *>();
const QImage *right = redirector->rightDecoPixmap<const QImage *>();
const QImage *bottom = redirector->bottomDecoPixmap<const QImage *>();
painter->drawImage(dtr, *top); painter->drawImage(dtr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Top));
painter->drawImage(dlr, *left); painter->drawImage(dlr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Left));
painter->drawImage(drr, *right); painter->drawImage(drr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Right));
painter->drawImage(dbr, *bottom); painter->drawImage(dbr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Bottom));
redirector->markAsRepainted();
} }
WindowPixmap *SceneQPainter::Window::createWindowPixmap() WindowPixmap *SceneQPainter::Window::createWindowPixmap()
@ -476,6 +475,11 @@ WindowPixmap *SceneQPainter::Window::createWindowPixmap()
return new QPainterWindowPixmap(this); return new QPainterWindowPixmap(this);
} }
Decoration::Renderer *SceneQPainter::createDecorationRenderer(Decoration::DecoratedClientImpl *impl)
{
return new SceneQPainterDecorationRenderer(impl);
}
//**************************************** //****************************************
// QPainterWindowPixmap // QPainterWindowPixmap
//**************************************** //****************************************
@ -615,4 +619,77 @@ bool SceneQPainterShadow::prepareBackend()
return true; return true;
} }
//****************************************
// QPainterDecorationRenderer
//****************************************
SceneQPainterDecorationRenderer::SceneQPainterDecorationRenderer(Decoration::DecoratedClientImpl *client)
: Renderer(client)
{
connect(this, &Renderer::renderScheduled, client->client(), static_cast<void (Client::*)(const QRect&)>(&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 } // KWin

View file

@ -23,6 +23,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "scene.h" #include "scene.h"
#include "shadow.h" #include "shadow.h"
#include "decorations/decorationrenderer.h"
namespace KWin { namespace KWin {
namespace Xcb { namespace Xcb {
@ -143,6 +145,7 @@ public:
virtual bool initFailed() const override; virtual bool initFailed() const override;
virtual EffectFrame *createEffectFrame(EffectFrameImpl *frame) override; virtual EffectFrame *createEffectFrame(EffectFrameImpl *frame) override;
virtual Shadow *createShadow(Toplevel *toplevel) override; virtual Shadow *createShadow(Toplevel *toplevel) override;
Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override;
QPainter *painter(); QPainter *painter();
@ -227,6 +230,29 @@ protected:
virtual bool prepareBackend() override; 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 inline
bool SceneQPainter::usesOverlayWindow() const bool SceneQPainter::usesOverlayWindow() const
{ {

View file

@ -26,18 +26,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "toplevel.h" #include "toplevel.h"
#include "client.h" #include "client.h"
#include "composite.h" #include "composite.h"
#include "decorations.h"
#include "deleted.h" #include "deleted.h"
#include "effects.h" #include "effects.h"
#include "main.h" #include "main.h"
#include "overlaywindow.h" #include "overlaywindow.h"
#include "paintredirector.h"
#include "workspace.h" #include "workspace.h"
#include "xcbutils.h" #include "xcbutils.h"
#include "kwinxrenderutils.h" #include "kwinxrenderutils.h"
#if HAVE_WAYLAND #if HAVE_WAYLAND
#include "wayland_backend.h" #include "wayland_backend.h"
#endif #endif
#include "decorations/decoratedclient.h"
#include <xcb/xfixes.h> #include <xcb/xfixes.h>
@ -466,6 +465,11 @@ Shadow *SceneXrender::createShadow(Toplevel *toplevel)
return new SceneXRenderShadow(toplevel); return new SceneXRenderShadow(toplevel);
} }
Decoration::Renderer *SceneXrender::createDecorationRenderer(Decoration::DecoratedClientImpl* client)
{
return new SceneXRenderDecorationRenderer(client);
}
//**************************************** //****************************************
// SceneXrender::Window // SceneXrender::Window
//**************************************** //****************************************
@ -611,7 +615,7 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat
Deleted *deleted = dynamic_cast<Deleted*>(toplevel); Deleted *deleted = dynamic_cast<Deleted*>(toplevel);
const QRect decorationRect = toplevel->decorationRect(); const QRect decorationRect = toplevel->decorationRect();
if (((client && !client->noBorder()) || (deleted && !deleted->noBorder())) && if (((client && !client->noBorder()) || (deleted && !deleted->noBorder())) &&
decorationPlugin()->hasAlpha()) { true) {
// decorated client // decorated client
transformed_shape = decorationRect; transformed_shape = decorationRect;
if (toplevel->shape()) { 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 top = XCB_RENDER_PICTURE_NONE;
xcb_render_picture_t right = XCB_RENDER_PICTURE_NONE; xcb_render_picture_t right = XCB_RENDER_PICTURE_NONE;
xcb_render_picture_t bottom = XCB_RENDER_PICTURE_NONE; xcb_render_picture_t bottom = XCB_RENDER_PICTURE_NONE;
PaintRedirector *redirector = NULL;
QRect dtr, dlr, drr, dbr; QRect dtr, dlr, drr, dbr;
if (client || deleted) { SceneXRenderDecorationRenderer *renderer = nullptr;
// TODO: deleted
if (client) {
if (client && !client->noBorder()) { if (client && !client->noBorder()) {
redirector = client->decorationPaintRedirector(); if (Decoration::DecoratedClientImpl *impl = client->decoratedClient()) {
renderer = static_cast<SceneXRenderDecorationRenderer*>(impl->renderer());
}
noBorder = client->noBorder(); noBorder = client->noBorder();
client->layoutDecorationRects(dlr, dtr, drr, dbr, Client::WindowRelative); client->layoutDecorationRects(dlr, dtr, drr, dbr, Client::WindowRelative);
} }
if (deleted && !deleted->noBorder()) { }
noBorder = deleted->noBorder(); if (renderer) {
redirector = deleted->decorationPaintRedirector(); renderer->render();
deleted->layoutDecorationRects(dlr, dtr, drr, dbr); left = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Left);
} top = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Top);
if (redirector) { right = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Right);
redirector->ensurePixmapsPainted(); bottom = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Bottom);
left = redirector->leftDecoPixmap<xcb_render_picture_t>(); }
top = redirector->topDecoPixmap<xcb_render_picture_t>(); if (!noBorder) {
right = redirector->rightDecoPixmap<xcb_render_picture_t>(); MAP_RECT_TO_TARGET(dtr);
bottom = redirector->bottomDecoPixmap<xcb_render_picture_t>(); MAP_RECT_TO_TARGET(dlr);
} MAP_RECT_TO_TARGET(drr);
if (!noBorder) { MAP_RECT_TO_TARGET(dbr);
MAP_RECT_TO_TARGET(dtr);
MAP_RECT_TO_TARGET(dlr);
MAP_RECT_TO_TARGET(drr);
MAP_RECT_TO_TARGET(dbr);
}
} }
//END deco preparations //END deco preparations
@ -860,9 +862,6 @@ xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, m_xrenderShadow->pic
renderDeco(right, drr); renderDeco(right, drr);
renderDeco(bottom, dbr); renderDeco(bottom, dbr);
} }
if (redirector) {
redirector->markAsRepainted();
}
} }
if (data.brightness() != 1.0) { if (data.brightness() != 1.0) {
@ -1307,6 +1306,115 @@ xcb_render_picture_t SceneXRenderShadow::picture(Shadow::ShadowElements element)
return *m_pictures[element]; return *m_pictures[element];
} }
SceneXRenderDecorationRenderer::SceneXRenderDecorationRenderer(Decoration::DecoratedClientImpl *client)
: Renderer(client)
, m_gc(XCB_NONE)
{
connect(this, &Renderer::renderScheduled, client->client(), static_cast<void (Client::*)(const QRect&)>(&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 DOUBLE_TO_FIXED
#undef FIXED_TO_DOUBLE #undef FIXED_TO_DOUBLE

View file

@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "scene.h" #include "scene.h"
#include "shadow.h" #include "shadow.h"
#include "decorations/decorationrenderer.h"
#ifdef KWIN_HAVE_XRENDER_COMPOSITING #ifdef KWIN_HAVE_XRENDER_COMPOSITING
@ -196,6 +197,7 @@ public:
virtual bool isLastFrameRendered() const { virtual bool isLastFrameRendered() const {
return m_backend->isLastFrameRendered(); return m_backend->isLastFrameRendered();
} }
Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *client);
static SceneXrender *createScene(); static SceneXrender *createScene();
protected: protected:
@ -337,6 +339,32 @@ private:
XRenderPicture* m_pictures[ShadowElementsCount]; 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 } // namespace
#endif #endif

View file

@ -21,7 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "tabgroup.h" #include "tabgroup.h"
#include "client.h" #include "client.h"
#include "decorations.h"
#include "effects.h" #include "effects.h"
#include "workspace.h" #include "workspace.h"
@ -63,7 +62,7 @@ bool TabGroup::add(Client* c, Client *other, bool after, bool becomeVisible)
{ {
Q_ASSERT(!c->tabGroup()); Q_ASSERT(!c->tabGroup());
if (!decorationPlugin()->supportsTabbing() || contains(c) || !contains(other)) if (contains(c) || !contains(other))
return false; return false;
// Tabbed windows MUST have a decoration // Tabbed windows MUST have a decoration

View file

@ -205,7 +205,6 @@ public:
virtual QRect visibleRect() const; // the area the window occupies on the screen virtual QRect visibleRect() const; // the area the window occupies on the screen
virtual QRect decorationRect() const; // rect including the decoration shadows virtual QRect decorationRect() const; // rect including the decoration shadows
virtual QRect transparentRect() const = 0; virtual QRect transparentRect() const = 0;
virtual QRegion decorationPendingRegion() const; // decoration region that needs to be repainted
virtual bool isClient() const; virtual bool isClient() const;
virtual bool isDeleted() const; virtual bool isDeleted() const;
@ -511,11 +510,6 @@ inline QRect Toplevel::rect() const
return QRect(0, 0, width(), height()); return QRect(0, 0, width(), height());
} }
inline QRegion Toplevel::decorationPendingRegion() const
{
return QRegion();
}
inline bool Toplevel::readyForPainting() const inline bool Toplevel::readyForPainting() const
{ {
return ready_for_painting; return ready_for_painting;

View file

@ -34,7 +34,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "useractions.h" #include "useractions.h"
#include "cursor.h" #include "cursor.h"
#include "client.h" #include "client.h"
#include "decorations.h"
#include "input.h" #include "input.h"
#include "workspace.h" #include "workspace.h"
#include "effects.h" #include "effects.h"
@ -337,7 +336,7 @@ void UserActionsMenu::init()
m_menu->addSeparator(); m_menu->addSeparator();
// Actions for window tabbing // Actions for window tabbing
if (decorationPlugin()->supportsTabbing()) { if (false) {
m_removeFromTabGroup = m_menu->addAction(i18n("&Untab")); m_removeFromTabGroup = m_menu->addAction(i18n("&Untab"));
setShortcut(m_removeFromTabGroup, QStringLiteral("Untab")); setShortcut(m_removeFromTabGroup, QStringLiteral("Untab"));
m_removeFromTabGroup->setData(Options::RemoveTabFromGroupOp); m_removeFromTabGroup->setData(Options::RemoveTabFromGroupOp);
@ -409,7 +408,7 @@ void UserActionsMenu::menuAboutToShow()
m_minimizeOperation->setEnabled(m_client.data()->isMinimizable()); m_minimizeOperation->setEnabled(m_client.data()->isMinimizable());
m_closeOperation->setEnabled(m_client.data()->isCloseable()); m_closeOperation->setEnabled(m_client.data()->isCloseable());
if (decorationPlugin()->supportsTabbing()) { if (false) {
initTabbingPopups(); initTabbingPopups();
m_addTabsMenu->setPalette(m_client.data()->palette()); m_addTabsMenu->setPalette(m_client.data()->palette());
} else { } else {

View file

@ -36,7 +36,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "composite.h" #include "composite.h"
#include "cursor.h" #include "cursor.h"
#include "dbusinterface.h" #include "dbusinterface.h"
#include "decorations.h"
#include "deleted.h" #include "deleted.h"
#include "effects.h" #include "effects.h"
#include "focuschain.h" #include "focuschain.h"
@ -63,6 +62,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif #endif
#include "xcbutils.h" #include "xcbutils.h"
#include "main.h" #include "main.h"
#include "decorations/decorationbridge.h"
// KDE // KDE
#include <KConfig> #include <KConfig>
#include <KConfigGroup> #include <KConfigGroup>
@ -171,7 +171,6 @@ Workspace::Workspace(bool restore)
options->loadConfig(); options->loadConfig();
options->loadCompositingConfig(false); options->loadCompositingConfig(false);
DecorationPlugin::create(this);
ColorMapper *colormaps = new ColorMapper(this); ColorMapper *colormaps = new ColorMapper(this);
connect(this, SIGNAL(clientActivated(KWin::Client*)), colormaps, SLOT(update())); connect(this, SIGNAL(clientActivated(KWin::Client*)), colormaps, SLOT(update()));
@ -213,7 +212,9 @@ Workspace::Workspace(bool restore)
XRenderUtils::init(connection(), rootWindow()); XRenderUtils::init(connection(), rootWindow());
m_compositor = Compositor::create(this); m_compositor = Compositor::create(this);
connect(this, SIGNAL(currentDesktopChanged(int,KWin::Client*)), m_compositor, SLOT(addRepaintFull())); 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); new DBusInterface(this);
@ -784,18 +785,6 @@ void Workspace::slotReconfigure()
m_userActionsMenu->discard(); m_userActionsMenu->discard();
updateToolWindows(true); 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(); RuleBook::self()->load();
for (ClientList::Iterator it = clients.begin(); for (ClientList::Iterator it = clients.begin();
it != clients.end(); it != clients.end();
@ -816,12 +805,6 @@ void Workspace::slotReconfigure()
(*it)->checkNoBorder(); (*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.width())
.arg(geo.height())); .arg(geo.height()));
} }
support.append(QStringLiteral("\nDecoration\n"));
support.append(QStringLiteral( "==========\n"));
support.append(decorationPlugin()->supportInformation());
support.append(QStringLiteral("\nCompositing\n")); support.append(QStringLiteral("\nCompositing\n"));
support.append(QStringLiteral( "===========\n")); support.append(QStringLiteral( "===========\n"));
if (effects) { if (effects) {