-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes: #33
- Loading branch information
Showing
7 changed files
with
334 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <[email protected]> | ||
# | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
|
||
liri_add_plugin(eglfs-x11-integration | ||
TYPE | ||
liri/egldeviceintegrations | ||
SOURCES | ||
qeglfsx11integration.cpp qeglfsx11integration.h | ||
qeglfsx11main.cpp | ||
DEFINES | ||
QT_EGL_NO_X11 | ||
INCLUDE_DIRECTORIES | ||
../../api | ||
LIBRARIES | ||
Qt::Core | ||
Qt::CorePrivate | ||
Qt::Gui | ||
Qt::GuiPrivate | ||
Liri::EglFSDeviceIntegration | ||
Liri::EglFSDeviceIntegrationPrivate | ||
X11::X11 | ||
X11::xcb | ||
X11::X11_xcb | ||
XCB::XCB | ||
) |
3 changes: 3 additions & 0 deletions
3
src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"Keys": [ "eglfs_x11" ] | ||
} |
195 changes: 195 additions & 0 deletions
195
src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
// Copyright (C) 2016 The Qt Company Ltd. | ||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | ||
|
||
#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() override; | ||
|
||
private: | ||
QEglFSX11Integration *m_integration; | ||
}; | ||
|
||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) | ||
Q_CONSTINIT static QBasicAtomicInt running = Q_BASIC_ATOMIC_INITIALIZER(0); | ||
#else | ||
static QBasicAtomicInt running; | ||
#endif | ||
|
||
void EventReader::run() | ||
{ | ||
xcb_generic_event_t *event = nullptr; | ||
while (running.loadRelaxed() && (event = xcb_wait_for_event(m_integration->connection()))) { | ||
uint response_type = event->response_type & ~0x80; | ||
switch (response_type) { | ||
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() : nullptr; | ||
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(nullptr); | ||
if (Q_UNLIKELY(!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, nullptr); | ||
|
||
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 = nullptr; | ||
|
||
XCloseDisplay(DISPLAY); | ||
m_display = nullptr; | ||
m_connection = nullptr; | ||
} | ||
|
||
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.size() == 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, nullptr); | ||
|
||
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], nullptr); | ||
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 qt_egl_cast<EGLNativeWindowType>(m_window); | ||
} | ||
|
||
void QEglFSX11Integration::destroyNativeWindow(EGLNativeWindowType window) | ||
{ | ||
xcb_destroy_window(m_connection, qt_egl_cast<xcb_window_t>(window)); | ||
} | ||
|
||
bool QEglFSX11Integration::hasCapability(QPlatformIntegration::Capability cap) const | ||
{ | ||
Q_UNUSED(cap); | ||
return false; | ||
} | ||
|
||
QT_END_NAMESPACE |
65 changes: 65 additions & 0 deletions
65
src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright (C) 2016 The Qt Company Ltd. | ||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | ||
|
||
#ifndef QEGLFSX11INTEGRATION_H | ||
#define QEGLFSX11INTEGRATION_H | ||
|
||
#include "private/qeglfsdeviceintegration_p.h" | ||
|
||
#include <qpa/qwindowsysteminterface.h> | ||
#include <qpa/qplatformwindow.h> | ||
|
||
#include <xcb/xcb.h> | ||
|
||
QT_BEGIN_NAMESPACE | ||
|
||
namespace Atoms { | ||
enum { | ||
_NET_WM_NAME = 0, | ||
UTF8_STRING, | ||
WM_PROTOCOLS, | ||
WM_DELETE_WINDOW, | ||
_NET_WM_STATE, | ||
_NET_WM_STATE_FULLSCREEN, | ||
|
||
N_ATOMS | ||
}; | ||
} | ||
|
||
class EventReader; | ||
|
||
class QEglFSX11Integration : public QEglFSDeviceIntegration | ||
{ | ||
public: | ||
QEglFSX11Integration() : m_connection(nullptr), m_window(0), m_eventReader(nullptr) {} | ||
|
||
void platformInit() override; | ||
void platformDestroy() override; | ||
EGLNativeDisplayType platformDisplay() const override; | ||
QSize screenSize() const override; | ||
EGLNativeWindowType createNativeWindow(QPlatformWindow *window, | ||
const QSize &size, | ||
const QSurfaceFormat &format) override; | ||
void destroyNativeWindow(EGLNativeWindowType window) override; | ||
bool hasCapability(QPlatformIntegration::Capability cap) const override; | ||
|
||
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); | ||
|
||
void *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; | ||
}; | ||
|
||
QT_END_NAMESPACE | ||
|
||
#endif |
20 changes: 20 additions & 0 deletions
20
src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright (C) 2016 The Qt Company Ltd. | ||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | ||
|
||
#include "private/qeglfsdeviceintegration_p.h" | ||
#include "qeglfsx11integration.h" | ||
|
||
QT_BEGIN_NAMESPACE | ||
|
||
class QEglFSX11IntegrationPlugin : public QEglFSDeviceIntegrationPlugin | ||
{ | ||
Q_OBJECT | ||
Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_x11.json") | ||
|
||
public: | ||
QEglFSDeviceIntegration *create() override { return new QEglFSX11Integration; } | ||
}; | ||
|
||
QT_END_NAMESPACE | ||
|
||
#include "qeglfsx11main.moc" |