kwin/xcbutils.h
Martin Gräßlin 4bd28e90af [kwin] Do not allow Qt to raise decoration widget above the Client
If the user actions menu is closed Qt looks for a QWidget at the mouse
position. If it finds one it tries to activate and raise it. If the
QWidget at the mouse position is a window decoration, it gets raised
above the Client. This makes the window unfortunately unusable.

To prevent this from happening we listen for the ZOrderChange event
in our event filter on the decoration widget and unconditionally lower
the decoration widget again - we never want the decoration widget to
be above our Client, so we can just always lower it. We have to use
the low level functionality and cannot use QWidget::lower as that would
result in a loop.
2013-10-27 09:52:45 +01:00

914 lines
28 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2012, 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
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_XCB_UTILS_H
#define KWIN_XCB_UTILS_H
#include <kwinglobals.h>
#include "utils.h"
#include <QRect>
#include <QRegion>
#include <QVector>
#include <xcb/xcb.h>
#include <xcb/composite.h>
#include <xcb/randr.h>
namespace KWin {
namespace Xcb {
typedef xcb_window_t WindowId;
// forward declaration of methods
static void defineCursor(xcb_window_t window, xcb_cursor_t cursor);
static void setInputFocus(xcb_window_t window, uint8_t revertTo = XCB_INPUT_FOCUS_POINTER_ROOT, xcb_timestamp_t time = xTime());
static void moveWindow(xcb_window_t window, const QPoint &pos);
static void moveWindow(xcb_window_t window, uint32_t x, uint32_t y);
static void lowerWindow(xcb_window_t window);
static void selectInput(xcb_window_t window, uint32_t events);
template <typename Reply,
typename Cookie,
Reply *(*replyFunc)(xcb_connection_t*, Cookie, xcb_generic_error_t**),
Cookie (*requestFunc)(xcb_connection_t*, xcb_window_t)>
class Wrapper
{
public:
Wrapper()
: m_retrieved(false)
, m_window(XCB_WINDOW_NONE)
, m_reply(NULL)
{
m_cookie.sequence = 0;
}
explicit Wrapper(WindowId window)
: m_retrieved(false)
, m_cookie(requestFunc(connection(), window))
, m_window(window)
, m_reply(NULL)
{
}
explicit Wrapper(const Wrapper &other)
: m_retrieved(other.m_retrieved)
, m_cookie(other.m_cookie)
, m_window(other.m_window)
, m_reply(NULL)
{
takeFromOther(const_cast<Wrapper&>(other));
}
virtual ~Wrapper() {
cleanup();
}
inline Wrapper &operator=(const Wrapper &other) {
if (this != &other) {
// if we had managed a reply, free it
cleanup();
// copy members
m_retrieved = other.m_retrieved;
m_cookie = other.m_cookie;
m_window = other.m_window;
m_reply = other.m_reply;
// take over the responsibility for the reply pointer
takeFromOther(const_cast<Wrapper&>(other));
}
return *this;
}
inline const Reply *operator->() {
getReply();
return m_reply;
}
inline bool isNull() {
getReply();
return m_reply == NULL;
}
inline operator bool() {
return !isNull();
}
inline const Reply *data() {
getReply();
return m_reply;
}
inline WindowId window() const {
return m_window;
}
inline bool isRetrieved() const {
return m_retrieved;
}
/**
* Returns the value of the reply pointer referenced by this object. The reply pointer of
* this object will be reset to null. Calling any method which requires the reply to be valid
* will crash.
*
* Callers of this function take ownership of the pointer.
**/
inline Reply *take() {
getReply();
Reply *ret = m_reply;
m_reply = NULL;
m_window = XCB_WINDOW_NONE;
return ret;
}
protected:
void getReply() {
if (m_retrieved || !m_cookie.sequence) {
return;
}
m_reply = replyFunc(connection(), m_cookie, NULL);
m_retrieved = true;
}
private:
inline void cleanup() {
if (!m_retrieved && m_cookie.sequence) {
xcb_discard_reply(connection(), m_cookie.sequence);
} else if (m_reply) {
free(m_reply);
}
}
inline void takeFromOther(Wrapper &other) {
if (m_retrieved) {
m_reply = other.take();
} else {
//ensure that other object doesn't try to get the reply or discards it in the dtor
other.m_retrieved = true;
other.m_window = XCB_WINDOW_NONE;
}
}
bool m_retrieved;
Cookie m_cookie;
WindowId m_window;
Reply *m_reply;
};
class Atom
{
public:
explicit Atom(const QByteArray &name, bool onlyIfExists = false)
: m_retrieved(false)
, m_cookie(xcb_intern_atom_unchecked(connection(), onlyIfExists, name.length(), name.constData()))
, m_atom(XCB_ATOM_NONE)
, m_name(name)
{
}
Atom() = delete;
Atom(const Atom &) = delete;
~Atom() {
if (!m_retrieved && m_cookie.sequence) {
xcb_discard_reply(connection(), m_cookie.sequence);
}
}
operator xcb_atom_t() const {
(const_cast<Atom*>(this))->getReply();
return m_atom;
}
inline const QByteArray &name() const {
return m_name;
}
private:
void getReply() {
if (m_retrieved || !m_cookie.sequence) {
return;
}
ScopedCPointer<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(connection(), m_cookie, nullptr));
if (!reply.isNull()) {
m_atom = reply->atom;
}
m_retrieved = true;
}
bool m_retrieved;
xcb_intern_atom_cookie_t m_cookie;
xcb_atom_t m_atom;
QByteArray m_name;
};
typedef Wrapper<xcb_get_window_attributes_reply_t, xcb_get_window_attributes_cookie_t, &xcb_get_window_attributes_reply, &xcb_get_window_attributes_unchecked> WindowAttributes;
typedef Wrapper<xcb_composite_get_overlay_window_reply_t, xcb_composite_get_overlay_window_cookie_t, &xcb_composite_get_overlay_window_reply, &xcb_composite_get_overlay_window_unchecked> OverlayWindow;
class WindowGeometry : public Wrapper<xcb_get_geometry_reply_t, xcb_get_geometry_cookie_t, &xcb_get_geometry_reply, &xcb_get_geometry_unchecked>
{
public:
WindowGeometry() : Wrapper<xcb_get_geometry_reply_t, xcb_get_geometry_cookie_t, &xcb_get_geometry_reply, &xcb_get_geometry_unchecked>() {}
explicit WindowGeometry(xcb_window_t window) : Wrapper<xcb_get_geometry_reply_t, xcb_get_geometry_cookie_t, &xcb_get_geometry_reply, &xcb_get_geometry_unchecked>(window) {}
inline QRect rect() {
const xcb_get_geometry_reply_t *geometry = data();
if (!geometry) {
return QRect();
}
return QRect(geometry->x, geometry->y, geometry->width, geometry->height);
}
};
class Tree : public Wrapper<xcb_query_tree_reply_t, xcb_query_tree_cookie_t, &xcb_query_tree_reply, &xcb_query_tree_unchecked>
{
public:
explicit Tree(WindowId window) : Wrapper<xcb_query_tree_reply_t, xcb_query_tree_cookie_t, &xcb_query_tree_reply, &xcb_query_tree_unchecked>(window) {}
inline WindowId *children() {
return xcb_query_tree_children(data());
}
inline xcb_window_t parent() {
if (isNull())
return XCB_WINDOW_NONE;
return (*this)->parent;
}
};
inline xcb_get_input_focus_cookie_t get_input_focus(xcb_connection_t *c, xcb_window_t) {
return xcb_get_input_focus(c);
}
class CurrentInput : public Wrapper<xcb_get_input_focus_reply_t, xcb_get_input_focus_cookie_t, &xcb_get_input_focus_reply, &get_input_focus>
{
public:
CurrentInput() : Wrapper<xcb_get_input_focus_reply_t, xcb_get_input_focus_cookie_t, &xcb_get_input_focus_reply, &get_input_focus>(XCB_WINDOW_NONE) {}
inline xcb_window_t window() {
if (isNull())
return XCB_WINDOW_NONE;
return (*this)->focus;
}
};
inline xcb_get_property_cookie_t get_transient_for(xcb_connection_t *c, xcb_window_t window)
{
return xcb_get_property_unchecked(c, 0, window, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 0, 1);
}
class TransientFor : public Wrapper<xcb_get_property_reply_t, xcb_get_property_cookie_t, &xcb_get_property_reply, &get_transient_for>
{
public:
explicit TransientFor(WindowId window) : Wrapper<xcb_get_property_reply_t, xcb_get_property_cookie_t, &xcb_get_property_reply, &get_transient_for>(window) {}
/**
* @brief Fill given window pointer with the WM_TRANSIENT_FOR property of a window.
* @param prop WM_TRANSIENT_FOR property value.
* @returns @c true on success, @c false otherwise
**/
inline bool getTransientFor(WindowId *prop) {
if (isNull()) {
return false;
}
const xcb_get_property_reply_t *reply = data();
if (!reply || reply->type != XCB_ATOM_WINDOW || reply->format != 32 || reply->length == 0)
return false;
*prop = *reinterpret_cast<WindowId *>(xcb_get_property_value(reply));
return true;
}
};
namespace RandR
{
typedef Wrapper<xcb_randr_get_screen_info_reply_t, xcb_randr_get_screen_info_cookie_t, &xcb_randr_get_screen_info_reply, &xcb_randr_get_screen_info_unchecked> ScreenInfo;
class ScreenResources : public Wrapper<xcb_randr_get_screen_resources_reply_t, xcb_randr_get_screen_resources_cookie_t, &xcb_randr_get_screen_resources_reply, &xcb_randr_get_screen_resources_unchecked>
{
public:
explicit ScreenResources(WindowId window) : Wrapper<xcb_randr_get_screen_resources_reply_t, xcb_randr_get_screen_resources_cookie_t, &xcb_randr_get_screen_resources_reply, &xcb_randr_get_screen_resources_unchecked>(window) {}
inline xcb_randr_crtc_t *crtcs() {
if (isNull()) {
return nullptr;
}
return xcb_randr_get_screen_resources_crtcs(data());
}
};
class CrtcGamma : public Wrapper<xcb_randr_get_crtc_gamma_reply_t, xcb_randr_get_crtc_gamma_cookie_t, &xcb_randr_get_crtc_gamma_reply, &xcb_randr_get_crtc_gamma_unchecked>
{
public:
explicit CrtcGamma(xcb_randr_crtc_t c) : Wrapper<xcb_randr_get_crtc_gamma_reply_t, xcb_randr_get_crtc_gamma_cookie_t, &xcb_randr_get_crtc_gamma_reply, &xcb_randr_get_crtc_gamma_unchecked>(c) {}
inline uint16_t *red() {
return xcb_randr_get_crtc_gamma_red(data());
}
inline uint16_t *green() {
return xcb_randr_get_crtc_gamma_green(data());
}
inline uint16_t *blue() {
return xcb_randr_get_crtc_gamma_blue(data());
}
};
}
class ExtensionData
{
public:
ExtensionData();
int version;
int eventBase;
int errorBase;
int majorOpcode;
bool present;
QByteArray name;
};
class Extensions
{
public:
bool isShapeAvailable() const {
return m_shape.version > 0;
}
bool isShapeInputAvailable() const;
int shapeNotifyEvent() const;
bool hasShape(xcb_window_t w) const;
bool isRandrAvailable() const {
return m_randr.present;
}
int randrNotifyEvent() const;
bool isDamageAvailable() const {
return m_damage.present;
}
int damageNotifyEvent() const;
bool isCompositeAvailable() const {
return m_composite.version > 0;
}
bool isCompositeOverlayAvailable() const;
bool isRenderAvailable() const {
return m_render.version > 0;
}
bool isFixesAvailable() const {
return m_fixes.version > 0;
}
int fixesCursorNotifyEvent() const;
bool isFixesRegionAvailable() const;
bool isSyncAvailable() const {
return m_sync.present;
}
int syncAlarmNotifyEvent() const;
QVector<ExtensionData> extensions() const;
static Extensions *self();
static void destroy();
private:
Extensions();
~Extensions();
void init();
template <typename reply, typename T, typename F>
void initVersion(T cookie, F f, ExtensionData *dataToFill);
void extensionQueryReply(const xcb_query_extension_reply_t *extension, ExtensionData *dataToFill);
ExtensionData m_shape;
ExtensionData m_randr;
ExtensionData m_damage;
ExtensionData m_composite;
ExtensionData m_render;
ExtensionData m_fixes;
ExtensionData m_sync;
static Extensions *s_self;
};
/**
* This class is an RAII wrapper for an xcb_window_t. An xcb_window_t hold by an instance of this class
* will be freed when the instance gets destroyed.
*
* Furthermore the class provides wrappers around some xcb methods operating on an xcb_window_t.
*
* For the cases that one is more interested in wrapping the xcb methods the constructor which takes
* an existing window and the @link reset method allow to disable the RAII functionality.
**/
class Window
{
public:
/**
* Takes over responsibility of @p window. If @p window is not provided an invalid Window is
* created. Use @link create to set an xcb_window_t later on.
*
* If @p destroy is @c true the window will be destroyed together with this object, if @c false
* the window will be kept around. This is useful if you are not interested in the RAII capabilities
* but still want to use a window like an object.
*
* @param window The window to manage.
* @param destroy Whether the window should be destroyed together with the object.
* @see reset
**/
Window(xcb_window_t window = XCB_WINDOW_NONE, bool destroy = true);
/**
* Creates an xcb_window_t and manages it. It's a convenient method to create a window with
* depth, class and visual being copied from parent and border being @c 0.
* @param geometry The geometry for the window to be created
* @param mask The mask for the values
* @param values The values to be passed to xcb_create_window
* @param parent The parent window
**/
Window(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
/**
* Creates an xcb_window_t and manages it. It's a convenient method to create a window with
* depth and visual being copied from parent and border being @c 0.
* @param geometry The geometry for the window to be created
* @param class The window class
* @param mask The mask for the values
* @param values The values to be passed to xcb_create_window
* @param parent The parent window
**/
Window(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
Window(const Window &other) = delete;
~Window();
/**
* Creates a new window for which the responsibility is taken over. If a window had been managed
* before it is freed.
*
* Depth, class and visual are being copied from parent and border is @c 0.
* @param geometry The geometry for the window to be created
* @param mask The mask for the values
* @param values The values to be passed to xcb_create_window
* @param parent The parent window
**/
void create(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
/**
* Creates a new window for which the responsibility is taken over. If a window had been managed
* before it is freed.
*
* Depth and visual are being copied from parent and border is @c 0.
* @param geometry The geometry for the window to be created
* @param class The window class
* @param mask The mask for the values
* @param values The values to be passed to xcb_create_window
* @param parent The parent window
**/
void create(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
/**
* Frees the existing window and starts to manage the new @p window.
* If @p destroy is @c true the new managed window will be destroyed together with this
* object or when reset is called again. If @p destroy is @c false the window will not
* be destroyed. It is then the responsibility of the caller to destroy the window.
**/
void reset(xcb_window_t window = XCB_WINDOW_NONE, bool destroy = true);
/**
* @returns @c true if a window is managed, @c false otherwise.
**/
bool isValid() const;
/**
* Configures the window with a new geometry.
* @param geometry The new window geometry to be used
**/
void setGeometry(const QRect &geometry);
void setGeometry(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
void move(const QPoint &pos);
void move(uint32_t x, uint32_t y);
void resize(const QSize &size);
void resize(uint32_t width, uint32_t height);
void raise();
void lower();
void map();
void unmap();
void reparent(xcb_window_t parent, int x = 0, int y = 0);
void changeProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t lenght,
const void *data, uint8_t mode = XCB_PROP_MODE_REPLACE);
void deleteProperty(xcb_atom_t property);
void setBorderWidth(uint32_t width);
void grabButton(uint8_t pointerMode, uint8_t keyboardmode,
uint16_t modifiers = XCB_MOD_MASK_ANY,
uint8_t button = XCB_BUTTON_INDEX_ANY,
uint16_t eventMask = XCB_EVENT_MASK_BUTTON_PRESS,
xcb_window_t confineTo = XCB_WINDOW_NONE,
xcb_cursor_t cursor = XCB_CURSOR_NONE,
bool ownerEvents = false);
void ungrabButton(uint16_t modifiers = XCB_MOD_MASK_ANY, uint8_t button = XCB_BUTTON_INDEX_ANY);
/**
* Clears the window area. Same as xcb_clear_area with x, y, width, height being @c 0.
**/
void clear();
void setBackgroundPixmap(xcb_pixmap_t pixmap);
void defineCursor(xcb_cursor_t cursor);
void focus(uint8_t revertTo = XCB_INPUT_FOCUS_POINTER_ROOT, xcb_timestamp_t time = xTime());
void selectInput(uint32_t events);
void kill();
operator xcb_window_t() const;
private:
xcb_window_t doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
void destroy();
xcb_window_t m_window;
bool m_destroy;
};
inline
Window::Window(xcb_window_t window, bool destroy)
: m_window(window)
, m_destroy(destroy)
{
}
inline
Window::Window(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
: m_window(doCreate(geometry, XCB_COPY_FROM_PARENT, mask, values, parent))
, m_destroy(true)
{
}
inline
Window::Window(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
: m_window(doCreate(geometry, windowClass, mask, values, parent))
, m_destroy(true)
{
}
inline
Window::~Window()
{
destroy();
}
inline
void Window::destroy()
{
if (!isValid() || !m_destroy) {
return;
}
xcb_destroy_window(connection(), m_window);
m_window = XCB_WINDOW_NONE;
}
inline
bool Window::isValid() const
{
return m_window != XCB_WINDOW_NONE;
}
inline
Window::operator xcb_window_t() const
{
return m_window;
}
inline
void Window::create(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
{
destroy();
m_window = doCreate(geometry, windowClass, mask, values, parent);
}
inline
void Window::create(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
{
create(geometry, XCB_COPY_FROM_PARENT, mask, values, parent);
}
inline
xcb_window_t Window::doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
{
xcb_window_t w = xcb_generate_id(connection());
xcb_create_window(connection(), XCB_COPY_FROM_PARENT, w, parent,
geometry.x(), geometry.y(), geometry.width(), geometry.height(),
0, windowClass, XCB_COPY_FROM_PARENT, mask, values);
return w;
}
inline
void Window::reset(xcb_window_t window, bool shouldDestroy)
{
destroy();
m_window = window;
m_destroy = shouldDestroy;
}
inline
void Window::setGeometry(const QRect &geometry)
{
setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height());
}
inline
void Window::setGeometry(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{
if (!isValid()) {
return;
}
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const uint32_t values[] = { x, y, width, height };
xcb_configure_window(connection(), m_window, mask, values);
}
inline
void Window::move(const QPoint &pos)
{
move(pos.x(), pos.y());
}
inline
void Window::move(uint32_t x, uint32_t y)
{
if (!isValid()) {
return;
}
moveWindow(m_window, x, y);
}
inline
void Window::resize(const QSize &size)
{
resize(size.width(), size.height());
}
inline
void Window::resize(uint32_t width, uint32_t height)
{
if (!isValid()) {
return;
}
const uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const uint32_t values[] = { width, height };
xcb_configure_window(connection(), m_window, mask, values);
}
inline
void Window::raise()
{
const uint32_t values[] = { XCB_STACK_MODE_ABOVE };
xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_STACK_MODE, values);
}
inline
void Window::lower()
{
lowerWindow(m_window);
}
inline
void Window::map()
{
if (!isValid()) {
return;
}
xcb_map_window(connection(), m_window);
}
inline
void Window::unmap()
{
if (!isValid()) {
return;
}
xcb_unmap_window(connection(), m_window);
}
inline
void Window::reparent(xcb_window_t parent, int x, int y)
{
if (!isValid()) {
return;
}
xcb_reparent_window(connection(), m_window, parent, x, y);
}
inline
void Window::changeProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t lenght, const void *data, uint8_t mode)
{
if (!isValid()) {
return;
}
xcb_change_property(connection(), mode, m_window, property, type, format, lenght, data);
}
inline
void Window::deleteProperty(xcb_atom_t property)
{
if (!isValid()) {
return;
}
xcb_delete_property(connection(), m_window, property);
}
inline
void Window::setBorderWidth(uint32_t width)
{
if (!isValid()) {
return;
}
xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_BORDER_WIDTH, &width);
}
inline
void Window::grabButton(uint8_t pointerMode, uint8_t keyboardmode, uint16_t modifiers,
uint8_t button, uint16_t eventMask, xcb_window_t confineTo,
xcb_cursor_t cursor, bool ownerEvents)
{
if (!isValid()) {
return;
}
xcb_grab_button(connection(), ownerEvents, m_window, eventMask,
pointerMode, keyboardmode, confineTo, cursor, button, modifiers);
}
inline
void Window::ungrabButton(uint16_t modifiers, uint8_t button)
{
if (!isValid()) {
return;
}
xcb_ungrab_button(connection(), button, m_window, modifiers);
}
inline
void Window::clear()
{
if (!isValid()) {
return;
}
xcb_clear_area(connection(), false, m_window, 0, 0, 0, 0);
}
inline
void Window::setBackgroundPixmap(xcb_pixmap_t pixmap)
{
if (!isValid()) {
return;
}
const uint32_t values[] = {pixmap};
xcb_change_window_attributes(connection(), m_window, XCB_CW_BACK_PIXMAP, values);
}
inline
void Window::defineCursor(xcb_cursor_t cursor)
{
Xcb::defineCursor(m_window, cursor);
}
inline
void Window::focus(uint8_t revertTo, xcb_timestamp_t time)
{
setInputFocus(m_window, revertTo, time);
}
inline
void Window::selectInput(uint32_t events)
{
Xcb::selectInput(m_window, events);
}
inline
void Window::kill()
{
xcb_kill_client(connection(), m_window);
}
// helper functions
static inline void moveResizeWindow(WindowId window, const QRect &geometry)
{
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const uint32_t values[] = {
static_cast<uint32_t>(geometry.x()),
static_cast<uint32_t>(geometry.y()),
static_cast<uint32_t>(geometry.width()),
static_cast<uint32_t>(geometry.height())
};
xcb_configure_window(connection(), window, mask, values);
}
static inline void moveWindow(xcb_window_t window, const QPoint& pos)
{
moveWindow(window, pos.x(), pos.y());
}
static inline void moveWindow(xcb_window_t window, uint32_t x, uint32_t y)
{
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
const uint32_t values[] = { x, y };
xcb_configure_window(connection(), window, mask, values);
}
static inline void lowerWindow(xcb_window_t window)
{
const uint32_t values[] = { XCB_STACK_MODE_BELOW };
xcb_configure_window(connection(), window, XCB_CONFIG_WINDOW_STACK_MODE, values);
}
static inline WindowId createInputWindow(const QRect &geometry, uint32_t mask, const uint32_t *values)
{
WindowId window = xcb_generate_id(connection());
xcb_create_window(connection(), 0, window, rootWindow(),
geometry.x(), geometry.y(), geometry.width(), geometry.height(),
0, XCB_WINDOW_CLASS_INPUT_ONLY,
XCB_COPY_FROM_PARENT, mask, values);
return window;
}
static inline void restackWindows(const QVector<xcb_window_t> &windows)
{
if (windows.count() < 2) {
// only one window, nothing to do
return;
}
for (int i=1; i<windows.count(); ++i) {
const uint16_t mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE;
const uint32_t stackingValues[] = {
windows.at(i-1),
XCB_STACK_MODE_BELOW
};
xcb_configure_window(connection(), windows.at(i), mask, stackingValues);
}
}
static inline void restackWindowsWithRaise(const QVector<xcb_window_t> &windows)
{
if (windows.isEmpty()) {
return;
}
const uint32_t values[] = { XCB_STACK_MODE_ABOVE };
xcb_configure_window(connection(), windows.first(), XCB_CONFIG_WINDOW_STACK_MODE, values);
restackWindows(windows);
}
static inline int defaultDepth()
{
static int depth = 0;
if (depth != 0) {
return depth;
}
int screen = QX11Info::appScreen();
for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(connection()));
it.rem;
--screen, xcb_screen_next(&it)) {
if (screen == 0) {
depth = it.data->root_depth;
break;
}
}
return depth;
}
static inline xcb_rectangle_t fromQt(const QRect &rect)
{
xcb_rectangle_t rectangle;
rectangle.x = rect.x();
rectangle.y = rect.y();
rectangle.width = rect.width();
rectangle.height = rect.height();
return rectangle;
}
static inline QVector<xcb_rectangle_t> regionToRects(const QRegion &region)
{
const QVector<QRect> regionRects = region.rects();
QVector<xcb_rectangle_t> rects(regionRects.count());
for (int i=0; i<regionRects.count(); ++i) {
rects[i] = Xcb::fromQt(regionRects.at(i));
}
return rects;
}
static inline void defineCursor(xcb_window_t window, xcb_cursor_t cursor)
{
xcb_change_window_attributes(connection(), window, XCB_CW_CURSOR, &cursor);
}
static inline void setInputFocus(xcb_window_t window, uint8_t revertTo, xcb_timestamp_t time)
{
xcb_set_input_focus(connection(), revertTo, window, time);
}
static inline void setTransientFor(xcb_window_t window, xcb_window_t transient_for_window)
{
xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_TRANSIENT_FOR,
XCB_ATOM_WINDOW, 32, 1, &transient_for_window);
}
static inline void sync()
{
auto *c = connection();
const auto cookie = xcb_get_input_focus(c);
xcb_generic_error_t *error = nullptr;
ScopedCPointer<xcb_get_input_focus_reply_t> sync(xcb_get_input_focus_reply(c, cookie, &error));
if (error) {
free(error);
}
}
void selectInput(xcb_window_t window, uint32_t events)
{
xcb_change_window_attributes(connection(), window, XCB_CW_EVENT_MASK, &events);
}
} // namespace X11
} // namespace KWin
#endif // KWIN_X11_UTILS_H