Port non-composited Outline to XCB

Use xcb to create and manage the X11 backend of Outline. In addition the
used background pixmaps are rendered with XRender instead of using a
QPainter on a QPixmap. This is done because QPixmap is no longer bound to
an X Pixmap.

To create the XRender Picture the available functionality from
kwinxrenderutils is used. To be able to use it in KWin core the compile
option to build without XRender is removed for kwinxrenderutils, but
still supported for effects.

Obviously the port to XCB is not complete as xremderutils itself is still
on XLib.

REVIEW: 108642
This commit is contained in:
Martin Gräßlin 2013-01-28 14:17:12 +01:00
parent f238cbc3f5
commit 9f85f7f597
9 changed files with 139 additions and 141 deletions

View file

@ -21,8 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "kwinxrenderutils.h"
#include "kwinglobals.h"
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
#include <QStack>
#include <QVector>
#include <QPixmap>
@ -263,5 +261,3 @@ QPixmap *xRenderOffscreenTarget()
}
} // namespace
#endif

View file

@ -23,8 +23,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kwinconfig.h>
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
#include <QtCore/QSharedData>
#include <QtGui/QColor>
#include <ksharedptr.h>
@ -164,8 +162,6 @@ KWIN_EXPORT XRenderPicture *scene_xRenderOffscreenTarget();
} // namespace
#endif
/** @} */
#endif

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2011 Arthur Arlt <a.arlt@stud.uni-heidelberg.de>
Copyright (C) 2013 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
@ -17,13 +18,14 @@ 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/>.
*********************************************************************/
// own
#include "outline.h"
// KWin
#include "effects.h"
#include <QtCore/QRect>
#include <QtGui/QX11Info>
#include <QtGui/QPainter>
#include <X11/Xlib.h>
// KWin libs
#include <kwinxrenderutils.h>
// xcb
#include <xcb/render.h>
namespace KWin {
@ -35,12 +37,6 @@ Outline::Outline()
Outline::~Outline()
{
if (m_initialized) {
XDestroyWindow(QX11Info::display(), m_leftOutline);
XDestroyWindow(QX11Info::display(), m_rightOutline);
XDestroyWindow(QX11Info::display(), m_topOutline);
XDestroyWindow(QX11Info::display(), m_bottomOutline);
}
}
void Outline::show()
@ -63,7 +59,7 @@ void Outline::hide()
static_cast<EffectsHandlerImpl*>(effects)->slotHideOutline();
return; // done by effect
}
hideWithX();
forEachWindow(&Xcb::Window::unmap);
}
void Outline::show(const QRect& outlineGeometry)
@ -77,9 +73,9 @@ void Outline::setGeometry(const QRect& outlineGeometry)
m_outlineGeometry = outlineGeometry;
}
QVector< Window > Outline::windowIds() const
QVector< xcb_window_t > Outline::windowIds() const
{
QVector<Window> windows;
QVector<xcb_window_t> windows;
if (m_initialized) {
windows.reserve(4);
windows << m_leftOutline << m_topOutline << m_rightOutline << m_bottomOutline;
@ -90,113 +86,114 @@ QVector< Window > Outline::windowIds() const
void Outline::showWithX()
{
if (!m_initialized) {
XSetWindowAttributes attr;
attr.override_redirect = 1;
m_leftOutline = XCreateWindow(QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr);
m_rightOutline = XCreateWindow(QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr);
m_topOutline = XCreateWindow(QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr);
m_bottomOutline = XCreateWindow(QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr);
m_initialized = true;
const QRect geo(0, 0, 1, 1);
const uint32_t values[] = {true};
// TODO: use template variant
m_leftOutline.create(geo, XCB_CW_OVERRIDE_REDIRECT, values);
m_rightOutline.create(geo, XCB_CW_OVERRIDE_REDIRECT, values);
m_topOutline.create(geo, XCB_CW_OVERRIDE_REDIRECT, values);
m_bottomOutline.create(geo, XCB_CW_OVERRIDE_REDIRECT, values);
m_initialized = true;
}
int defaultDepth = XDefaultDepth(QX11Info::display(), QX11Info::appScreen());
int screen = QX11Info::appScreen();
int defaultDepth = 0;
// TODO: move into xcbutils or maybe kwinglobals
for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(connection()));
it.rem;
--screen, xcb_screen_next(&it)) {
if (screen == 0) {
defaultDepth = it.data->root_depth;
break;
}
}
// left/right parts are between top/bottom, they don't reach as far as the corners
XMoveResizeWindow(QX11Info::display(), m_leftOutline, m_outlineGeometry.x(), m_outlineGeometry.y() + 5, 5, m_outlineGeometry.height() - 10);
XMoveResizeWindow(QX11Info::display(), m_rightOutline, m_outlineGeometry.x() + m_outlineGeometry.width() - 5, m_outlineGeometry.y() + 5, 5, m_outlineGeometry.height() - 10);
XMoveResizeWindow(QX11Info::display(), m_topOutline, m_outlineGeometry.x(), m_outlineGeometry.y(), m_outlineGeometry.width(), 5);
XMoveResizeWindow(QX11Info::display(), m_bottomOutline, m_outlineGeometry.x(), m_outlineGeometry.y() + m_outlineGeometry.height() - 5, m_outlineGeometry.width(), 5);
{
Pixmap xpix = XCreatePixmap(display(), rootWindow(), 5,
m_outlineGeometry.height() - 10, defaultDepth);
QPixmap pix = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared);
QPainter p(&pix);
p.setPen(Qt::white);
p.drawLine(0, 0, 0, pix.height() - 1);
p.drawLine(4, 0, 4, pix.height() - 1);
p.setPen(Qt::gray);
p.drawLine(1, 0, 1, pix.height() - 1);
p.drawLine(3, 0, 3, pix.height() - 1);
p.setPen(Qt::black);
p.drawLine(2, 0, 2, pix.height() - 1);
p.end();
XSetWindowBackgroundPixmap(QX11Info::display(), m_leftOutline, pix.handle());
XSetWindowBackgroundPixmap(QX11Info::display(), m_rightOutline, pix.handle());
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
XFreePixmap (display(), xpix);
}
{
Pixmap xpix = XCreatePixmap(display(), rootWindow(), m_outlineGeometry.width(),
5, defaultDepth);
QPixmap pix = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared);
QPainter p(&pix);
p.setPen(Qt::white);
p.drawLine(0, 0, pix.width() - 1 - 0, 0);
p.drawLine(4, 4, pix.width() - 1 - 4, 4);
p.drawLine(0, 0, 0, 4);
p.drawLine(pix.width() - 1 - 0, 0, pix.width() - 1 - 0, 4);
p.setPen(Qt::gray);
p.drawLine(1, 1, pix.width() - 1 - 1, 1);
p.drawLine(3, 3, pix.width() - 1 - 3, 3);
p.drawLine(1, 1, 1, 4);
p.drawLine(3, 3, 3, 4);
p.drawLine(pix.width() - 1 - 1, 1, pix.width() - 1 - 1, 4);
p.drawLine(pix.width() - 1 - 3, 3, pix.width() - 1 - 3, 4);
p.setPen(Qt::black);
p.drawLine(2, 2, pix.width() - 1 - 2, 2);
p.drawLine(2, 2, 2, 4);
p.drawLine(pix.width() - 1 - 2, 2, pix.width() - 1 - 2, 4);
p.end();
XSetWindowBackgroundPixmap(QX11Info::display(), m_topOutline, pix.handle());
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
XFreePixmap (display(), xpix);
}
{
Pixmap xpix = XCreatePixmap(display(), rootWindow(), m_outlineGeometry.width(),
5, defaultDepth);
QPixmap pix = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared);
QPainter p(&pix);
p.setPen(Qt::white);
p.drawLine(4, 0, pix.width() - 1 - 4, 0);
p.drawLine(0, 4, pix.width() - 1 - 0, 4);
p.drawLine(0, 4, 0, 0);
p.drawLine(pix.width() - 1 - 0, 4, pix.width() - 1 - 0, 0);
p.setPen(Qt::gray);
p.drawLine(3, 1, pix.width() - 1 - 3, 1);
p.drawLine(1, 3, pix.width() - 1 - 1, 3);
p.drawLine(3, 1, 3, 0);
p.drawLine(1, 3, 1, 0);
p.drawLine(pix.width() - 1 - 3, 1, pix.width() - 1 - 3, 0);
p.drawLine(pix.width() - 1 - 1, 3, pix.width() - 1 - 1, 0);
p.setPen(Qt::black);
p.drawLine(2, 2, pix.width() - 1 - 2, 2);
p.drawLine(2, 0, 2, 2);
p.drawLine(pix.width() - 1 - 2, 0, pix.width() - 1 - 2, 2);
p.end();
XSetWindowBackgroundPixmap(QX11Info::display(), m_bottomOutline, pix.handle());
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
XFreePixmap (display(), xpix);
}
XClearWindow(QX11Info::display(), m_leftOutline);
XClearWindow(QX11Info::display(), m_rightOutline);
XClearWindow(QX11Info::display(), m_topOutline);
XClearWindow(QX11Info::display(), m_bottomOutline);
XMapWindow(QX11Info::display(), m_leftOutline);
XMapWindow(QX11Info::display(), m_rightOutline);
XMapWindow(QX11Info::display(), m_topOutline);
XMapWindow(QX11Info::display(), m_bottomOutline);
}
const uint16_t verticalWidth = 5;
const uint16_t verticalHeight = m_outlineGeometry.height() - 10;
const uint16_t horizontalWidth = m_outlineGeometry.width();
const uint horizontalHeight = 5;
m_leftOutline.setGeometry(m_outlineGeometry.x(), m_outlineGeometry.y() + 5, verticalWidth, verticalHeight);
m_rightOutline.setGeometry(m_outlineGeometry.x() + m_outlineGeometry.width() - 5, m_outlineGeometry.y() + 5, verticalWidth, verticalHeight);
m_topOutline.setGeometry(m_outlineGeometry.x(), m_outlineGeometry.y(), horizontalWidth, horizontalHeight);
m_bottomOutline.setGeometry(m_outlineGeometry.x(), m_outlineGeometry.y() + m_outlineGeometry.height() - 5, horizontalWidth, horizontalHeight);
void Outline::hideWithX()
{
XUnmapWindow(QX11Info::display(), m_leftOutline);
XUnmapWindow(QX11Info::display(), m_rightOutline);
XUnmapWindow(QX11Info::display(), m_topOutline);
XUnmapWindow(QX11Info::display(), m_bottomOutline);
const xcb_render_color_t white = {0xffff, 0xffff, 0xffff, 0xffff};
QColor qGray(Qt::gray);
const xcb_render_color_t gray = {
uint16_t(0xffff * qGray.redF()),
uint16_t(0xffff * qGray.greenF()),
uint16_t(0xffff * qGray.blueF()),
0xffff
};
const xcb_render_color_t black = {0, 0, 0, 0xffff};
{
xcb_pixmap_t xpix = xcb_generate_id(connection());
xcb_create_pixmap(connection(), defaultDepth, xpix, rootWindow(), verticalWidth, verticalHeight);
XRenderPicture pic(xpix, defaultDepth);
xcb_rectangle_t rect = {0, 0, 5, verticalHeight};
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, white, 1, &rect);
rect.x = 1;
rect.width = 3;
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, gray, 1, &rect);
rect.x = 2;
rect.width = 1;
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, black, 1, &rect);
m_leftOutline.setBackgroundPixmap(xpix);
m_rightOutline.setBackgroundPixmap(xpix);
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
xcb_free_pixmap(connection(), xpix);
}
{
xcb_pixmap_t xpix = xcb_generate_id(connection());
xcb_create_pixmap(connection(), defaultDepth, xpix, rootWindow(), horizontalWidth, horizontalHeight);
XRenderPicture pic(xpix, defaultDepth);
xcb_rectangle_t rect = {0, 0, horizontalWidth, horizontalHeight};
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, white, 1, &rect);
xcb_rectangle_t grayRects[] = {
{1, 1, uint16_t(horizontalWidth -2), 3},
{1, 4, 3, 1},
{int16_t(horizontalWidth - 4), 4, 3, 1}
};
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, gray, 3, grayRects);
xcb_rectangle_t blackRects[] = {
{2, 2, uint16_t(horizontalWidth -4), 1},
{2, 3, 1, 2},
{int16_t(horizontalWidth - 3), 3, 1, 2}
};
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, black, 3, blackRects);
m_topOutline.setBackgroundPixmap(xpix);
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
xcb_free_pixmap(connection(), xpix);
}
{
xcb_pixmap_t xpix = xcb_generate_id(connection());
xcb_create_pixmap(connection(), defaultDepth, xpix, rootWindow(), m_outlineGeometry.width(), 5);
XRenderPicture pic(xpix, defaultDepth);
xcb_rectangle_t rect = {0, 0, horizontalWidth, horizontalHeight};
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, white, 1, &rect);
xcb_rectangle_t grayRects[] = {
{1, 1, uint16_t(horizontalWidth -2), 3},
{1, 0, 3, 1},
{int16_t(horizontalWidth - 4), 0, 3, 1}
};
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, gray, 3, grayRects);
xcb_rectangle_t blackRects[] = {
{2, 2, uint16_t(horizontalWidth -4), 1},
{2, 0, 1, 2},
{int16_t(horizontalWidth - 3), 0, 1, 2}
};
xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, pic, black, 3, blackRects);
m_bottomOutline.setBackgroundPixmap(xpix);
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
xcb_free_pixmap(connection(), xpix);
}
forEachWindow(&Xcb::Window::clear);
forEachWindow(&Xcb::Window::map);
}
} // namespace

View file

@ -20,8 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_OUTLINE_H
#define KWIN_OUTLINE_H
#include <X11/X.h>
#include <fixx11h.h>
#include "xcbutils.h"
#include <QtCore/QRect>
#include <QtCore/QVector>
@ -77,7 +76,7 @@ public:
* Return outline window ids
* @return The window ids created to represent the outline
*/
QVector<Window> windowIds() const;
QVector<xcb_window_t> windowIds() const;
private:
/**
@ -85,20 +84,29 @@ private:
*/
void showWithX();
/**
* Hide previously shown outline used the X implementation
*/
void hideWithX();
// TODO: variadic template arguments for adding method arguments
template <typename T>
void forEachWindow(T method);
Window m_topOutline;
Window m_rightOutline;
Window m_bottomOutline;
Window m_leftOutline;
Xcb::Window m_topOutline;
Xcb::Window m_rightOutline;
Xcb::Window m_bottomOutline;
Xcb::Window m_leftOutline;
QRect m_outlineGeometry;
bool m_initialized;
bool m_active;
};
template <typename T>
inline
void Outline::forEachWindow(T method)
{
(m_topOutline.*method)();
(m_rightOutline.*method)();
(m_bottomOutline.*method)();
(m_leftOutline.*method)();
}
}
#endif

View file

@ -326,7 +326,7 @@ void TabBoxHandlerImpl::hideOutline()
Workspace::self()->outline()->hide();
}
QVector< Window > TabBoxHandlerImpl::outlineWindowIds() const
QVector< xcb_window_t > TabBoxHandlerImpl::outlineWindowIds() const
{
return Workspace::self()->outline()->windowIds();
}

View file

@ -64,7 +64,7 @@ public:
virtual QWeakPointer< TabBoxClient > desktopClient() const;
virtual void hideOutline();
virtual void showOutline(const QRect &outline);
virtual QVector< Window > outlineWindowIds() const;
virtual QVector< xcb_window_t > outlineWindowIds() const;
virtual void activateAndClose();
private:

View file

@ -186,7 +186,7 @@ void TabBoxHandlerPrivate::updateHighlightWindows()
}
data[ 0 ] = currentClient ? currentClient->window() : 0L;
if (config.isShowOutline()) {
QVector<Window> outlineWindows = q->outlineWindowIds();
QVector<xcb_window_t> outlineWindows = q->outlineWindowIds();
data.resize(2+outlineWindows.size());
for (int i=0; i<outlineWindows.size(); ++i) {
data[2+i] = outlineWindows[i];

View file

@ -28,6 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QString>
#include <X11/Xlib.h>
#include <fixx11h.h>
#include <xcb/xcb.h>
/**
* @file
@ -351,7 +352,7 @@ protected:
* @return The outline window ids given in the order left, top, right, bottom
* @since 4.7
**/
virtual QVector<Window> outlineWindowIds() const = 0;
virtual QVector<xcb_window_t> outlineWindowIds() const = 0;
signals:
/**

View file

@ -68,8 +68,8 @@ public:
virtual int numberOfDesktops() const {
return 1;
}
virtual QVector< Window > outlineWindowIds() const {
return QVector<Window>();
virtual QVector< xcb_window_t > outlineWindowIds() const {
return QVector<xcb_window_t>();
}
virtual void raiseClient(TabBox::TabBoxClient *c) const {
Q_UNUSED(c)