#include "qxcbwindow.h"
#include "qxcbclipboard.h"
#include "qxcbdrag.h"
+#include "qxcbwmsupport.h"
#include <QtAlgorithms>
#include <QSocketNotifier>
xcb_screen_next(&it);
}
+ m_wmSupport = new QXcbWMSupport(this);
m_keyboard = new QXcbKeyboard(this);
m_clipboard = new QXcbClipboard(this);
m_drag = new QXcbDrag(this);
{ \
event_t *e = (event_t *)event; \
if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) \
- m_keyboard->handler(platformWindow->window(), e); \
+ m_keyboard->handler(platformWindow, e); \
} \
break;
xcb_generic_event_t *event = eventqueue.at(i);
if (!event)
continue;
+ eventqueue[i] = 0;
uint response_type = event->response_type & ~0x80;
QByteArray QXcbConnection::atomName(xcb_atom_t atom)
{
- xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name_unchecked(xcb_connection(), atom));
- xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, 0);
+ if (!atom)
+ return QByteArray();
+
+ xcb_generic_error_t *error = 0;
+ xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name(xcb_connection(), atom));
+ xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, &error);
+ if (error) {
+ qWarning() << "QXcbConnection::atomName: bad Atom" << atom;
+ }
if (reply) {
QByteArray result(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
free(reply);
class QXcbDrag;
class QXcbKeyboard;
class QXcbClipboard;
+class QXcbWMSupport;
typedef QHash<xcb_window_t, QXcbWindow *> WindowMapper;
static const xcb_atom_t XA_BITMAP = 5;
static const xcb_atom_t XA_STRING = 32;
static const xcb_atom_t XA_WINDOW = 33;
+ static const xcb_atom_t XA_CARDINAL = 6;
enum Atom {
// window-manager <-> client protocols
QXcbClipboard *clipboard() const { return m_clipboard; }
QXcbDrag *drag() const { return m_drag; }
+ QXcbWMSupport *wmSupport() const { return m_wmSupport; }
+
#ifdef XCB_USE_XLIB
void *xlib_display() const { return m_xlib_display; }
#endif
template<typename T>
inline xcb_generic_event_t *checkEvent(const T &checker);
- QXcbWindow *platformWindowFromId(xcb_window_t id);
-
typedef bool (*PeekFunc)(xcb_generic_event_t *);
void addPeekFunc(PeekFunc f);
QXcbKeyboard *m_keyboard;
QXcbClipboard *m_clipboard;
QXcbDrag *m_drag;
+ QXcbWMSupport *m_wmSupport;
#if defined(XCB_USE_XLIB)
void *m_xlib_display;
****************************************************************************/
#include "qxcbkeyboard.h"
+#include "qxcbwindow.h"
#include <xcb/xcb_keysyms.h>
QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, code, 0, state, string.left(count));
}
-void QXcbKeyboard::handleKeyPressEvent(QWindow *window, const xcb_key_press_event_t *event)
+void QXcbKeyboard::handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event)
{
- handleKeyEvent(window, QEvent::KeyPress, event->detail, event->state, event->time);
+ window->updateNetWmUserTime(event->time);
+ handleKeyEvent(window->window(), QEvent::KeyPress, event->detail, event->state, event->time);
}
-void QXcbKeyboard::handleKeyReleaseEvent(QWindow *window, const xcb_key_release_event_t *event)
+void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event)
{
- handleKeyEvent(window, QEvent::KeyRelease, event->detail, event->state, event->time);
+ handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time);
}
void QXcbKeyboard::handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event)
QXcbKeyboard(QXcbConnection *connection);
~QXcbKeyboard();
- void handleKeyPressEvent(QWindow *window, const xcb_key_press_event_t *event);
- void handleKeyReleaseEvent(QWindow *window, const xcb_key_release_event_t *event);
+ void handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event);
+ void handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event);
void handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event);
#include "qxcbconnection.h"
#include "qxcbscreen.h"
#include "qxcbdrag.h"
-
+#include "qxcbwmsupport.h"
#ifdef XCB_USE_DRI2
#include "qdri2context.h"
, m_context(0)
, m_syncCounter(0)
, m_mapped(false)
+ , m_netWmUserTimeWindow(XCB_NONE)
{
m_screen = static_cast<QXcbScreen *>(QGuiApplicationPrivate::platformIntegration()->screens().at(0));
setNetWmState(netWmState);
}
+void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
+{
+ xcb_window_t wid = m_window;
+
+ const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
+ if (m_netWmUserTimeWindow || isSupportedByWM) {
+ if (!m_netWmUserTimeWindow) {
+ m_netWmUserTimeWindow = xcb_generate_id(xcb_connection());
+ Q_XCB_CALL(xcb_create_window(xcb_connection(),
+ XCB_COPY_FROM_PARENT, // depth -- same as root
+ m_netWmUserTimeWindow, // window id
+ m_window, // parent window id
+ -1, -1, 1, 1,
+ 0, // border width
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
+ m_screen->screen()->root_visual, // visual
+ 0, // value mask
+ 0)); // value list
+ wid = m_netWmUserTimeWindow;
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW),
+ QXcbAtom::XA_WINDOW, 32, 1, &m_netWmUserTimeWindow);
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME));
+ } else if (!isSupportedByWM) {
+ // WM no longer supports it, then we should remove the
+ // _NET_WM_USER_TIME_WINDOW atom.
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
+ xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
+ m_netWmUserTimeWindow = XCB_NONE;
+ } else {
+ wid = m_netWmUserTimeWindow;
+ }
+ }
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::_NET_WM_USER_TIME),
+ QXcbAtom::XA_CARDINAL, 32, 1, ×tamp);
+}
+
+
WId QXcbWindow::winId() const
{
return m_window;
void QXcbWindow::requestActivateWindow()
{
if (m_mapped){
- Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME));
- connection()->sync();
+ updateNetWmUserTime(connection()->time());
+ Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time()));
}
+ connection()->sync();
}
QPlatformGLContext *QXcbWindow::glContext() const
return;
if (event->type == atom(QXcbAtom::WM_PROTOCOLS)) {
+ qDebug() << "WM_PROTO" << m_window << connection()->atomName(event->data.data32[0]);
if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) {
QWindowSystemInterface::handleCloseEvent(window());
} else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) {
connection()->setTime(event->data.data32[1]);
- // ### handle take focus!
+ requestActivateWindow();
} else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
xcb_client_message_event_t reply = *event;
}
m_syncValue.lo = event->data.data32[2];
m_syncValue.hi = event->data.data32[3];
+ } else {
+ qWarning() << "unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]);
}
} else if (event->type == atom(QXcbAtom::XdndEnter)) {
connection()->drag()->handleEnter(window(), event);
connection()->drag()->handleLeave(window(), event, false);
} else if (event->type == atom(QXcbAtom::XdndDrop)) {
connection()->drag()->handleDrop(window(), event, false);
+ } else {
+ qWarning() << "unhandled client message:" << connection()->atomName(event->type);
}
}
void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
{
+ updateNetWmUserTime(event->time);
+
QPoint local(event->event_x, event->event_y);
QPoint global(event->root_x, event->root_y);
void handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global);
void updateSyncRequestCounter();
+ void updateNetWmUserTime(xcb_timestamp_t timestamp);
+ void netWmUserTime() const;
private:
void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0);
void updateMotifWmHintsBeforeMap();
void updateNetWmStateBeforeMap();
+
void create();
void destroy();
Qt::WindowState m_windowState;
bool m_mapped;
+ xcb_window_t m_netWmUserTimeWindow;
};
#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qxcbwmsupport.h"
+#include "qxcbscreen.h"
+
+#include <qdebug.h>
+
+QXcbWMSupport::QXcbWMSupport(QXcbConnection *c)
+ : QXcbObject(c)
+{
+ updateNetWMAtoms();
+ updateVirtualRoots();
+}
+
+bool QXcbWMSupport::isSupportedByWM(xcb_atom_t atom) const
+{
+ return net_wm_atoms.contains(atom);
+}
+
+
+
+void QXcbWMSupport::updateNetWMAtoms()
+{
+ net_wm_atoms.clear();
+
+ xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root();
+ int offset = 0;
+ int remaining = 0;
+ do {
+ xcb_generic_error_t *error = 0;
+ xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_SUPPORTED), QXcbAtom::XA_ATOM, offset, 1024);
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, &error);
+ if (!reply || error)
+ break;
+
+ remaining = 0;
+
+ if (reply->type == QXcbAtom::XA_ATOM && reply->format == 32) {
+ int len = xcb_get_property_value_length(reply)/4;
+ xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply);
+ int s = net_wm_atoms.size();
+ net_wm_atoms.resize(s + len);
+ memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t));
+
+ remaining = reply->bytes_after;
+ offset += len;
+ }
+
+ free(reply);
+ } while (remaining > 0);
+
+// qDebug() << "======== updateNetWMAtoms";
+// for (int i = 0; i < net_wm_atoms.size(); ++i)
+// qDebug() << atomName(net_wm_atoms.at(i));
+// qDebug() << "======== updateNetWMAtoms";
+}
+
+// update the virtual roots array
+void QXcbWMSupport::updateVirtualRoots()
+{
+ net_virtual_roots.clear();
+
+ if (!isSupportedByWM(atom(QXcbAtom::_NET_VIRTUAL_ROOTS)))
+ return;
+
+ xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root();
+ int offset = 0;
+ int remaining = 0;
+ do {
+ xcb_generic_error_t *error = 0;
+ xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_VIRTUAL_ROOTS), QXcbAtom::XA_ATOM, offset, 1024);
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, &error);
+ if (!reply || error)
+ break;
+
+ remaining = 0;
+
+ if (reply->type == QXcbAtom::XA_ATOM && reply->format == 32) {
+ int len = xcb_get_property_value_length(reply)/4;
+ xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply);
+ int s = net_wm_atoms.size();
+ net_wm_atoms.resize(s + len);
+ memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t));
+
+ remaining = reply->bytes_after;
+ offset += len;
+ }
+
+ free(reply);
+ } while (remaining > 0);
+
+ qDebug() << "======== updateVirtualRoots";
+ for (int i = 0; i < net_virtual_roots.size(); ++i)
+ qDebug() << connection()->atomName(net_virtual_roots.at(i));
+ qDebug() << "======== updateVirtualRoots";
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QXCBWMSUPPORT_H
+#define QXCBWMSUPPORT_H
+
+#include "qxcbobject.h"
+#include "qxcbconnection.h"
+#include <qvector.h>
+
+class QXcbWMSupport : public QXcbObject
+{
+public:
+ QXcbWMSupport(QXcbConnection *c);
+
+
+ bool isSupportedByWM(xcb_atom_t atom) const;
+ const QVector<xcb_window_t> &virtualRoots() const { return net_virtual_roots; }
+
+private:
+ friend class QXcbConnection;
+ void updateNetWMAtoms();
+ void updateVirtualRoots();
+
+ QVector<xcb_atom_t> net_wm_atoms;
+ QVector<xcb_window_t> net_virtual_roots;
+};
+
+
+#endif
qxcbscreen.cpp \
qxcbwindow.cpp \
qxcbwindowsurface.cpp \
+ qxcbwmsupport.cpp \
main.cpp \
qxcbnativeinterface.cpp
qxcbscreen.h \
qxcbwindow.h \
qxcbwindowsurface.h \
+ qxcbwmsupport.h \
qxcbnativeinterface.h
QT += gui-private core-private