Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwaylandseat.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qwaylandseat.h"
5#include "qwaylandseat_p.h"
6
9#include "qwaylandview.h"
10#if QT_CONFIG(draganddrop)
11#include <QtWaylandCompositor/QWaylandDrag>
12#endif
13#include <QtWaylandCompositor/QWaylandTouch>
14#include <QtWaylandCompositor/QWaylandPointer>
15#include <QtWaylandCompositor/QWaylandKeymap>
16#include <QtWaylandCompositor/private/qwaylandseat_p.h>
17#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
18#include <QtWaylandCompositor/private/qwaylandkeyboard_p.h>
19#if QT_CONFIG(wayland_datadevice)
20#include <QtWaylandCompositor/private/qwldatadevice_p.h>
21#endif
22#include <QtWaylandCompositor/private/qwaylandutils_p.h>
23
26#if QT_WAYLAND_TEXT_INPUT_V4_WIP
28#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
30
32
34#if QT_CONFIG(wayland_datadevice)
35 drag_handle(new QWaylandDrag(seat)),
36#endif
37 keymap(new QWaylandKeymap())
38{
39}
40
42{
43}
44
45void QWaylandSeatPrivate::setCapabilities(QWaylandSeat::CapabilityFlags caps)
46{
47 Q_Q(QWaylandSeat);
48 if (capabilities != caps) {
49 QWaylandSeat::CapabilityFlags changed = caps ^ capabilities;
50
51 if (changed & QWaylandSeat::Pointer) {
52 pointer.reset(pointer.isNull() ? QWaylandCompositorPrivate::get(compositor)->callCreatePointerDevice(q) : nullptr);
53 }
54
55 if (changed & QWaylandSeat::Keyboard) {
56 keyboard.reset(keyboard.isNull() ? QWaylandCompositorPrivate::get(compositor)->callCreateKeyboardDevice(q) : nullptr);
57 }
58
59 if (changed & QWaylandSeat::Touch) {
60 touch.reset(touch.isNull() ? QWaylandCompositorPrivate::get(compositor)->callCreateTouchDevice(q) : nullptr);
61 }
62
63 capabilities = caps;
64 QList<Resource *> resources = resourceMap().values();
65 for (int i = 0; i < resources.size(); i++) {
66 wl_seat::send_capabilities(resources.at(i)->handle, (uint32_t)capabilities);
67 }
68
69 if ((changed & caps & QWaylandSeat::Keyboard) && keyboardFocus != nullptr)
70 keyboard->setFocus(keyboardFocus);
71 }
72}
73
74#if QT_CONFIG(wayland_datadevice)
75void QWaylandSeatPrivate::clientRequestedDataDevice(QtWayland::DataDeviceManager *, struct wl_client *client, uint32_t id)
76{
77 Q_Q(QWaylandSeat);
78 if (!data_device)
79 data_device.reset(new QtWayland::DataDevice(q));
80 data_device->add(client, id, 1);
81}
82#endif
83
85{
86// cleanupDataDeviceForClient(resource->client(), true);
87}
88
89void QWaylandSeatPrivate::seat_bind_resource(wl_seat::Resource *resource)
90{
91 // The order of capabilities matches the order defined in the wayland protocol
92 wl_seat::send_capabilities(resource->handle, (uint32_t)capabilities);
93}
94
95void QWaylandSeatPrivate::seat_get_pointer(wl_seat::Resource *resource, uint32_t id)
96{
97 if (!pointer.isNull()) {
98 pointer->addClient(QWaylandClient::fromWlClient(compositor, resource->client()), id, resource->version());
99 }
100}
101
102void QWaylandSeatPrivate::seat_get_keyboard(wl_seat::Resource *resource, uint32_t id)
103{
104 if (!keyboard.isNull()) {
105 keyboard->addClient(QWaylandClient::fromWlClient(compositor, resource->client()), id, resource->version());
106 }
107}
108
109void QWaylandSeatPrivate::seat_get_touch(wl_seat::Resource *resource, uint32_t id)
110{
111 if (!touch.isNull()) {
112 touch->addClient(QWaylandClient::fromWlClient(compositor, resource->client()), id, resource->version());
113 }
114}
115
154{
155 Q_D(QWaylandSeat);
156 d->compositor = compositor;
157 d->capabilities = capabilityFlags;
158 if (compositor->isCreated())
159 initialize();
160
161 // Support deprecated signal for backward compatibility
162 connect(this, &QWaylandSeat::cursorSurfaceRequested, this, &QWaylandSeat::cursorSurfaceRequest);
163}
164
169{
170}
171
181{
182 Q_D(QWaylandSeat);
183 d->init(d->compositor->display(), 4);
184
185 if (d->capabilities & QWaylandSeat::Pointer)
186 d->pointer.reset(QWaylandCompositorPrivate::get(d->compositor)->callCreatePointerDevice(this));
187 if (d->capabilities & QWaylandSeat::Touch)
188 d->touch.reset(QWaylandCompositorPrivate::get(d->compositor)->callCreateTouchDevice(this));
189 if (d->capabilities & QWaylandSeat::Keyboard)
190 d->keyboard.reset(QWaylandCompositorPrivate::get(d->compositor)->callCreateKeyboardDevice(this));
191
192 d->isInitialized = true;
193}
194
201{
202 Q_D(const QWaylandSeat);
203 return d->isInitialized;
204}
205
210{
211 Q_D(QWaylandSeat);
212 d->pointer->sendMousePressEvent(button);
213}
214
219{
220 Q_D(QWaylandSeat);
221 d->pointer->sendMouseReleaseEvent(button);
222}
223
228void QWaylandSeat::sendMouseMoveEvent(QWaylandView *view, const QPointF &localPos, const QPointF &outputSpacePos)
229{
230 Q_D(QWaylandSeat);
231 d->pointer->sendMouseMoveEvent(view, localPos, outputSpacePos);
232}
233
238{
239 Q_D(QWaylandSeat);
240 d->pointer->sendMouseWheelEvent(orientation, delta);
241}
242
247{
248 Q_D(QWaylandSeat);
249 d->keyboard->sendKeyPressEvent(code);
250}
251
256{
257 Q_D(QWaylandSeat);
258 d->keyboard->sendKeyReleaseEvent(code);
259}
260
272{
273 Q_D(QWaylandSeat);
274
275 if (d->touch.isNull())
276 return 0;
277
278 return d->touch->sendTouchPointEvent(surface, id, point,state);
279}
280
311{
313}
314
345{
347}
348
379{
381}
382
395{
396 Q_D(QWaylandSeat);
397 if (!d->touch.isNull())
398 d->touch->sendFrameEvent(client);
399}
400
411{
412 Q_D(QWaylandSeat);
413 if (!d->touch.isNull())
414 d->touch->sendCancelEvent(client);
415}
416
426{
427 Q_D(QWaylandSeat);
428
429 if (!d->touch)
430 return;
431
432 d->touch->sendFullTouchEvent(surface, event);
433}
434
444{
445 Q_D(QWaylandSeat);
446
447 if (!keyboardFocus()) {
448 qWarning("Cannot send key event, no keyboard focus, fix the compositor");
449 return;
450 }
451
452#if QT_CONFIG(im)
453 if (keyboardFocus()->inputMethodControl()->enabled()
454 && event->nativeScanCode() == 0) {
455 if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV2)) {
457 if (textInput) {
458 textInput->sendKeyEvent(event);
459 return;
460 }
461 }
462
465 if (textInputMethod) {
466 textInputMethod->sendKeyEvent(event);
467 return;
468 }
469 }
470
471#if QT_WAYLAND_TEXT_INPUT_V4_WIP
472 if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV4)) {
474 if (textInputV4 && !event->text().isEmpty()) {
475 // it will just commit the text for text-input-unstable-v4-wip when keyPress
476 if (event->type() == QEvent::KeyPress)
477 textInputV4->sendKeyEvent(event);
478 return;
479 }
480 }
481#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
482 }
483#endif
484
486 if (ext && ext->postQtKeyEvent(event, keyboardFocus()))
487 return;
488
489 if (!d->keyboard.isNull() && !event->isAutoRepeat()) {
490
491 uint scanCode = event->nativeScanCode();
492 if (scanCode == 0)
493 scanCode = d->keyboard->keyToScanCode(event->key());
494
495 if (scanCode == 0) {
496 qWarning() << "Can't send Wayland key event: Unable to get a valid scan code";
497 return;
498 }
499
500 if (event->type() == QEvent::KeyPress) {
502 d->keyboard->sendKeyPressEvent(scanCode);
503 } else if (event->type() == QEvent::KeyRelease) {
504 d->keyboard->sendKeyReleaseEvent(scanCode);
505 }
506 }
507}
508
526void QWaylandSeat::sendKeyEvent(int qtKey, bool pressed)
527{
528 Q_D(QWaylandSeat);
529 if (!keyboardFocus()) {
530 qWarning("Cannot send Wayland key event, no keyboard focus, fix the compositor");
531 return;
532 }
533
534 if (auto scanCode = d->keyboard->keyToScanCode(qtKey)) {
535 if (pressed)
536 d->keyboard->sendKeyPressEvent(scanCode);
537 else
538 d->keyboard->sendKeyReleaseEvent(scanCode);
539 } else {
540 qWarning() << "Can't send Wayland key event: Unable to get scan code for" << Qt::Key(qtKey);
541 }
542}
543
566void QWaylandSeat::sendUnicodeKeyEvent(uint unicode, bool pressed)
567{
568 if (!keyboardFocus()) {
569 qWarning("Can't send a unicode key event, no keyboard focus, fix the compositor");
570 return;
571 }
572
573#if QT_CONFIG(im)
574 auto eventType = pressed ? QEvent::KeyPress : QEvent::KeyRelease;
575 // make a keysym value for the UCS4
576 const uint keysym = 0x01000000 | unicode;
578 QKeyEvent event(eventType, Qt::Key_unknown, Qt::KeyboardModifiers{}, text);
579 if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV2)) {
581 if (textInput) {
582 textInput->sendKeyEvent(&event);
583 return;
584 }
585 }
586
589 if (textInputMethod) {
590 textInputMethod->sendKeyEvent(&event);
591 return;
592 }
593 }
594
595#if QT_WAYLAND_TEXT_INPUT_V4_WIP
596 if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV4)) {
598 if (textInputV4 && !text.isEmpty()) {
599 // it will just commit the text for text-input-unstable-v4-wip when keyPress
600 if (eventType == QEvent::KeyPress)
601 textInputV4->sendKeyEvent(&event);
602 return;
603 }
604 }
605#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
606#else
607 Q_UNUSED(keysym);
609 qWarning() << "Can't send a unicode key event: Unable to find a text-input protocol.";
610#endif
611}
612
617{
618 Q_D(const QWaylandSeat);
619 return d->keyboard.data();
620}
621
626{
627 Q_D(const QWaylandSeat);
628 if (d->keyboard.isNull() || !d->keyboard->focus())
629 return nullptr;
630
631 return d->keyboard->focus();
632}
633
640{
641 Q_D(QWaylandSeat);
642 if (surface && surface->isDestroyed())
643 return false;
644
645 QWaylandSurface *oldSurface = keyboardFocus();
646 if (surface == oldSurface)
647 return true;
648
649 d->keyboardFocus = surface;
650 if (!d->keyboard.isNull())
651 d->keyboard->setFocus(surface);
652#if QT_CONFIG(wayland_datadevice)
653 if (d->data_device)
654 d->data_device->setFocus(surface ? surface->client() : nullptr);
655#endif
656 emit keyboardFocusChanged(surface, oldSurface);
657 return true;
658}
659
660
666{
667 Q_D(const QWaylandSeat);
668 return d->keymap.data();
669}
670
675{
676 Q_D(const QWaylandSeat);
677 return d->pointer.data();
678}
679
684{
685 Q_D(const QWaylandSeat);
686 return d->touch.data();
687}
688
693{
694 Q_D(const QWaylandSeat);
695 return d->mouseFocus;
696}
697
702{
703 Q_D(QWaylandSeat);
704 if (view == d->mouseFocus)
705 return;
706
707 QWaylandView *oldFocus = d->mouseFocus;
708 d->mouseFocus = view;
709
710 if (oldFocus)
711 disconnect(oldFocus, &QObject::destroyed, this, &QWaylandSeat::handleMouseFocusDestroyed);
712 if (d->mouseFocus)
713 connect(d->mouseFocus, &QObject::destroyed, this, &QWaylandSeat::handleMouseFocusDestroyed);
714
715 emit mouseFocusChanged(d->mouseFocus, oldFocus);
716}
717
722{
723 Q_D(const QWaylandSeat);
724 return d->compositor;
725}
726
730#if QT_CONFIG(draganddrop)
731QWaylandDrag *QWaylandSeat::drag() const
732{
733 Q_D(const QWaylandSeat);
734 return d->drag_handle.data();
735}
736#endif
737
741QWaylandSeat::CapabilityFlags QWaylandSeat::capabilities() const
742{
743 Q_D(const QWaylandSeat);
744 return d->capabilities;
745}
746
750bool QWaylandSeat::isOwner(QInputEvent *inputEvent) const
751{
752 Q_UNUSED(inputEvent);
753 return true;
754}
755
760QWaylandSeat *QWaylandSeat::fromSeatResource(struct ::wl_resource *resource)
761{
762 if (auto p = QtWayland::fromResource<QWaylandSeatPrivate *>(resource))
763 return p->q_func();
764 return nullptr;
765}
766
773void QWaylandSeat::handleMouseFocusDestroyed()
774{
775 // This is triggered when the QWaylandView is destroyed, NOT the surface.
776 // ... so this is for the rare case when the view that currently holds the mouse focus is
777 // destroyed before its surface
778 Q_D(QWaylandSeat);
779 d->mouseFocus = nullptr;
780 QWaylandView *oldFocus = nullptr; // we have to send nullptr because the old focus is already destroyed at this point
781 emit mouseFocusChanged(d->mouseFocus, oldFocus);
782}
783
784
850
851#include "moc_qwaylandseat.cpp"
@ KeyRelease
Definition qcoreevent.h:65
@ KeyPress
Definition qcoreevent.h:64
\inmodule QtGui
Definition qevent.h:49
The QKeyEvent class describes a key event.
Definition qevent.h:423
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
\inmodule QtCore\reentrant
Definition qpoint.h:214
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
The QTouchEvent class contains parameters that describe a touch event.
Definition qevent.h:916
\qmltype WaylandClient \instantiates QWaylandClient \inqmlmodule QtWayland.Compositor
static QWaylandClient * fromWlClient(QWaylandCompositor *compositor, wl_client *wlClient)
Returns the QWaylandClient corresponding to the Wayland client wlClient and compositor.
static QWaylandTextInput * findIn(QWaylandObject *container)
If any instance of the interface has been registered with container, this is returned.
QWaylandKeyboard * callCreateKeyboardDevice(QWaylandSeat *seat)
QWaylandPointer * callCreatePointerDevice(QWaylandSeat *seat)
static QWaylandCompositorPrivate * get(QWaylandCompositor *compositor)
QWaylandTouch * callCreateTouchDevice(QWaylandSeat *seat)
\qmltype WaylandCompositor \instantiates QWaylandCompositor \inqmlmodule QtWayland....
void checkAndRepairModifierState(QKeyEvent *ke)
static QWaylandKeyboardPrivate * get(QWaylandKeyboard *keyboard)
\inmodule QtWaylandCompositor
virtual void setFocus(QWaylandSurface *surface)
Sets the current focus to surface.
virtual void addClient(QWaylandClient *client, uint32_t id, uint32_t version)
\inmodule QtWaylandCompositor
\inmodule QtWaylandCompositor
~QWaylandSeatPrivate() override
void seat_get_keyboard(wl_seat::Resource *resource, uint32_t id) override
void seat_get_pointer(wl_seat::Resource *resource, uint32_t id) override
QWaylandSeatPrivate(QWaylandSeat *seat)
void seat_destroy_resource(wl_seat::Resource *resource) override
void seat_get_touch(wl_seat::Resource *resource, uint32_t id) override
void seat_bind_resource(wl_seat::Resource *resource) override
void setCapabilities(QWaylandSeat::CapabilityFlags caps)
\qmltype WaylandSeat \instantiates QWaylandSeat \inqmlmodule QtWayland.Compositor
~QWaylandSeat() override
Destroys the QWaylandSeat.
QWaylandSeat::CapabilityFlags capabilities() const
Returns the drag object for this QWaylandSeat.
void keyboardFocusChanged(QWaylandSurface *newFocus, QWaylandSurface *oldFocus)
\qmlsignal void QtWayland.Compositor::WaylandSeat::keyboardFocusChanged(QWaylandSurface newFocus,...
QWaylandKeymap * keymap
Returns the keymap object for this QWaylandSeat.
QWaylandSeat(QWaylandCompositor *compositor, CapabilityFlags capabilityFlags=DefaultCapabilities)
Constructs a QWaylandSeat for the given compositor and capabilityFlags.
void sendMouseMoveEvent(QWaylandView *surface, const QPointF &localPos, const QPointF &outputSpacePos=QPointF())
Sets the mouse focus to view and sends a mouse move event to the pointer device with the local positi...
Q_INVOKABLE uint sendTouchPointReleased(QWaylandSurface *surface, int id, const QPointF &position)
\qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchPointReleased(WaylandSurface surface,...
void sendMouseReleaseEvent(Qt::MouseButton button)
Sends a mouse release event for button to the QWaylandSeat's pointer device.
void setMouseFocus(QWaylandView *view)
Sets the current mouse focus to view.
void sendFullTouchEvent(QWaylandSurface *surface, QTouchEvent *event)
Sends the event to the specified surface on the touch device.
void sendMousePressEvent(Qt::MouseButton button)
Sends a mouse press event for button to the QWaylandSeat's pointer device.
QWaylandKeyboard * keyboard() const
Returns the keyboard for this input device.
void sendKeyReleaseEvent(uint code)
Sends a key release event with the key code to the keyboard device.
Q_INVOKABLE void sendKeyEvent(int qtKey, bool pressed)
\qmlmethod void QtWayland.Compositor::WaylandSeat::sendKeyEvent(int qtKey, bool pressed)
bool isInitialized() const
Returns true if the QWaylandSeat is initialized; false otherwise.
void cursorSurfaceRequested(QWaylandSurface *surface, int hotspotX, int hotspotY, QWaylandClient *client)
QWaylandPointer * pointer() const
Returns the pointer device for this QWaylandSeat.
static QWaylandSeat * fromSeatResource(struct ::wl_resource *resource)
Returns the QWaylandSeat corresponding to the resource.
void sendFullKeyEvent(QKeyEvent *event)
Sends the event to the keyboard device.
QWaylandSurface * keyboardFocus() const
Returns the current focused surface for keyboard input.
QWaylandTouch * touch() const
Returns the touch device for this QWaylandSeat.
QWaylandView * mouseFocus() const
Returns the view that currently has mouse focus.
bool setKeyboardFocus(QWaylandSurface *surface)
Sets the current keyboard focus to surface.
void sendMouseWheelEvent(Qt::Orientation orientation, int delta)
Sends a mouse wheel event to the QWaylandSeat's pointer device with the given orientation and delta.
Q_INVOKABLE void sendTouchFrameEvent(QWaylandClient *client)
\qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchFrameEvent(WaylandClient client)
Q_INVOKABLE uint sendTouchPointPressed(QWaylandSurface *surface, int id, const QPointF &position)
\qmlmethod uint QtWayland.Compositor::WaylandSeat::sendTouchPointPressed(WaylandSurface surface,...
virtual void initialize()
Initializes parts of the seat corresponding to the capabilities set in the constructor,...
uint sendTouchPointEvent(QWaylandSurface *surface, int id, const QPointF &point, Qt::TouchPointState state)
Sends a touch point event to the surface on a touch device with the given id, point and state.
QWaylandCompositor * compositor() const
Returns the compositor for this QWaylandSeat.
virtual bool isOwner(QInputEvent *inputEvent) const
Q_INVOKABLE void sendTouchCancelEvent(QWaylandClient *client)
\qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchCancelEvent(WaylandClient client)
Q_INVOKABLE uint sendTouchPointMoved(QWaylandSurface *surface, int id, const QPointF &position)
\qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchPointMoved(WaylandSurface surface,...
void sendKeyPressEvent(uint code)
Sends a key press event with the key code to the keyboard device.
void mouseFocusChanged(QWaylandView *newFocus, QWaylandView *oldFocus)
This signal is emitted when the mouse focus has changed from oldFocus to newFocus.
\qmltype WaylandSurface \instantiates QWaylandSurface \inqmlmodule QtWayland.Compositor
QWaylandClient * client
\qmlproperty WaylandClient QtWayland.Compositor::WaylandSurface::client
Q_INVOKABLE bool isDestroyed() const
\qmlmethod bool QtWayland.Compositor::WaylandSurface::isDestroyed()
void sendKeyEvent(QKeyEvent *event)
void sendKeyEvent(QKeyEvent *event)
\inmodule QtWaylandCompositor
virtual void addClient(QWaylandClient *client, uint32_t id, uint32_t version)
\qmltype WaylandView \instantiates QWaylandView \inqmlmodule QtWayland.Compositor
static QString lookupStringNoKeysymTransformations(xkb_keysym_t keysym)
#define this
Definition dialogs.cpp:9
QString text
QPushButton * button
[2]
else opt state
[0]
Combined button and popup list for selecting options.
MouseButton
Definition qnamespace.h:55
Orientation
Definition qnamespace.h:97
@ Key_unknown
TouchPointState
@ TouchPointReleased
@ TouchPointPressed
@ TouchPointMoved
#define qWarning
Definition qlogging.h:162
static QOpenGLCompositor * compositor
struct _cl_event * event
GLsizei const void * pointer
Definition qopenglext.h:384
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static QString qtKey(CFStringRef cfkey)
#define QT_CONFIG(feature)
#define emit
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:29
bool testFlag(MaskType mask, FlagType flag)
#define enabled
if(qFloatDistance(a, b)<(1<< 7))
[0]
myObject disconnect()
[26]
QQuickView * view
[0]