qt5: use signal handler for input processing

Fixes #1707
This commit is contained in:
Christian Prochaska 2015-09-21 15:07:36 +02:00 committed by Christian Helmuth
parent 45bcb7f48f
commit 3bf050ed30
7 changed files with 189 additions and 109 deletions

View File

@ -14,12 +14,14 @@ SRC_CC += main.cpp \
qnitpickerintegration.cpp \ qnitpickerintegration.cpp \
qnitpickerplatformwindow.cpp \ qnitpickerplatformwindow.cpp \
qnitpickerwindowsurface.cpp \ qnitpickerwindowsurface.cpp \
qsignalhandlerthread.cpp \
moc_qnitpickerplatformwindow.cpp \ moc_qnitpickerplatformwindow.cpp \
moc_qnitpickerwindowsurface.cpp \ moc_qnitpickerwindowsurface.cpp \
moc_qnitpickerintegrationplugin.cpp \ moc_qnitpickerintegrationplugin.cpp \
qevdevkeyboardhandler.cpp \ qevdevkeyboardhandler.cpp \
moc_qunixeventdispatcher_qpa_p.cpp \ moc_qunixeventdispatcher_qpa_p.cpp \
moc_qevdevkeyboardhandler_p.cpp moc_qevdevkeyboardhandler_p.cpp \
moc_qsignalhandlerthread.cpp
INC_DIR += $(QT5_CONTRIB_DIR)/qtbase/src/platformsupport/eventdispatchers \ INC_DIR += $(QT5_CONTRIB_DIR)/qtbase/src/platformsupport/eventdispatchers \
$(QT5_CONTRIB_DIR)/qtbase/src/platformsupport/fontdatabases/basic \ $(QT5_CONTRIB_DIR)/qtbase/src/platformsupport/fontdatabases/basic \

View File

@ -11,11 +11,6 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <base/rpc_server.h>
#include <cap_session/connection.h>
/* Qt includes */ /* Qt includes */
#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qguiapplication_p.h>
#include "qnitpickerglcontext.h" #include "qnitpickerglcontext.h"
@ -30,21 +25,20 @@ QT_BEGIN_NAMESPACE
static const bool verbose = false; static const bool verbose = false;
static Genode::Rpc_entrypoint &_entrypoint() Genode::Signal_receiver &QNitpickerIntegration::_signal_receiver()
{ {
enum { STACK_SIZE = 2*1024*sizeof(Genode::addr_t) }; static Genode::Signal_receiver _inst;
static Genode::Cap_connection cap; return _inst;
static Genode::Rpc_entrypoint entrypoint(&cap, STACK_SIZE, "qt_window_ep");
return entrypoint;
} }
QNitpickerIntegration::QNitpickerIntegration() QNitpickerIntegration::QNitpickerIntegration()
: _nitpicker_screen(new QNitpickerScreen()), : _signal_handler_thread(_signal_receiver()),
_nitpicker_screen(new QNitpickerScreen()),
_event_dispatcher(createUnixEventDispatcher()) _event_dispatcher(createUnixEventDispatcher())
{ {
QGuiApplicationPrivate::instance()->setEventDispatcher(_event_dispatcher); QGuiApplicationPrivate::instance()->setEventDispatcher(_event_dispatcher);
screenAdded(_nitpicker_screen); screenAdded(_nitpicker_screen);
_signal_handler_thread.start();
} }
@ -63,7 +57,8 @@ QPlatformWindow *QNitpickerIntegration::createPlatformWindow(QWindow *window) co
qDebug() << "QNitpickerIntegration::createPlatformWindow(" << window << ")"; qDebug() << "QNitpickerIntegration::createPlatformWindow(" << window << ")";
QRect screen_geometry = _nitpicker_screen->geometry(); QRect screen_geometry = _nitpicker_screen->geometry();
return new QNitpickerPlatformWindow(window, _entrypoint(), return new QNitpickerPlatformWindow(window,
_signal_receiver(),
screen_geometry.width(), screen_geometry.width(),
screen_geometry.height()); screen_geometry.height());
} }

View File

@ -21,6 +21,7 @@
#include <qpa/qplatformscreen.h> #include <qpa/qplatformscreen.h>
#include "qnitpickerscreen.h" #include "qnitpickerscreen.h"
#include "qsignalhandlerthread.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -28,22 +29,32 @@ class QNitpickerIntegration : public QPlatformIntegration
{ {
private: private:
QSignalHandlerThread _signal_handler_thread;
QNitpickerScreen *_nitpicker_screen; QNitpickerScreen *_nitpicker_screen;
QAbstractEventDispatcher *_event_dispatcher; QAbstractEventDispatcher *_event_dispatcher;
/*
* A reference to the signal receiver gets passed to newly created
* objects, for example in 'createPlatformWindow()'. Since this is
* a const member function, the signal receiver cannot be a member
* variable of QNitpickerIntegration.
*/
static Genode::Signal_receiver &_signal_receiver();
public: public:
QNitpickerIntegration(); QNitpickerIntegration();
bool hasCapability(QPlatformIntegration::Capability cap) const; bool hasCapability(QPlatformIntegration::Capability cap) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformWindow *createPlatformWindow(QWindow *window) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
QAbstractEventDispatcher *guiThreadEventDispatcher() const; QAbstractEventDispatcher *guiThreadEventDispatcher() const override;
QPlatformFontDatabase *fontDatabase() const; QPlatformFontDatabase *fontDatabase() const override;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -111,6 +111,7 @@ void QNitpickerPlatformWindow::_process_mouse_event(Input::Event *ev)
_mouse_button_state); _mouse_button_state);
} }
void QNitpickerPlatformWindow::_process_key_event(Input::Event *ev) void QNitpickerPlatformWindow::_process_key_event(Input::Event *ev)
{ {
const bool pressed = (ev->type() == Input::Event::PRESS); const bool pressed = (ev->type() == Input::Event::PRESS);
@ -118,6 +119,55 @@ void QNitpickerPlatformWindow::_process_key_event(Input::Event *ev)
_keyboard_handler.processKeycode(keycode, pressed, false); _keyboard_handler.processKeycode(keycode, pressed, false);
} }
void QNitpickerPlatformWindow::_handle_input(unsigned int)
{
for (int i = 0, num_ev = _input_session.flush(); i < num_ev; i++) {
Input::Event *ev = &_ev_buf[i];
bool const is_key_event = ev->type() == Input::Event::PRESS ||
ev->type() == Input::Event::RELEASE;
bool const is_mouse_button_event =
is_key_event && (ev->code() == Input::BTN_LEFT ||
ev->code() == Input::BTN_MIDDLE ||
ev->code() == Input::BTN_RIGHT);
if (ev->type() == Input::Event::MOTION ||
ev->type() == Input::Event::WHEEL ||
is_mouse_button_event) {
_process_mouse_event(ev);
} else if (is_key_event && (ev->code() < 128)) {
_process_key_event(ev);
}
}
}
void QNitpickerPlatformWindow::_handle_mode_changed(unsigned int)
{
Framebuffer::Mode mode(_nitpicker_session.mode());
if ((mode.width() != _current_mode.width()) ||
(mode.height() != _current_mode.height()) ||
(mode.format() != _current_mode.format())) {
QRect geo(geometry());
geo.setWidth(mode.width());
geo.setHeight(mode.height());
QWindowSystemInterface::handleGeometryChange(window(), geo);
setGeometry(geo);
}
}
Nitpicker::Session::View_handle QNitpickerPlatformWindow::_create_view() Nitpicker::Session::View_handle QNitpickerPlatformWindow::_create_view()
{ {
if (window()->type() == Qt::Desktop) if (window()->type() == Qt::Desktop)
@ -176,27 +226,33 @@ void QNitpickerPlatformWindow::_adjust_and_set_geometry(const QRect &rect)
emit framebuffer_changed(); emit framebuffer_changed();
} }
QNitpickerPlatformWindow::QNitpickerPlatformWindow(QWindow *window, Genode::Rpc_entrypoint &ep, QNitpickerPlatformWindow::QNitpickerPlatformWindow(QWindow *window,
int screen_width, int screen_height) Genode::Signal_receiver &signal_receiver,
int screen_width, int screen_height)
: QPlatformWindow(window), : QPlatformWindow(window),
_framebuffer_session(_nitpicker_session.framebuffer_session()), _framebuffer_session(_nitpicker_session.framebuffer_session()),
_framebuffer(0), _framebuffer(0),
_framebuffer_changed(false), _framebuffer_changed(false),
_geometry_changed(false), _geometry_changed(false),
_signal_receiver(signal_receiver),
_view_handle(_create_view()), _view_handle(_create_view()),
_input_session(_nitpicker_session.input_session()), _input_session(_nitpicker_session.input_session()),
_timer(this),
_keyboard_handler("", -1, false, false, ""), _keyboard_handler("", -1, false, false, ""),
_resize_handle(!window->flags().testFlag(Qt::Popup)), _resize_handle(!window->flags().testFlag(Qt::Popup)),
_decoration(!window->flags().testFlag(Qt::Popup)), _decoration(!window->flags().testFlag(Qt::Popup)),
_egl_surface(EGL_NO_SURFACE) _egl_surface(EGL_NO_SURFACE),
_input_signal_dispatcher(_signal_receiver, *this,
&QNitpickerPlatformWindow::_input),
_mode_changed_signal_dispatcher(_signal_receiver, *this,
&QNitpickerPlatformWindow::_mode_changed)
{ {
if (qnpw_verbose) if (qnpw_verbose)
if (window->transientParent()) if (window->transientParent())
qDebug() << "QNitpickerPlatformWindow(): child window of" << window->transientParent(); qDebug() << "QNitpickerPlatformWindow(): child window of" << window->transientParent();
_mode_changed_signal_context_capability = _signal_receiver.manage(&_mode_changed_signal_context); _input_session.sigh(_input_signal_dispatcher);
_nitpicker_session.mode_sigh(_mode_changed_signal_context_capability);
_nitpicker_session.mode_sigh(_mode_changed_signal_dispatcher);
_adjust_and_set_geometry(geometry()); _adjust_and_set_geometry(geometry());
@ -211,8 +267,13 @@ QNitpickerPlatformWindow::QNitpickerPlatformWindow(QWindow *window, Genode::Rpc_
_nitpicker_session.execute(); _nitpicker_session.execute();
} }
connect(_timer, SIGNAL(timeout()), this, SLOT(handle_events())); connect(this, SIGNAL(_input(unsigned int)),
_timer->start(10); this, SLOT(_handle_input(unsigned int)),
Qt::QueuedConnection);
connect(this, SIGNAL(_mode_changed(unsigned int)),
this, SLOT(_handle_mode_changed(unsigned int)),
Qt::QueuedConnection);
} }
QWindow *QNitpickerPlatformWindow::window() const QWindow *QNitpickerPlatformWindow::window() const
@ -584,61 +645,4 @@ Nitpicker::View_capability QNitpickerPlatformWindow::view_cap() const
return npw->_nitpicker_session.view_capability(_view_handle); return npw->_nitpicker_session.view_capability(_view_handle);
} }
void QNitpickerPlatformWindow::handle_events()
{
/* handle resize events */
if (_signal_receiver.pending()) {
_signal_receiver.wait_for_signal();
Framebuffer::Mode mode(_nitpicker_session.mode());
if ((mode.width() != _current_mode.width()) ||
(mode.height() != _current_mode.height()) ||
(mode.format() != _current_mode.format())) {
QRect geo(geometry());
geo.setWidth(mode.width());
geo.setHeight(mode.height());
QWindowSystemInterface::handleGeometryChange(window(), geo);
setGeometry(geo);
}
}
/* handle input events */
if (_input_session.is_pending()) {
for (int i = 0, num_ev = _input_session.flush(); i < num_ev; i++) {
Input::Event *ev = &_ev_buf[i];
bool const is_key_event = ev->type() == Input::Event::PRESS ||
ev->type() == Input::Event::RELEASE;
bool const is_mouse_button_event =
is_key_event && (ev->code() == Input::BTN_LEFT ||
ev->code() == Input::BTN_MIDDLE ||
ev->code() == Input::BTN_RIGHT);
if (ev->type() == Input::Event::MOTION ||
ev->type() == Input::Event::WHEEL ||
is_mouse_button_event) {
_process_mouse_event(ev);
} else if (is_key_event && (ev->code() < 128)) {
_process_key_event(ev);
}
}
}
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -37,25 +37,25 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
private: private:
Nitpicker::Connection _nitpicker_session; Nitpicker::Connection _nitpicker_session;
Framebuffer::Session_client _framebuffer_session; Framebuffer::Session_client _framebuffer_session;
unsigned char *_framebuffer; unsigned char *_framebuffer;
bool _framebuffer_changed; bool _framebuffer_changed;
bool _geometry_changed; bool _geometry_changed;
Framebuffer::Mode _current_mode; Framebuffer::Mode _current_mode;
Genode::Signal_context _mode_changed_signal_context; Genode::Signal_receiver &_signal_receiver;
Genode::Signal_context_capability _mode_changed_signal_context_capability; Nitpicker::Session::View_handle _view_handle;
Genode::Signal_receiver _signal_receiver; Input::Session_client _input_session;
Nitpicker::Session::View_handle _view_handle; Input::Event *_ev_buf;
Input::Session_client _input_session; Qt::MouseButtons _mouse_button_state;
Input::Event *_ev_buf; QEvdevKeyboardHandler _keyboard_handler;
QMember<QTimer> _timer; QByteArray _title;
Qt::MouseButtons _mouse_button_state; bool _resize_handle;
QEvdevKeyboardHandler _keyboard_handler; bool _decoration;
QByteArray _title; EGLSurface _egl_surface;
bool _resize_handle;
bool _decoration; Genode::Signal_dispatcher<QNitpickerPlatformWindow> _input_signal_dispatcher;
EGLSurface _egl_surface; Genode::Signal_dispatcher<QNitpickerPlatformWindow> _mode_changed_signal_dispatcher;
void _process_mouse_event(Input::Event *ev); void _process_mouse_event(Input::Event *ev);
void _process_key_event(Input::Event *ev); void _process_key_event(Input::Event *ev);
@ -63,9 +63,20 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
Nitpicker::Session::View_handle _create_view(); Nitpicker::Session::View_handle _create_view();
void _adjust_and_set_geometry(const QRect &rect); void _adjust_and_set_geometry(const QRect &rect);
private Q_SLOTS:
void _handle_input(unsigned int);
void _handle_mode_changed(unsigned int);
Q_SIGNALS:
void _input(unsigned int);
void _mode_changed(unsigned int);
public: public:
QNitpickerPlatformWindow(QWindow *window, Genode::Rpc_entrypoint &ep, QNitpickerPlatformWindow(QWindow *window,
Genode::Signal_receiver &signal_receiver,
int screen_width, int screen_height); int screen_width, int screen_height);
QWindow *window() const; QWindow *window() const;
@ -162,10 +173,6 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
void framebuffer_changed(); void framebuffer_changed();
private slots:
void handle_events();
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -0,0 +1,22 @@
/*
* \brief QPA signal handler thread
* \author Christian Prochaska
* \date 2015-09-18
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "qsignalhandlerthread.h"
void QSignalHandlerThread::run()
{
for (;;) {
Genode::Signal s = _signal_receiver.wait_for_signal();
static_cast<Genode::Signal_dispatcher_base*>(s.context())->dispatch(s.num());
}
}

View File

@ -0,0 +1,39 @@
/*
* \brief QPA signal handler thread
* \author Christian Prochaska
* \date 2015-09-18
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _QSIGNALHANDLERTHREAD_H_
#define _QSIGNALHANDLERTHREAD_H_
/* Genode includes */
#include <base/signal.h>
/* Qt includes */
#include <QThread>
class QSignalHandlerThread : public QThread
{
Q_OBJECT
private:
Genode::Signal_receiver &_signal_receiver;
public:
QSignalHandlerThread(Genode::Signal_receiver &signal_receiver)
: _signal_receiver(signal_receiver) { }
void run() override;
};
#endif /* _QSIGNALHANDLERTHREAD_H_ */