summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@digia.com>2013-09-11 17:51:46 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-17 14:57:03 +0200
commit2b20ed5af4d10533a14477750c7572ef09e60005 (patch)
tree5ce153089da4aa30184aaae2ece1aa5741ddac9f
parent9c3b79200b4bb413a27e4341d7c201c1799e2ef0 (diff)
eglfs: Sanitize the X11 hooks
Replace all xlib calls with xcb equivalents, leaving only the absolutely required xlib calls. Handle WM_DELETE_WINDOW so that closing the window exits the app as expected. Finally, introduce EGLFS_X11_FULLSCREEN to enable requesting a fullscreen native window. Change-Id: I8c46ae832d38549ec7d673592f400a4f34bf4314 Reviewed-by: Andy Nichols <andy.nichols@digia.com>
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks.h4
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks_stub.cpp5
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks_x11.cpp150
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.cpp2
4 files changed, 121 insertions, 40 deletions
diff --git a/src/plugins/platforms/eglfs/qeglfshooks.h b/src/plugins/platforms/eglfs/qeglfshooks.h
index c8486b9378..461ffa0f25 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks.h
+++ b/src/plugins/platforms/eglfs/qeglfshooks.h
@@ -66,7 +66,9 @@ public:
virtual int screenDepth() const;
virtual QImage::Format screenFormat() const;
virtual QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const;
- virtual EGLNativeWindowType createNativeWindow(const QSize &size, const QSurfaceFormat &format);
+ virtual EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
+ const QSize &size,
+ const QSurfaceFormat &format);
virtual void destroyNativeWindow(EGLNativeWindowType window);
virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
virtual QEglFSCursor *createCursor(QEglFSScreen *screen) const;
diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
index c334f46c2c..d04803d8e3 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
+++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
@@ -234,8 +234,11 @@ bool QEglFSHooks::filterConfig(EGLDisplay, EGLConfig) const
return true;
}
-EGLNativeWindowType QEglFSHooks::createNativeWindow(const QSize &size, const QSurfaceFormat &format)
+EGLNativeWindowType QEglFSHooks::createNativeWindow(QPlatformWindow *platformWindow,
+ const QSize &size,
+ const QSurfaceFormat &format)
{
+ Q_UNUSED(platformWindow);
Q_UNUSED(size);
Q_UNUSED(format);
return 0;
diff --git a/src/plugins/platforms/eglfs/qeglfshooks_x11.cpp b/src/plugins/platforms/eglfs/qeglfshooks_x11.cpp
index 0d8be66438..50f8d0acb6 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks_x11.cpp
+++ b/src/plugins/platforms/eglfs/qeglfshooks_x11.cpp
@@ -42,6 +42,7 @@
#include "qeglfshooks.h"
#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qplatformwindow.h>
#include <QThread>
#include <X11/Xlib.h>
@@ -50,45 +51,65 @@
QT_BEGIN_NAMESPACE
+class QEglFSX11Hooks;
+
class EventReader : public QThread
{
public:
- EventReader(xcb_connection_t *connection)
- : m_connection(connection)
- {
- }
+ EventReader(QEglFSX11Hooks *hooks)
+ : m_hooks(hooks) { }
void run();
- xcb_connection_t *connection() { return m_connection; }
-
private:
- xcb_connection_t *m_connection;
+ QEglFSX11Hooks *m_hooks;
};
+namespace Atoms {
+ enum {
+ _NET_WM_NAME = 0,
+ UTF8_STRING,
+ WM_PROTOCOLS,
+ WM_DELETE_WINDOW,
+ _NET_WM_STATE,
+ _NET_WM_STATE_FULLSCREEN,
+
+ N_ATOMS
+ };
+}
+
class QEglFSX11Hooks : public QEglFSHooks
{
public:
- QEglFSX11Hooks() : m_eventReader(0) {}
+ QEglFSX11Hooks() : m_connection(0), m_window(0), m_eventReader(0) {}
virtual void platformInit();
virtual void platformDestroy();
virtual EGLNativeDisplayType platformDisplay() const;
virtual QSize screenSize() const;
- virtual EGLNativeWindowType createNativeWindow(const QSize &size, const QSurfaceFormat &format);
+ virtual EGLNativeWindowType createNativeWindow(QPlatformWindow *window,
+ const QSize &size,
+ const QSurfaceFormat &format);
virtual void destroyNativeWindow(EGLNativeWindowType window);
virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
+ xcb_connection_t *connection() { return m_connection; }
+ const xcb_atom_t *atoms() const { return m_atoms; }
+ QPlatformWindow *platformWindow() { return m_platformWindow; }
+
private:
void sendConnectionEvent(xcb_atom_t a);
- EventReader *m_eventReader;
+ Display *m_display;
xcb_connection_t *m_connection;
+ xcb_atom_t m_atoms[Atoms::N_ATOMS];
+ xcb_window_t m_window;
+ EventReader *m_eventReader;
xcb_window_t m_connectionEventListener;
+ QPlatformWindow *m_platformWindow;
+ mutable QSize m_screenSize;
};
-static Display *display = 0;
-
QAtomicInt running;
static Qt::MouseButtons translateMouseButtons(int s)
@@ -143,7 +164,7 @@ void EventReader::run()
Qt::MouseButtons buttons;
xcb_generic_event_t *event;
- while (running.load() && (event = xcb_wait_for_event(m_connection))) {
+ while (running.load() && (event = xcb_wait_for_event(m_hooks->connection()))) {
uint response_type = event->response_type & ~0x80;
switch (response_type) {
case XCB_BUTTON_PRESS: {
@@ -168,6 +189,15 @@ void EventReader::run()
QWindowSystemInterface::handleMouseEvent(0, motion->time, p, p, buttons);
break;
}
+ case XCB_CLIENT_MESSAGE: {
+ xcb_client_message_event_t *client = (xcb_client_message_event_t *) event;
+ const xcb_atom_t *atoms = m_hooks->atoms();
+ if (client->format == 32
+ && client->type == atoms[Atoms::WM_PROTOCOLS]
+ && client->data.data32[0] == atoms[Atoms::WM_DELETE_WINDOW])
+ QWindowSystemInterface::handleCloseEvent(m_hooks->platformWindow()->window());
+ break;
+ }
default:
break;
}
@@ -191,14 +221,14 @@ void QEglFSX11Hooks::sendConnectionEvent(xcb_atom_t a)
void QEglFSX11Hooks::platformInit()
{
- display = XOpenDisplay(NULL);
- if (!display)
+ m_display = XOpenDisplay(0);
+ if (!m_display)
qFatal("Could not open display");
- XSetEventQueueOwner(display, XCBOwnsEventQueue);
- running.ref();
+ XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
+ m_connection = XGetXCBConnection(m_display);
- m_connection = XGetXCBConnection(display);
+ running.ref();
xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection));
@@ -208,7 +238,7 @@ void QEglFSX11Hooks::platformInit()
0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
it.data->root_visual, 0, 0);
- m_eventReader = new EventReader(m_connection);
+ m_eventReader = new EventReader(this);
m_eventReader->start();
}
@@ -218,45 +248,91 @@ void QEglFSX11Hooks::platformDestroy()
sendConnectionEvent(XCB_ATOM_NONE);
- XCloseDisplay(display);
-
m_eventReader->wait();
delete m_eventReader;
m_eventReader = 0;
+
+ XCloseDisplay(m_display);
+ m_display = 0;
+ m_connection = 0;
}
EGLNativeDisplayType QEglFSX11Hooks::platformDisplay() const
{
- return display;
+ return m_display;
}
QSize QEglFSX11Hooks::screenSize() const
{
- QList<QByteArray> env = qgetenv("EGLFS_X11_SIZE").split('x');
- if (env.length() != 2)
- return QSize(640, 480);
- return QSize(env.at(0).toInt(), env.at(1).toInt());
+ if (m_screenSize.isEmpty()) {
+ QList<QByteArray> env = qgetenv("EGLFS_X11_SIZE").split('x');
+ if (env.length() == 2) {
+ m_screenSize = QSize(env.at(0).toInt(), env.at(1).toInt());
+ } else {
+ m_screenSize = QSize(640, 480);
+ qDebug("EGLFS_X11_SIZE not set, falling back to 640x480");
+ }
+ }
+ return m_screenSize;
}
-EGLNativeWindowType QEglFSX11Hooks::createNativeWindow(const QSize &size, const QSurfaceFormat &format)
+EGLNativeWindowType QEglFSX11Hooks::createNativeWindow(QPlatformWindow *platformWindow,
+ const QSize &size,
+ const QSurfaceFormat &format)
{
Q_UNUSED(format);
- Window root = DefaultRootWindow(display);
- XSetWindowAttributes swa;
- memset(&swa, 0, sizeof(swa));
- swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ButtonMotionMask;
- Window win = XCreateWindow(display, root, 0, 0, size.width(), size.height(), 0, CopyFromParent,
- InputOutput, CopyFromParent, CWEventMask, &swa);
- XMapWindow(display, win);
- XStoreName(display, win, "EGLFS");
+ m_platformWindow = platformWindow;
+
+ xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection));
+ m_window = xcb_generate_id(m_connection);
+ xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, m_window, it.data->root,
+ 0, 0, size.width(), size.height(), 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, it.data->root_visual,
+ 0, 0);
+
+ xcb_map_window(m_connection, m_window);
+
+ xcb_intern_atom_cookie_t cookies[Atoms::N_ATOMS];
+ static const char *atomNames[Atoms::N_ATOMS] = {
+ "_NET_WM_NAME",
+ "UTF8_STRING",
+ "WM_PROTOCOLS",
+ "WM_DELETE_WINDOW",
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_FULLSCREEN"
+ };
+
+ for (int i = 0; i < Atoms::N_ATOMS; ++i) {
+ cookies[i] = xcb_intern_atom(m_connection, false, strlen(atomNames[i]), atomNames[i]);
+ xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(m_connection, cookies[i], 0);
+ m_atoms[i] = reply->atom;
+ free(reply);
+ }
+
+ // Set window title
+ xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
+ m_atoms[Atoms::_NET_WM_NAME], m_atoms[Atoms::UTF8_STRING], 8, 5, "EGLFS");
+
+ // Enable WM_DELETE_WINDOW
+ xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
+ m_atoms[Atoms::WM_PROTOCOLS], XCB_ATOM_ATOM, 32, 1, &m_atoms[Atoms::WM_DELETE_WINDOW]);
+
+ if (qgetenv("EGLFS_X11_FULLSCREEN").toInt()) {
+ // Go fullscreen. The QScreen and QWindow size is controlled by EGLFS_X11_SIZE regardless,
+ // this is just the native window.
+ xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
+ m_atoms[Atoms::_NET_WM_STATE], XCB_ATOM_ATOM, 32, 1, &m_atoms[Atoms::_NET_WM_STATE_FULLSCREEN]);
+ }
+
+ xcb_flush(m_connection);
- return win;
+ return m_window;
}
void QEglFSX11Hooks::destroyNativeWindow(EGLNativeWindowType window)
{
- XDestroyWindow(display, window);
+ xcb_destroy_window(m_connection, window);
}
bool QEglFSX11Hooks::hasCapability(QPlatformIntegration::Capability cap) const
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp
index 73f52f0796..d66f175920 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp
@@ -114,7 +114,7 @@ void QEglFSWindow::resetSurface()
{
EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
- m_window = QEglFSHooks::hooks()->createNativeWindow(QEglFSHooks::hooks()->screenSize(), m_format);
+ m_window = QEglFSHooks::hooks()->createNativeWindow(this, QEglFSHooks::hooks()->screenSize(), m_format);
has_window = true;
m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL);