summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp')
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp292
1 files changed, 292 insertions, 0 deletions
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
new file mode 100644
index 0000000000..4d29b96608
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfsx11integration.h"
+#include <QThread>
+
+#include <X11/Xlib.h>
+#include <X11/Xlib-xcb.h>
+
+/* Make no mistake: This is not a replacement for the xcb platform plugin.
+ This here is barely an extremely useful tool for developing eglfs itself because
+ it allows to do so without any requirements for devices or drivers. */
+
+QT_BEGIN_NAMESPACE
+
+class EventReader : public QThread
+{
+public:
+ EventReader(QEglFSX11Integration *integration)
+ : m_integration(integration) { }
+
+ void run();
+
+private:
+ QEglFSX11Integration *m_integration;
+};
+
+QAtomicInt running;
+
+static Qt::MouseButtons translateMouseButtons(int s)
+{
+ Qt::MouseButtons ret = 0;
+ if (s & XCB_BUTTON_MASK_1)
+ ret |= Qt::LeftButton;
+ if (s & XCB_BUTTON_MASK_2)
+ ret |= Qt::MidButton;
+ if (s & XCB_BUTTON_MASK_3)
+ ret |= Qt::RightButton;
+ return ret;
+}
+
+static Qt::MouseButton translateMouseButton(xcb_button_t s)
+{
+ switch (s) {
+ case 1: return Qt::LeftButton;
+ case 2: return Qt::MidButton;
+ case 3: return Qt::RightButton;
+ // Button values 4-7 were already handled as Wheel events, and won't occur here.
+ case 8: return Qt::BackButton; // Also known as Qt::ExtraButton1
+ case 9: return Qt::ForwardButton; // Also known as Qt::ExtraButton2
+ case 10: return Qt::ExtraButton3;
+ case 11: return Qt::ExtraButton4;
+ case 12: return Qt::ExtraButton5;
+ case 13: return Qt::ExtraButton6;
+ case 14: return Qt::ExtraButton7;
+ case 15: return Qt::ExtraButton8;
+ case 16: return Qt::ExtraButton9;
+ case 17: return Qt::ExtraButton10;
+ case 18: return Qt::ExtraButton11;
+ case 19: return Qt::ExtraButton12;
+ case 20: return Qt::ExtraButton13;
+ case 21: return Qt::ExtraButton14;
+ case 22: return Qt::ExtraButton15;
+ case 23: return Qt::ExtraButton16;
+ case 24: return Qt::ExtraButton17;
+ case 25: return Qt::ExtraButton18;
+ case 26: return Qt::ExtraButton19;
+ case 27: return Qt::ExtraButton20;
+ case 28: return Qt::ExtraButton21;
+ case 29: return Qt::ExtraButton22;
+ case 30: return Qt::ExtraButton23;
+ case 31: return Qt::ExtraButton24;
+ default: return Qt::NoButton;
+ }
+}
+
+void EventReader::run()
+{
+ Qt::MouseButtons buttons;
+
+ xcb_generic_event_t *event;
+ while (running.load() && (event = xcb_wait_for_event(m_integration->connection()))) {
+ uint response_type = event->response_type & ~0x80;
+ switch (response_type) {
+ case XCB_BUTTON_PRESS: {
+ xcb_button_press_event_t *press = (xcb_button_press_event_t *)event;
+ QPoint p(press->event_x, press->event_y);
+ buttons = (buttons & ~0x7) | translateMouseButtons(press->state);
+ buttons |= translateMouseButton(press->detail);
+ QWindowSystemInterface::handleMouseEvent(0, press->time, p, p, buttons);
+ break;
+ }
+ case XCB_BUTTON_RELEASE: {
+ xcb_button_release_event_t *release = (xcb_button_release_event_t *)event;
+ QPoint p(release->event_x, release->event_y);
+ buttons = (buttons & ~0x7) | translateMouseButtons(release->state);
+ buttons &= ~translateMouseButton(release->detail);
+ QWindowSystemInterface::handleMouseEvent(0, release->time, p, p, buttons);
+ break;
+ }
+ case XCB_MOTION_NOTIFY: {
+ xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)event;
+ QPoint p(motion->event_x, motion->event_y);
+ 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_integration->atoms();
+ if (client->format == 32
+ && client->type == atoms[Atoms::WM_PROTOCOLS]
+ && client->data.data32[0] == atoms[Atoms::WM_DELETE_WINDOW]) {
+ QWindow *window = m_integration->platformWindow() ? m_integration->platformWindow()->window() : 0;
+ if (window)
+ QWindowSystemInterface::handleCloseEvent(window);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void QEglFSX11Integration::sendConnectionEvent(xcb_atom_t a)
+{
+ xcb_client_message_event_t event;
+ memset(&event, 0, sizeof(event));
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.sequence = 0;
+ event.window = m_connectionEventListener;
+ event.type = a;
+
+ xcb_send_event(m_connection, false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
+ xcb_flush(m_connection);
+}
+
+#define DISPLAY ((Display *) m_display)
+
+void QEglFSX11Integration::platformInit()
+{
+ m_display = XOpenDisplay(0);
+ if (!m_display)
+ qFatal("Could not open display");
+
+ XSetEventQueueOwner(DISPLAY, XCBOwnsEventQueue);
+ m_connection = XGetXCBConnection(DISPLAY);
+
+ running.ref();
+
+ xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection));
+
+ m_connectionEventListener = xcb_generate_id(m_connection);
+ xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
+ m_connectionEventListener, it.data->root,
+ 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
+ it.data->root_visual, 0, 0);
+
+ m_eventReader = new EventReader(this);
+ m_eventReader->start();
+}
+
+void QEglFSX11Integration::platformDestroy()
+{
+ running.deref();
+
+ sendConnectionEvent(XCB_ATOM_NONE);
+
+ m_eventReader->wait();
+ delete m_eventReader;
+ m_eventReader = 0;
+
+ XCloseDisplay(DISPLAY);
+ m_display = 0;
+ m_connection = 0;
+}
+
+EGLNativeDisplayType QEglFSX11Integration::platformDisplay() const
+{
+ return DISPLAY;
+}
+
+QSize QEglFSX11Integration::screenSize() const
+{
+ 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 {
+ XWindowAttributes a;
+ if (XGetWindowAttributes(DISPLAY, DefaultRootWindow(DISPLAY), &a))
+ m_screenSize = QSize(a.width, a.height);
+ }
+ }
+ return m_screenSize;
+}
+
+EGLNativeWindowType QEglFSX11Integration::createNativeWindow(QPlatformWindow *platformWindow,
+ const QSize &size,
+ const QSurfaceFormat &format)
+{
+ Q_UNUSED(format);
+
+ 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_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]);
+
+ // Go fullscreen.
+ 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_map_window(m_connection, m_window);
+
+ xcb_flush(m_connection);
+
+ return m_window;
+}
+
+void QEglFSX11Integration::destroyNativeWindow(EGLNativeWindowType window)
+{
+ xcb_destroy_window(m_connection, window);
+}
+
+bool QEglFSX11Integration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ Q_UNUSED(cap);
+ return false;
+}
+
+QT_END_NAMESPACE