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>
This commit is contained in:
parent
9c3b79200b
commit
2b20ed5af4
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,15 +221,15 @@ 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);
|
||||
|
||||
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
|
||||
m_connection = XGetXCBConnection(m_display);
|
||||
|
||||
running.ref();
|
||||
|
||||
m_connection = XGetXCBConnection(display);
|
||||
|
||||
xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection));
|
||||
|
||||
m_connectionEventListener = xcb_generate_id(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;
|
||||
|
||||
return win;
|
||||
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 m_window;
|
||||
}
|
||||
|
||||
void QEglFSX11Hooks::destroyNativeWindow(EGLNativeWindowType window)
|
||||
{
|
||||
XDestroyWindow(display, window);
|
||||
xcb_destroy_window(m_connection, window);
|
||||
}
|
||||
|
||||
bool QEglFSX11Hooks::hasCapability(QPlatformIntegration::Capability cap) const
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user