diff options
17 files changed, 1206 insertions, 665 deletions
diff --git a/src/compositor/compositor_api/qwaylandinput.cpp b/src/compositor/compositor_api/qwaylandinput.cpp index c73784eb..76e83030 100644 --- a/src/compositor/compositor_api/qwaylandinput.cpp +++ b/src/compositor/compositor_api/qwaylandinput.cpp @@ -41,6 +41,7 @@ #include "qwaylandinput.h" #include "qwlinputdevice_p.h" +#include "qwlkeyboard_p.h" #include "qwaylandcompositor.h" #include "qwlsurface_p.h" #include "qwlcompositor_p.h" @@ -88,12 +89,12 @@ void QWaylandInputDevice::sendMouseWheelEvent(Qt::Orientation orientation, int d void QWaylandInputDevice::sendKeyPressEvent(uint code) { - d->sendKeyPressEvent(code); + d->keyboardDevice()->sendKeyPressEvent(code); } void QWaylandInputDevice::sendKeyReleaseEvent(uint code) { - d->sendKeyReleaseEvent(code); + d->keyboardDevice()->sendKeyReleaseEvent(code); } void QWaylandInputDevice::sendTouchPointEvent(int id, double x, double y, Qt::TouchPointState state) diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp index f60a3fa4..b00f6700 100644 --- a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp +++ b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp @@ -201,8 +201,8 @@ void QWaylandSurfaceItem::mousePressEvent(QMouseEvent *event) if (m_surface) { QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice(); if (inputDevice->mouseFocus() != m_surface) - inputDevice->setMouseFocus(m_surface, event->pos(), event->globalPos()); - inputDevice->sendMousePressEvent(event->button(), toSurface(event->pos()), event->globalPos()); + inputDevice->setMouseFocus(m_surface, event->localPos(), event->windowPos()); + inputDevice->sendMousePressEvent(event->button(), event->localPos(), event->windowPos()); } } @@ -210,7 +210,7 @@ void QWaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event) { if (m_surface){ QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice(); - inputDevice->sendMouseMoveEvent(m_surface, toSurface(event->pos()), event->globalPos()); + inputDevice->sendMouseMoveEvent(m_surface, event->localPos(), event->windowPos()); } } @@ -218,7 +218,7 @@ void QWaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event) { if (m_surface){ QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice(); - inputDevice->sendMouseReleaseEvent(event->button(), toSurface(event->pos()), event->globalPos()); + inputDevice->sendMouseReleaseEvent(event->button(), event->localPos(), event->windowPos()); } } @@ -274,11 +274,6 @@ void QWaylandSurfaceItem::takeFocus() } } -QPoint QWaylandSurfaceItem::toSurface(const QPointF &pos) const -{ - return pos.toPoint(); -} - void QWaylandSurfaceItem::surfaceMapped() { setPaintEnabled(true); diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.h b/src/compositor/compositor_api/qwaylandsurfaceitem.h index c6a5cff8..93a0c62c 100644 --- a/src/compositor/compositor_api/qwaylandsurfaceitem.h +++ b/src/compositor/compositor_api/qwaylandsurfaceitem.h @@ -134,7 +134,6 @@ protected: private: friend class QWaylandSurfaceNode; void updateTexture(); - QPoint toSurface(const QPointF &pos) const; void init(QWaylandSurface *); void ensureProvider(); diff --git a/src/compositor/wayland_wrapper/qwlcompositor.cpp b/src/compositor/wayland_wrapper/qwlcompositor.cpp index 57b7cdbd..ceded93b 100644 --- a/src/compositor/wayland_wrapper/qwlcompositor.cpp +++ b/src/compositor/wayland_wrapper/qwlcompositor.cpp @@ -51,10 +51,11 @@ #include "qwlextendedsurface_p.h" #include "qwlsubsurface_p.h" #include "qwlshellsurface_p.h" -#include "qwltouch_p.h" +#include "qwlqttouch_p.h" #include "qwlqtkey_p.h" #include "qwlinputdevice_p.h" #include "qwlregion_p.h" +#include "qwlpointer_p.h" #include <QWindow> #include <QSocketNotifier> @@ -277,7 +278,10 @@ void Compositor::surfaceDestroyed(Surface *surface) // Make sure the surface is reset regardless of what the grabber // interface's focus() does. (e.g. the default implementation does // nothing when a button is down which would be disastrous here) - wl_pointer_set_focus(dev->pointerDevice(), 0, 0, 0); + dev->pointerDevice()->setFocus(0, QPointF()); + } + if (dev->pointerDevice()->current() == surface) { + dev->pointerDevice()->setCurrent(0, QPointF()); } if (dev->keyboardFocus() == surface) dev->setKeyboardFocus(0); diff --git a/src/compositor/wayland_wrapper/qwlinputdevice.cpp b/src/compositor/wayland_wrapper/qwlinputdevice.cpp index d0a5d753..d9a91bfa 100644 --- a/src/compositor/wayland_wrapper/qwlinputdevice.cpp +++ b/src/compositor/wayland_wrapper/qwlinputdevice.cpp @@ -43,23 +43,15 @@ #include "qwlcompositor_p.h" #include "qwldatadevice_p.h" #include "qwlsurface_p.h" -#include "qwltouch_p.h" +#include "qwlqttouch_p.h" #include "qwlqtkey_p.h" #include "qwaylandcompositor.h" +#include "qwlpointer_p.h" +#include "qwlkeyboard_p.h" +#include "qwltouch_p.h" #include <QtGui/QTouchEvent> -#ifndef QT_NO_WAYLAND_XKB -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/epoll.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#endif - QT_BEGIN_NAMESPACE namespace QtWayland { @@ -68,146 +60,54 @@ InputDevice::InputDevice(QWaylandInputDevice *handle, Compositor *compositor) : QtWaylandServer::wl_seat(compositor->wl_display()) , m_handle(handle) , m_compositor(compositor) + , m_pointer(new Pointer(m_compositor, this)) + , m_keyboard(new Keyboard(m_compositor, this)) + , m_touch(new Touch(m_compositor)) { - wl_seat_init(&m_seat); - initDevices(); - -#ifndef QT_NO_WAYLAND_XKB - xkb_rule_names xkb_names; - xkb_context *context = xkb_context_new(xkb_context_flags(0)); - - memset(&xkb_names, 0, sizeof(xkb_names)); - xkb_names.rules = strdup("evdev"); - xkb_names.model = strdup("pc105"); - xkb_names.layout = strdup("us"); - - xkb_keymap *keymap = xkb_map_new_from_names(context, &xkb_names, xkb_map_compile_flags(0)); - if (!keymap) - qFatal("Failed to compile global XKB keymap"); - - char *keymap_str_data = xkb_map_get_as_string(keymap); - QByteArray keymap_str = keymap_str_data; - m_keymap_size = keymap_str.size() + 1; - free(keymap_str_data); - - const char *path = getenv("XDG_RUNTIME_DIR"); - if (!path) - qFatal("XDG_RUNTIME_DIR not set"); - - QByteArray name = QByteArray(path) + "/qtwayland-xkb-map-XXXXXX"; - - int fd = mkstemp(name.data()); - if (fd >= 0) { - long flags = fcntl(fd, F_GETFD); - if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { - close(fd); - qFatal("Failed to set FD_CLOEXEC on anonymous file"); - } - unlink(name.data()); - } else { - qFatal("Failed to create anonymous file with name %s", name.constData()); - } - - if (ftruncate(fd, m_keymap_size) < 0) - qFatal("Failed to create anonymous file of size %lu", (unsigned long)m_keymap_size); - - m_keymap_fd = fd; - - m_keymap_area = (char *)mmap(0, m_keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_keymap_fd, 0); - if (m_keymap_area == MAP_FAILED) { - close(m_keymap_fd); - qFatal("Failed to map shared memory segment"); - } - - strcpy(m_keymap_area, keymap_str.constData()); - - m_state = xkb_state_new(keymap); - - free((char *)xkb_names.rules); - free((char *)xkb_names.model); - free((char *)xkb_names.layout); - xkb_map_unref(keymap); - xkb_context_unref(context); -#endif } InputDevice::~InputDevice() { qDeleteAll(m_data_devices); - releaseDevices(); - -#ifndef QT_NO_WAYLAND_XKB - if (m_keymap_area) - munmap(m_keymap_area, m_keymap_size); - close(m_keymap_fd); - xkb_state_unref(m_state); -#endif } -void InputDevice::initDevices() +Pointer *InputDevice::pointerDevice() { - wl_pointer_init(&m_device_interfaces.pointer); - wl_seat_set_pointer(&m_seat, &m_device_interfaces.pointer); - - wl_keyboard_init(&m_device_interfaces.keyboard); - wl_seat_set_keyboard(&m_seat, &m_device_interfaces.keyboard); - - wl_touch_init(&m_device_interfaces.touch); - wl_seat_set_touch(&m_seat, &m_device_interfaces.touch); + return m_pointer.data(); } -void InputDevice::releaseDevices() +Keyboard *InputDevice::keyboardDevice() { - wl_pointer_release(&m_device_interfaces.pointer); - wl_keyboard_release(&m_device_interfaces.keyboard); - wl_touch_release(&m_device_interfaces.touch); + return m_keyboard.data(); } -wl_pointer *InputDevice::pointerDevice() +Touch *InputDevice::touchDevice() { - return &m_device_interfaces.pointer; + return m_touch.data(); } -wl_keyboard *InputDevice::keyboardDevice() +const Pointer *InputDevice::pointerDevice() const { - return &m_device_interfaces.keyboard; + return m_pointer.data(); } -wl_touch *InputDevice::touchDevice() +const Keyboard *InputDevice::keyboardDevice() const { - return &m_device_interfaces.touch; + return m_keyboard.data(); } -const wl_pointer *InputDevice::pointerDevice() const +const Touch *InputDevice::touchDevice() const { - return &m_device_interfaces.pointer; -} - -const wl_keyboard *InputDevice::keyboardDevice() const -{ - return &m_device_interfaces.keyboard; -} - -const wl_touch *InputDevice::touchDevice() const -{ - return &m_device_interfaces.touch; + return m_touch.data(); } void InputDevice::seat_destroy_resource(wl_seat::Resource *resource) { - if (keyboardDevice()->focus_resource == resource->handle) - keyboardDevice()->focus_resource = 0; - - if (pointerDevice()->focus_resource == resource->handle) - pointerDevice()->focus_resource = 0; - cleanupDataDeviceForClient(resource->client(), true); } void InputDevice::seat_bind_resource(wl_seat::Resource *resource) { - wl_list_insert(&m_seat.base_resource_list, &resource->handle->link); - uint32_t caps = WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD; if (!QTouchDevice::devices().isEmpty()) caps |= WL_SEAT_CAPABILITY_TOUCH; @@ -215,82 +115,34 @@ void InputDevice::seat_bind_resource(wl_seat::Resource *resource) wl_seat::send_capabilities(resource->handle, caps); } -void InputDevice::pointer_set_cursor(wl_pointer::Resource *resource, - uint32_t serial, wl_resource *surface_resource, - int32_t hotspot_x, int32_t hotspot_y) -{ - Q_UNUSED(resource); - Q_UNUSED(serial); - - /* Hide cursor */ - if (!surface_resource) - { - m_compositor->waylandCompositor()->setCursorSurface(NULL, 0, 0); - return; - } - - QtWayland::Surface *surface = QtWayland::Surface::fromResource(surface_resource); - surface->setCursorSurface(true); - m_compositor->waylandCompositor()->setCursorSurface(surface->waylandSurface(), hotspot_x, hotspot_y); -} - void InputDevice::seat_get_pointer(wl_seat::Resource *resource, uint32_t id) { - ::wl_pointer *pointer = pointerDevice(); - wl_pointer::add(&pointer->resource_list, resource->client(), id); + m_pointer->add(resource->client(), id); } void InputDevice::seat_get_keyboard(wl_seat::Resource *resource, uint32_t id) { - ::wl_keyboard *keyboard = keyboardDevice(); - wl_keyboard::add(&keyboard->resource_list, resource->client(), id); -} - -void InputDevice::keyboard_bind_resource(wl_keyboard::Resource *resource) -{ -#ifndef QT_NO_WAYLAND_XKB - wl_keyboard::send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, - m_keymap_fd, m_keymap_size); -#endif + m_keyboard->add(resource->client(), id); } void InputDevice::seat_get_touch(wl_seat::Resource *resource, uint32_t id) { - ::wl_touch *touch = touchDevice(); - wl_touch::add(&touch->resource_list, resource->client(), id); + m_touch->add(resource->client(), id); } void InputDevice::sendMousePressEvent(Qt::MouseButton button, const QPointF &localPos, const QPointF &globalPos) { - sendMouseMoveEvent(localPos,globalPos); - ::wl_pointer *pointer = pointerDevice(); - pointer->button_count++; - uint32_t time = m_compositor->currentTimeMsecs(); - const struct wl_pointer_grab_interface *interface = pointer->grab->interface; - interface->button(pointer->grab, time, toWaylandButton(button), 1); + pointerDevice()->sendMousePressEvent(button, localPos, globalPos); } void InputDevice::sendMouseReleaseEvent(Qt::MouseButton button, const QPointF &localPos, const QPointF &globalPos) { - sendMouseMoveEvent(localPos,globalPos); - ::wl_pointer *pointer = pointerDevice(); - pointer->button_count--; - uint32_t time = m_compositor->currentTimeMsecs(); - const struct wl_pointer_grab_interface *interface = pointer->grab->interface; - interface->button(pointer->grab, time, toWaylandButton(button), 0); + pointerDevice()->sendMouseReleaseEvent(button, localPos, globalPos); } void InputDevice::sendMouseMoveEvent(const QPointF &localPos, const QPointF &globalPos) { - Q_UNUSED(globalPos); - uint32_t time = m_compositor->currentTimeMsecs(); - ::wl_pointer *pointer = pointerDevice(); - const struct wl_pointer_grab_interface *interface = pointer->grab->interface; - pointer->x = wl_fixed_from_double(globalPos.x()); - pointer->y = wl_fixed_from_double(globalPos.y()); - interface->motion(pointer->grab, - time, - wl_fixed_from_double(localPos.x()), wl_fixed_from_double(localPos.y())); + pointerDevice()->sendMouseMoveEvent(localPos, globalPos); } void InputDevice::sendMouseMoveEvent(Surface *surface, const QPointF &localPos, const QPointF &globalPos) @@ -301,100 +153,20 @@ void InputDevice::sendMouseMoveEvent(Surface *surface, const QPointF &localPos, void InputDevice::sendMouseWheelEvent(Qt::Orientation orientation, int delta) { - ::wl_pointer *pointer = pointerDevice(); - struct wl_resource *resource = pointer->focus_resource; - if (!resource) - return; - uint32_t time = m_compositor->currentTimeMsecs(); - uint32_t axis = orientation == Qt::Horizontal ? WL_POINTER_AXIS_HORIZONTAL_SCROLL - : WL_POINTER_AXIS_VERTICAL_SCROLL; - wl_pointer_send_axis(resource, time, axis, wl_fixed_from_int(-delta / 12)); -} - -void InputDevice::updateModifierState(uint code, int state) -{ -#ifndef QT_NO_WAYLAND_XKB - xkb_state_update_key(m_state, code, state ? XKB_KEY_DOWN : XKB_KEY_UP); - - uint32_t mods_depressed = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_DEPRESSED); - uint32_t mods_latched = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_LATCHED); - uint32_t mods_locked = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_LATCHED); - uint32_t group = xkb_state_serialize_group(m_state, (xkb_state_component)XKB_STATE_EFFECTIVE); - - ::wl_keyboard *keyboard = keyboardDevice(); - - if (mods_depressed == keyboard->modifiers.mods_depressed - && mods_latched == keyboard->modifiers.mods_latched - && mods_locked == keyboard->modifiers.mods_locked - && group == keyboard->modifiers.group) - { - return; // no change - } - - keyboard->modifiers.mods_depressed = mods_depressed; - keyboard->modifiers.mods_latched = mods_latched; - keyboard->modifiers.mods_locked = mods_locked; - keyboard->modifiers.group = group; - - if (keyboard->focus_resource) - sendKeyModifiers(keyboard->focus_resource); -#else - Q_UNUSED(code); - Q_UNUSED(state); -#endif -} - -void InputDevice::sendKeyModifiers(wl_resource *resource) -{ - ::wl_keyboard *keyboard = keyboardDevice(); - uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); - wl_keyboard_send_modifiers(resource, serial, keyboard->modifiers.mods_depressed, - keyboard->modifiers.mods_latched, keyboard->modifiers.mods_locked, keyboard->modifiers.group); -} - -void InputDevice::sendKeyPressEvent(uint code) -{ - ::wl_keyboard *keyboard = keyboardDevice(); - if (keyboard->focus_resource) { - uint32_t time = m_compositor->currentTimeMsecs(); - uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); - wl_keyboard_send_key(keyboard->focus_resource, - serial, time, code - 8, 1); - } - updateModifierState(code, 1); -} - -void InputDevice::sendKeyReleaseEvent(uint code) -{ - ::wl_keyboard *keyboard = keyboardDevice(); - if (keyboard->focus_resource) { - uint32_t time = m_compositor->currentTimeMsecs(); - uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); - wl_keyboard_send_key(keyboard->focus_resource, - serial, time, code - 8, 0); - } - updateModifierState(code, 0); + pointerDevice()->sendMouseWheelEvent(orientation, delta); } void InputDevice::sendTouchPointEvent(int id, double x, double y, Qt::TouchPointState state) { - uint32_t time = m_compositor->currentTimeMsecs(); - uint32_t serial = 0; - ::wl_touch *touch = touchDevice(); - wl_resource *resource = touch->focus_resource; - if (!resource) - return; switch (state) { case Qt::TouchPointPressed: - wl_touch_send_down(resource, serial, time, &touch->focus->resource, id, - wl_fixed_from_double(x), wl_fixed_from_double(y)); + m_touch->sendDown(id, QPointF(x, y)); break; case Qt::TouchPointMoved: - wl_touch_send_motion(resource, time, id, - wl_fixed_from_double(x), wl_fixed_from_double(y)); + m_touch->sendMotion(id, QPointF(x, y)); break; case Qt::TouchPointReleased: - wl_touch_send_up(resource, serial, time, id); + m_touch->sendUp(id); break; case Qt::TouchPointStationary: // stationary points are not sent through wayland, the client must cache them @@ -406,18 +178,12 @@ void InputDevice::sendTouchPointEvent(int id, double x, double y, Qt::TouchPoint void InputDevice::sendTouchFrameEvent() { - ::wl_touch *touch = touchDevice(); - wl_resource *resource = touch->focus_resource; - if (resource) - wl_touch_send_frame(resource); + m_touch->sendFrame(); } void InputDevice::sendTouchCancelEvent() { - ::wl_touch *touch = touchDevice(); - wl_resource *resource = touch->focus_resource; - if (resource) - wl_touch_send_cancel(resource); + m_touch->sendCancel(); } void InputDevice::sendFullKeyEvent(QKeyEvent *event) @@ -432,9 +198,9 @@ void InputDevice::sendFullKeyEvent(QKeyEvent *event) return; if (event->type() == QEvent::KeyPress) - sendKeyPressEvent(event->nativeScanCode()); + m_keyboard->sendKeyPressEvent(event->nativeScanCode()); else if (event->type() == QEvent::KeyRelease) - sendKeyReleaseEvent(event->nativeScanCode()); + m_keyboard->sendKeyReleaseEvent(event->nativeScanCode()); } void InputDevice::sendFullTouchEvent(QTouchEvent *event) @@ -470,7 +236,7 @@ void InputDevice::sendFullTouchEvent(QTouchEvent *event) Surface *InputDevice::keyboardFocus() const { - return static_cast<Surface *>(keyboardDevice()->focus); + return m_keyboard->focus(); } /*! @@ -482,31 +248,22 @@ bool InputDevice::setKeyboardFocus(Surface *surface) return false; sendSelectionFocus(surface); - wl_keyboard_set_focus(keyboardDevice(), surface); + m_keyboard->setFocus(surface); return true; } Surface *InputDevice::mouseFocus() const { - return static_cast<Surface *>(pointerDevice()->focus); + return m_pointer->focusSurface(); } void InputDevice::setMouseFocus(Surface *surface, const QPointF &localPos, const QPointF &globalPos) { - ::wl_pointer *pointer = pointerDevice(); - pointer->x = wl_fixed_from_double(globalPos.x()); - pointer->y = wl_fixed_from_double(globalPos.y()); - pointer->current = surface; - pointer->current_x = wl_fixed_from_double(localPos.x()); - pointer->current_y = wl_fixed_from_double(localPos.y()); - pointer->grab->interface->focus(pointer->grab, surface, - wl_fixed_from_double(localPos.x()), wl_fixed_from_double(localPos.y())); + m_pointer->setMouseFocus(surface, localPos, globalPos); // We have no separate touch focus management so make it match the pointer focus always. // No wl_touch_set_focus() is available so set it manually. - ::wl_touch *touch = touchDevice(); - touch->focus = surface; - touch->focus_resource = Compositor::resourceForSurface(&touch->resource_list, surface); + m_touch->setFocus(surface); } void InputDevice::cleanupDataDeviceForClient(struct wl_client *client, bool destroyDev) @@ -550,35 +307,6 @@ QWaylandInputDevice *InputDevice::handle() const return m_handle; } -uint32_t InputDevice::toWaylandButton(Qt::MouseButton button) -{ -#ifndef BTN_LEFT - uint32_t BTN_LEFT = 0x110; -#endif - // the range of valid buttons (evdev module) is from 0x110 - // through 0x11f. 0x120 is the first 'Joystick' button. - switch (button) { - case Qt::LeftButton: return BTN_LEFT; - case Qt::RightButton: return uint32_t(0x111); - case Qt::MiddleButton: return uint32_t(0x112); - case Qt::ExtraButton1: return uint32_t(0x113); // AKA Qt::BackButton, Qt::XButton1 - case Qt::ExtraButton2: return uint32_t(0x114); // AKA Qt::ForwardButton, Qt::XButton2 - case Qt::ExtraButton3: return uint32_t(0x115); - case Qt::ExtraButton4: return uint32_t(0x116); - case Qt::ExtraButton5: return uint32_t(0x117); - case Qt::ExtraButton6: return uint32_t(0x118); - case Qt::ExtraButton7: return uint32_t(0x119); - case Qt::ExtraButton8: return uint32_t(0x11a); - case Qt::ExtraButton9: return uint32_t(0x11b); - case Qt::ExtraButton10: return uint32_t(0x11c); - case Qt::ExtraButton11: return uint32_t(0x11d); - case Qt::ExtraButton12: return uint32_t(0x11e); - case Qt::ExtraButton13: return uint32_t(0x11f); - // default should not occur; but if it does, then return Wayland's highest possible button number. - default: return uint32_t(0x11f); - } -} - DataDevice *InputDevice::dataDevice(struct wl_client *client) const { for (int i = 0; i < m_data_devices.size();i++) { diff --git a/src/compositor/wayland_wrapper/qwlinputdevice_p.h b/src/compositor/wayland_wrapper/qwlinputdevice_p.h index fd1b0fb4..8ad8a0a7 100644 --- a/src/compositor/wayland_wrapper/qwlinputdevice_p.h +++ b/src/compositor/wayland_wrapper/qwlinputdevice_p.h @@ -45,6 +45,7 @@ #include <QtCore/QList> #include <QtCore/QPoint> +#include <QtCore/QScopedPointer> #ifndef QT_NO_WAYLAND_XKB #include <xkbcommon/xkbcommon.h> @@ -64,8 +65,11 @@ class Compositor; class DataDevice; class Surface; class DataDeviceManager; +class Pointer; +class Keyboard; +class Touch; -class InputDevice : public QtWaylandServer::wl_seat, public QtWaylandServer::wl_pointer, public QtWaylandServer::wl_keyboard, public QtWaylandServer::wl_touch +class InputDevice : public QtWaylandServer::wl_seat, public QtWaylandServer::wl_touch { public: InputDevice(QWaylandInputDevice *handle, Compositor *compositor); @@ -77,9 +81,6 @@ public: void sendMouseMoveEvent(Surface *surface, const QPointF &localPos, const QPointF &globalPos = QPointF()); void sendMouseWheelEvent(Qt::Orientation orientation, int delta); - void sendKeyPressEvent(uint code); - void sendKeyReleaseEvent(uint code); - void sendTouchPointEvent(int id, double x, double y, Qt::TouchPointState state); void sendTouchFrameEvent(); void sendTouchCancelEvent(); @@ -100,13 +101,13 @@ public: Compositor *compositor() const; QWaylandInputDevice *handle() const; - ::wl_pointer *pointerDevice(); - ::wl_keyboard *keyboardDevice(); - ::wl_touch *touchDevice(); + Pointer *pointerDevice(); + Keyboard *keyboardDevice(); + Touch *touchDevice(); - const ::wl_pointer *pointerDevice() const; - const ::wl_keyboard *keyboardDevice() const; - const ::wl_touch *touchDevice() const; + const Pointer *pointerDevice() const; + const Keyboard *keyboardDevice() const; + const Touch *touchDevice() const; static InputDevice *fromSeatResource(struct ::wl_resource *resource) { @@ -114,44 +115,18 @@ public: } private: - void initDevices(); - void releaseDevices(); void cleanupDataDeviceForClient(struct wl_client *client, bool destroyDev); - void updateModifierState(uint key, int state); - void sendKeyModifiers(wl_resource *resource); QWaylandInputDevice *m_handle; Compositor *m_compositor; QList<DataDevice *> m_data_devices; - struct { - ::wl_pointer pointer; - ::wl_keyboard keyboard; - ::wl_touch touch; - } m_device_interfaces; - - ::wl_seat m_seat; - -#ifndef QT_NO_WAYLAND_XKB - struct xkb_keymap *m_keymap; - struct xkb_state *m_state; - int m_keymap_fd; - size_t m_keymap_size; - char *m_keymap_area; -#endif - - uint32_t toWaylandButton(Qt::MouseButton button); + QScopedPointer<Pointer> m_pointer; + QScopedPointer<Keyboard> m_keyboard; + QScopedPointer<Touch> m_touch; void seat_bind_resource(wl_seat::Resource *resource) Q_DECL_OVERRIDE; - void pointer_set_cursor(wl_pointer::Resource *resource, - uint32_t serial, - struct wl_resource *surface, - int32_t hotspot_x, - int32_t hotspot_y) Q_DECL_OVERRIDE; - - void keyboard_bind_resource(wl_keyboard::Resource *resource) Q_DECL_OVERRIDE; - void seat_get_pointer(wl_seat::Resource *resource, uint32_t id) Q_DECL_OVERRIDE; void seat_get_keyboard(wl_seat::Resource *resource, diff --git a/src/compositor/wayland_wrapper/qwlkeyboard.cpp b/src/compositor/wayland_wrapper/qwlkeyboard.cpp new file mode 100644 index 00000000..0ca283c8 --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlkeyboard.cpp @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwlkeyboard_p.h" + +#include <QFile> +#include <QStandardPaths> + +#include "qwlcompositor_p.h" +#include "qwlsurface_p.h" + +#ifndef QT_NO_WAYLAND_XKB +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#endif + +namespace QtWayland { + +Keyboard::Keyboard(Compositor *compositor, InputDevice *seat) + : QtWaylandServer::wl_keyboard() + , m_compositor(compositor) + , m_seat(seat) + , m_focus() + , m_focusResource() + , m_keys() + , m_modsDepressed() + , m_modsLatched() + , m_modsLocked() + , m_group() +{ +#ifndef QT_NO_WAYLAND_XKB + initXKB(); +#endif +} + +Keyboard::~Keyboard() +{ +#ifndef QT_NO_WAYLAND_XKB + if (m_keymap_area) + munmap(m_keymap_area, m_keymap_size); + close(m_keymap_fd); + xkb_state_unref(m_state); +#endif +} + +void Keyboard::setFocus(Surface *surface) +{ + if (m_focusResource && m_focus != surface) { + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); + } + + struct ::wl_resource *r = Compositor::resourceForSurface(resourceList(), surface); + Resource *resource = r ? Resource::fromResource(r) : 0; + + if (resource && (m_focus != surface || m_focusResource != resource)) { + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + send_modifiers(resource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); + send_enter(resource->handle, serial, surface->resource()->handle, m_keys); + } + + m_focusResource = resource; + m_focus = surface; +} + +void Keyboard::sendKeyModifiers(wl_keyboard::Resource *resource, uint32_t serial) +{ + send_modifiers(resource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); +} + +void Keyboard::sendKeyPressEvent(uint code) +{ + sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_PRESSED); +} + +void Keyboard::sendKeyReleaseEvent(uint code) +{ + sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED); +} + +Surface *Keyboard::focus() const +{ + return m_focus; +} + +void Keyboard::keyboard_bind_resource(wl_keyboard::Resource *resource) +{ +#ifndef QT_NO_WAYLAND_XKB + send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + m_keymap_fd, m_keymap_size); +#else + int null_fd = open("/dev/null", O_RDONLY); + send_keymap(resource->handle, 0 /* WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP */, + null_fd, 0); + close(null_fd); +#endif +} + +void Keyboard::keyboard_destroy_resource(wl_keyboard::Resource *resource) +{ + if (m_focusResource == resource) + m_focusResource = 0; +} + +void Keyboard::sendKeyEvent(uint code, uint32_t state) +{ + if (m_focusResource) { + uint32_t time = m_compositor->currentTimeMsecs(); + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + send_key(m_focusResource->handle, serial, time, code - 8, state); + } + updateModifierState(code, state); +} + +void Keyboard::updateModifierState(uint code, uint32_t state) +{ +#ifndef QT_NO_WAYLAND_XKB + xkb_state_update_key(m_state, code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); + + uint32_t modsDepressed = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_DEPRESSED); + uint32_t modsLatched = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_LATCHED); + uint32_t modsLocked = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_LATCHED); + uint32_t group = xkb_state_serialize_group(m_state, (xkb_state_component)XKB_STATE_EFFECTIVE); + + if (modsDepressed == m_modsDepressed + && modsLatched == m_modsLatched + && modsLocked == m_modsLocked + && group == m_group) + return; + + m_modsDepressed = modsDepressed; + m_modsLatched = modsLatched; + m_modsLocked = modsLocked; + m_group = group; + + if (m_focusResource) + sendKeyModifiers(m_focusResource, wl_display_next_serial(m_compositor->wl_display())); +#else + Q_UNUSED(code); + Q_UNUSED(state); +#endif +} + +#ifndef QT_NO_WAYLAND_XKB +static int createAnonymousFile(size_t size) +{ + QString path = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); + if (path.isEmpty()) + return -1; + + QByteArray name = QFile::encodeName(path + QStringLiteral("/qtwayland-XXXXXX")); + + int fd = mkstemp(name.data()); + if (fd < 0) + return -1; + + long flags = fcntl(fd, F_GETFD); + if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { + close(fd); + fd = -1; + } + unlink(name.constData()); + + if (fd < 0) + return -1; + + if (ftruncate(fd, size) < 0) + return -1; + + return fd; +} + +void Keyboard::initXKB() +{ + struct xkb_context *context = xkb_context_new(static_cast<xkb_context_flags>(0)); + + struct xkb_rule_names rule_names = {0, 0, 0, 0, 0}; + struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, &rule_names, static_cast<xkb_keymap_compile_flags>(0)); + + char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); + if (!keymap_str) + qFatal("Failed to compile global XKB keymap"); + + m_keymap_size = strlen(keymap_str) + 1; + m_keymap_fd = createAnonymousFile(m_keymap_size); + if (m_keymap_fd < 0) + qFatal("Failed to create anonymous file of size %lu", static_cast<unsigned long>(m_keymap_size)); + + m_keymap_area = static_cast<char *>(mmap(0, m_keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_keymap_fd, 0)); + if (m_keymap_area == MAP_FAILED) { + close(m_keymap_fd); + qFatal("Failed to map shared memory segment"); + } + + strcpy(m_keymap_area, keymap_str); + + m_state = xkb_state_new(keymap); + + xkb_keymap_unref(keymap); + xkb_context_unref(context); +} +#endif + +} // namespace QtWayland diff --git a/src/compositor/wayland_wrapper/qwlkeyboard_p.h b/src/compositor/wayland_wrapper/qwlkeyboard_p.h new file mode 100644 index 00000000..80b21106 --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlkeyboard_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidi ary(-ies). +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTWAYLAND_QWLKEYBOARD_P_H +#define QTWAYLAND_QWLKEYBOARD_P_H + +#include <qwayland-server-wayland.h> + +#include <QtCore/QByteArray> + +#ifndef QT_NO_WAYLAND_XKB +#include <xkbcommon/xkbcommon.h> +#endif + +QT_BEGIN_NAMESPACE + +namespace QtWayland { + +class Compositor; +class InputDevice; +class Surface; + +class Keyboard : public QtWaylandServer::wl_keyboard +{ +public: + Keyboard(Compositor *compositor, InputDevice *seat); + ~Keyboard(); + + void setFocus(Surface *surface); + + void sendKeyModifiers(Resource *resource, uint32_t serial); + void sendKeyPressEvent(uint code); + void sendKeyReleaseEvent(uint code); + + Surface *focus() const; + +protected: + void keyboard_bind_resource(Resource *resource); + void keyboard_destroy_resource(Resource *resource); + +private: + void sendKeyEvent(uint code, uint32_t state); + void updateModifierState(uint code, uint32_t state); + +#ifndef QT_NO_WAYLAND_XKB + void initXKB(); +#endif + + Compositor *m_compositor; + InputDevice *m_seat; + + Surface *m_focus; + Resource *m_focusResource; + + QByteArray m_keys; + uint32_t m_modsDepressed; + uint32_t m_modsLatched; + uint32_t m_modsLocked; + uint32_t m_group; + +#ifndef QT_NO_WAYLAND_XKB + size_t m_keymap_size; + int m_keymap_fd; + char *m_keymap_area; + struct xkb_state *m_state; +#endif +}; + +} // namespace QtWayland + +QT_END_NAMESPACE + +#endif // QTWAYLAND_QWLKEYBOARD_P_H diff --git a/src/compositor/wayland_wrapper/qwlpointer.cpp b/src/compositor/wayland_wrapper/qwlpointer.cpp new file mode 100644 index 00000000..c4f122a1 --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlpointer.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwlpointer_p.h" + +#include "qwlcompositor_p.h" +#include "qwlinputdevice_p.h" +#include "qwlkeyboard_p.h" +#include "qwlsurface_p.h" +#include "qwaylandcompositor.h" + +namespace QtWayland { + +using QtWaylandServer::wl_keyboard; + +static uint32_t toWaylandButton(Qt::MouseButton button) +{ +#ifndef BTN_LEFT + uint32_t BTN_LEFT = 0x110; +#endif + // the range of valid buttons (evdev module) is from 0x110 + // through 0x11f. 0x120 is the first 'Joystick' button. + switch (button) { + case Qt::LeftButton: return BTN_LEFT; + case Qt::RightButton: return uint32_t(0x111); + case Qt::MiddleButton: return uint32_t(0x112); + case Qt::ExtraButton1: return uint32_t(0x113); // AKA Qt::BackButton, Qt::XButton1 + case Qt::ExtraButton2: return uint32_t(0x114); // AKA Qt::ForwardButton, Qt::XButton2 + case Qt::ExtraButton3: return uint32_t(0x115); + case Qt::ExtraButton4: return uint32_t(0x116); + case Qt::ExtraButton5: return uint32_t(0x117); + case Qt::ExtraButton6: return uint32_t(0x118); + case Qt::ExtraButton7: return uint32_t(0x119); + case Qt::ExtraButton8: return uint32_t(0x11a); + case Qt::ExtraButton9: return uint32_t(0x11b); + case Qt::ExtraButton10: return uint32_t(0x11c); + case Qt::ExtraButton11: return uint32_t(0x11d); + case Qt::ExtraButton12: return uint32_t(0x11e); + case Qt::ExtraButton13: return uint32_t(0x11f); + // default should not occur; but if it does, then return Wayland's highest possible button number. + default: return uint32_t(0x11f); + } +} + +Pointer::Pointer(Compositor *compositor, InputDevice *seat) + : wl_pointer() + , PointerGrabber() + , m_compositor(compositor) + , m_seat(seat) + , m_grab(this) + , m_position(100, 100) + , m_focus() + , m_focusResource() + , m_current() + , m_currentPoint() + , m_buttonCount() +{ +} + +void Pointer::setFocus(Surface *surface, const QPointF &position) +{ + if (m_focusResource && m_focus != surface) { + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); + } + + struct ::wl_resource *r = Compositor::resourceForSurface(resourceList(), surface); + Resource *resource = r ? Resource::fromResource(r) : 0; + + if (resource && (m_focus != surface || resource != m_focusResource)) { + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + Keyboard *keyboard = m_seat->keyboardDevice(); + if (keyboard) { + struct ::wl_resource *kr = Compositor::resourceForSurface(keyboard->resourceList(), surface); + if (kr) + keyboard->sendKeyModifiers(wl_keyboard::Resource::fromResource(kr), serial); + } + send_enter(resource->handle, serial, surface->resource()->handle, + wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y())); + } + + m_focusResource = resource; + m_focus = surface; +} + +void Pointer::startGrab(PointerGrabber *grab) +{ + m_grab = grab; + grab->m_pointer = this; + + if (m_current) + grab->focus(); +} + +void Pointer::endGrab() +{ + m_grab = this; + m_grab->focus(); +} + +void Pointer::setCurrent(Surface *surface, const QPointF &point) +{ + m_current = surface; + m_currentPoint = point; +} + +bool Pointer::buttonPressed() const +{ + return m_buttonCount > 0; +} + +Surface *Pointer::focusSurface() const +{ + return m_focus; +} + +Surface *Pointer::current() const +{ + return m_current; +} + +QPointF Pointer::position() const +{ + return m_position; +} + +void Pointer::pointer_destroy_resource(wl_pointer::Resource *resource) +{ + if (m_focusResource == resource) + m_focusResource = 0; +} + +void Pointer::setMouseFocus(Surface *surface, const QPointF &localPos, const QPointF &globalPos) +{ + m_position = globalPos; + + m_current = surface; + m_currentPoint = localPos; + + m_grab->focus(); +} + +void Pointer::sendMousePressEvent(Qt::MouseButton button, const QPointF &localPos, const QPointF &globalPos) +{ + sendMouseMoveEvent(localPos, globalPos); + m_buttonCount++; + uint32_t time = m_compositor->currentTimeMsecs(); + m_grab->button(time, button, WL_POINTER_BUTTON_STATE_PRESSED); +} + +void Pointer::sendMouseReleaseEvent(Qt::MouseButton button, const QPointF &localPos, const QPointF &globalPos) +{ + sendMouseMoveEvent(localPos, globalPos); + m_buttonCount--; + uint32_t time = m_compositor->currentTimeMsecs(); + m_grab->button(time, button, WL_POINTER_BUTTON_STATE_RELEASED); +} + +void Pointer::sendMouseMoveEvent(const QPointF &localPos, const QPointF &globalPos) +{ + uint32_t time = m_compositor->currentTimeMsecs(); + + m_position = globalPos; + m_currentPoint = localPos; + + m_grab->motion(time); +} + +void Pointer::sendMouseWheelEvent(Qt::Orientation orientation, int delta) +{ + if (!m_focusResource) + return; + + uint32_t time = m_compositor->currentTimeMsecs(); + uint32_t axis = orientation == Qt::Horizontal ? WL_POINTER_AXIS_HORIZONTAL_SCROLL + : WL_POINTER_AXIS_VERTICAL_SCROLL; + send_axis(m_focusResource->handle, time, axis, wl_fixed_from_int(-delta / 12)); +} + +void Pointer::focus() +{ + if (buttonPressed()) + return; + + setFocus(m_current, m_currentPoint); +} + +void Pointer::motion(uint32_t time) +{ + if (m_focusResource) + send_motion(m_focusResource->handle, time, + wl_fixed_from_double(m_currentPoint.x()), + wl_fixed_from_double(m_currentPoint.y())); + +} + +void Pointer::button(uint32_t time, Qt::MouseButton button, uint32_t state) +{ + if (m_focusResource) { + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + send_button(m_focusResource->handle, serial, time, toWaylandButton(button), state); + } + + if (!buttonPressed() && state == WL_POINTER_BUTTON_STATE_RELEASED) + setFocus(m_current, m_currentPoint); +} + +void Pointer::pointer_set_cursor(wl_pointer::Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) +{ + Q_UNUSED(resource); + Q_UNUSED(serial); + + if (!surface) { + m_compositor->waylandCompositor()->setCursorSurface(NULL, 0, 0); + return; + } + + Surface *s = Surface::fromResource(surface); + s->setCursorSurface(true); + m_compositor->waylandCompositor()->setCursorSurface(s->waylandSurface(), hotspot_x, hotspot_y); +} + +PointerGrabber::~PointerGrabber() +{ +} + +} // namespace QtWayland diff --git a/src/compositor/wayland_wrapper/qwlpointer_p.h b/src/compositor/wayland_wrapper/qwlpointer_p.h new file mode 100644 index 00000000..f6db2dcb --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlpointer_p.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTWAYLAND_QWLPOINTER_P_H +#define QTWAYLAND_QWLPOINTER_P_H + +#include <QtCore/QList> +#include <QtCore/QPoint> + +#include <qwayland-server-wayland.h> + +#include <stdint.h> + +QT_BEGIN_NAMESPACE + +namespace QtWayland { + +class Compositor; +class InputDevice; +class Pointer; +class Surface; + +class PointerGrabber { +public: + virtual ~PointerGrabber(); + + virtual void focus() = 0; + virtual void motion(uint32_t time) = 0; + virtual void button(uint32_t time, Qt::MouseButton button, uint32_t state) = 0; + + Pointer *m_pointer; +}; + +class Pointer : public QtWaylandServer::wl_pointer, public PointerGrabber +{ +public: + Pointer(Compositor *compositor, InputDevice *seat); + + void setFocus(Surface *surface, const QPointF &position); + + void startGrab(PointerGrabber *grab); + void endGrab(); + + void setCurrent(Surface *surface, const QPointF &point); + void setMouseFocus(Surface *surface, const QPointF &localPos, const QPointF &globalPos); + + void sendMousePressEvent(Qt::MouseButton button, const QPointF &localPos, const QPointF &globalPos); + void sendMouseReleaseEvent(Qt::MouseButton button, const QPointF &localPos, const QPointF &globalPos); + void sendMouseMoveEvent(const QPointF &localPos, const QPointF &globalPos); + void sendMouseWheelEvent(Qt::Orientation orientation, int delta); + + Surface *focusSurface() const; + Surface *current() const; + QPointF position() const; + + void focus() Q_DECL_OVERRIDE; + void motion(uint32_t time) Q_DECL_OVERRIDE; + void button(uint32_t time, Qt::MouseButton button, uint32_t state) Q_DECL_OVERRIDE; + +protected: + void pointer_set_cursor(Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) Q_DECL_OVERRIDE; + void pointer_destroy_resource(Resource *resource) Q_DECL_OVERRIDE; + +private: + bool buttonPressed() const; + + Compositor *m_compositor; + InputDevice *m_seat; + + PointerGrabber *m_grab; + + QPointF m_position; + + Surface *m_focus; + Resource *m_focusResource; + + Surface *m_current; + QPointF m_currentPoint; + + int m_buttonCount; +}; + +} // namespace QtWayland + +QT_END_NAMESPACE + +#endif // QTWAYLAND_QWLPOINTER_P_H diff --git a/src/compositor/wayland_wrapper/qwlqttouch.cpp b/src/compositor/wayland_wrapper/qwlqttouch.cpp new file mode 100644 index 00000000..a5a266be --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlqttouch.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwlqttouch_p.h" +#include "qwlsurface_p.h" +#include <QTouchEvent> +#include <QWindow> + +QT_BEGIN_NAMESPACE + +namespace QtWayland { + +static void dummy(wl_client *, wl_resource *) +{ +} + +const struct qt_touch_extension_interface TouchExtensionGlobal::touch_interface = { + dummy +}; + +static const int maxRawPos = 24; + +TouchExtensionGlobal::TouchExtensionGlobal(Compositor *compositor) + : m_compositor(compositor), + m_flags(0) +{ + wl_array_init(&m_rawdata_array); + m_rawdata_ptr = static_cast<float *>(wl_array_add(&m_rawdata_array, maxRawPos * sizeof(float) * 2)); + + wl_display_add_global(compositor->wl_display(), + &qt_touch_extension_interface, + this, + TouchExtensionGlobal::bind_func); +} + +TouchExtensionGlobal::~TouchExtensionGlobal() +{ + wl_array_release(&m_rawdata_array); +} + +void TouchExtensionGlobal::destroy_resource(wl_resource *resource) +{ + TouchExtensionGlobal *self = static_cast<TouchExtensionGlobal *>(resource->data); + self->m_resources.removeOne(resource); + free(resource); +} + +void TouchExtensionGlobal::bind_func(wl_client *client, void *data, uint32_t version, uint32_t id) +{ + Q_UNUSED(version); + wl_resource *resource = wl_client_add_object(client, &qt_touch_extension_interface, &touch_interface, id, data); + resource->destroy = destroy_resource; + TouchExtensionGlobal *self = static_cast<TouchExtensionGlobal *>(resource->data); + self->m_resources.append(resource); + qt_touch_extension_send_configure(resource, self->m_flags); +} + +static inline int toFixed(qreal f) +{ + return int(f * 10000); +} + +bool TouchExtensionGlobal::postTouchEvent(QTouchEvent *event, Surface *surface) +{ + const QList<QTouchEvent::TouchPoint> points = event->touchPoints(); + const int pointCount = points.count(); + if (!pointCount) + return false; + + QPointF surfacePos = surface->pos(); + wl_client *surfaceClient = surface->resource()->client(); + uint32_t time = m_compositor->currentTimeMsecs(); + const int rescount = m_resources.count(); + + for (int res = 0; res < rescount; ++res) { + wl_resource *target = m_resources.at(res); + if (target->client != surfaceClient) + continue; + + // We will use no touch_frame type of event, to reduce the number of + // events flowing through the wire. Instead, the number of points sent is + // included in the touch point events. + int sentPointCount = 0; + for (int i = 0; i < pointCount; ++i) { + if (points.at(i).state() != Qt::TouchPointStationary) + ++sentPointCount; + } + + for (int i = 0; i < pointCount; ++i) { + const QTouchEvent::TouchPoint &tp(points.at(i)); + // Stationary points are never sent. They are cached on client side. + if (tp.state() == Qt::TouchPointStationary) + continue; + + uint32_t id = tp.id(); + uint32_t state = (tp.state() & 0xFFFF) | (sentPointCount << 16); + uint32_t flags = (tp.flags() & 0xFFFF) | (int(event->device()->capabilities()) << 16); + + QPointF p = tp.pos() - surfacePos; // surface-relative + int x = toFixed(p.x()); + int y = toFixed(p.y()); + int nx = toFixed(tp.normalizedPos().x()); + int ny = toFixed(tp.normalizedPos().y()); + int w = toFixed(tp.rect().width()); + int h = toFixed(tp.rect().height()); + int vx = toFixed(tp.velocity().x()); + int vy = toFixed(tp.velocity().y()); + uint32_t pressure = uint32_t(tp.pressure() * 255); + + wl_array *rawData = 0; + QVector<QPointF> rawPosList = tp.rawScreenPositions(); + int rawPosCount = rawPosList.count(); + if (rawPosCount) { + rawPosCount = qMin(maxRawPos, rawPosCount); + rawData = &m_rawdata_array; + rawData->size = rawPosCount * sizeof(float) * 2; + float *p = m_rawdata_ptr; + for (int rpi = 0; rpi < rawPosCount; ++rpi) { + const QPointF &rawPos(rawPosList.at(rpi)); + // This will stay in screen coordinates for performance + // reasons, clients using this data will presumably know + // what they are doing. + *p++ = float(rawPos.x()); + *p++ = float(rawPos.y()); + } + } + + qt_touch_extension_send_touch(target, + time, id, state, + x, y, nx, ny, w, h, + pressure, vx, vy, + flags, rawData); + } + + return true; + } + + return false; +} + +} + +QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlqttouch_p.h b/src/compositor/wayland_wrapper/qwlqttouch_p.h new file mode 100644 index 00000000..955aa5f8 --- /dev/null +++ b/src/compositor/wayland_wrapper/qwlqttouch_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WLTOUCH_H +#define WLTOUCH_H + +#include <private/qwlcompositor_p.h> +#include "wayland-touch-extension-server-protocol.h" +#include "wayland-util.h" + +QT_BEGIN_NAMESPACE + +class Compositor; +class Surface; +class QTouchEvent; + +namespace QtWayland { + +class TouchExtensionGlobal +{ +public: + TouchExtensionGlobal(Compositor *compositor); + ~TouchExtensionGlobal(); + + bool postTouchEvent(QTouchEvent *event, Surface *surface); + + void setFlags(int flags) { m_flags = flags; } + +private: + static void bind_func(struct wl_client *client, void *data, + uint32_t version, uint32_t id); + + static void destroy_resource(wl_resource *resource); + + static const struct qt_touch_extension_interface touch_interface; + + Compositor *m_compositor; + int m_flags; + QList<wl_resource *> m_resources; + wl_array m_rawdata_array; + float *m_rawdata_ptr; +}; + +} + +QT_END_NAMESPACE + +#endif // WLTOUCH_H diff --git a/src/compositor/wayland_wrapper/qwlshellsurface.cpp b/src/compositor/wayland_wrapper/qwlshellsurface.cpp index fc75665c..c6e67c00 100644 --- a/src/compositor/wayland_wrapper/qwlshellsurface.cpp +++ b/src/compositor/wayland_wrapper/qwlshellsurface.cpp @@ -44,6 +44,7 @@ #include "qwlsurface_p.h" #include "qwlinputdevice_p.h" #include "qwlsubsurface_p.h" +#include "qwlpointer_p.h" #include <QtCore/qglobal.h> #include <QtCore/QDebug> @@ -106,8 +107,8 @@ void ShellSurface::adjustPosInResize() if (!m_resizeGrabber || !(m_resizeGrabber->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP_LEFT)) return; - int bottomLeftX = wl_fixed_to_int(m_resizeGrabber->base()->x) + m_resizeGrabber->width; - int bottomLeftY = wl_fixed_to_int(m_resizeGrabber->base()->y) + m_resizeGrabber->height; + int bottomLeftX = m_resizeGrabber->point.x() + m_resizeGrabber->width; + int bottomLeftY = m_resizeGrabber->point.y() + m_resizeGrabber->height; qreal x = surface()->pos().x(); qreal y = surface()->pos().y(); if (m_resizeGrabber->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP) @@ -166,15 +167,11 @@ void ShellSurface::shell_surface_move(Resource *resource, } InputDevice *input_device = InputDevice::fromSeatResource(input_device_super); - ::wl_pointer *pointer = input_device->pointerDevice(); + Pointer *pointer = input_device->pointerDevice(); - m_moveGrabber = new ShellSurfaceMoveGrabber(this); - m_moveGrabber->base()->x = pointer->x; - m_moveGrabber->base()->y = pointer->y; - m_moveGrabber->offset_x = wl_fixed_to_int(pointer->x) - surface()->pos().x(); - m_moveGrabber->offset_y = wl_fixed_to_int(pointer->y) - surface()->pos().y(); + m_moveGrabber = new ShellSurfaceMoveGrabber(this, pointer->position() - surface()->pos()); - wl_pointer_start_grab(pointer, m_moveGrabber->base()); + pointer->startGrab(m_moveGrabber); } void ShellSurface::shell_surface_resize(Resource *resource, @@ -194,15 +191,14 @@ void ShellSurface::shell_surface_resize(Resource *resource, m_resizeGrabber = new ShellSurfaceResizeGrabber(this); InputDevice *input_device = InputDevice::fromSeatResource(input_device_super); - ::wl_pointer *pointer = input_device->pointerDevice(); + Pointer *pointer = input_device->pointerDevice(); - m_resizeGrabber->base()->x = pointer->x; - m_resizeGrabber->base()->y = pointer->y; - m_resizeGrabber->resize_edges = wl_shell_surface_resize(edges); + m_resizeGrabber->point = pointer->position(); + m_resizeGrabber->resize_edges = static_cast<wl_shell_surface_resize>(edges); m_resizeGrabber->width = surface()->size().width(); m_resizeGrabber->height = surface()->size().height(); - wl_pointer_start_grab(pointer, m_resizeGrabber->base()); + pointer->startGrab(m_resizeGrabber); } void ShellSurface::shell_surface_set_toplevel(Resource *resource) @@ -285,175 +281,91 @@ void ShellSurface::shell_surface_set_class(Resource *resource, surface()->setClassName(className); } -Qt::MouseButton toQtButton(uint32_t button) -{ -#ifndef BTN_LEFT - static const uint32_t BTN_LEFT = 0x110; - static const uint32_t BTN_RIGHT = 0x111; - static const uint32_t BTN_MIDDLE = 0x112; -#endif - switch (button) { - case BTN_LEFT: - return Qt::LeftButton; - case BTN_RIGHT: - return Qt::RightButton; - case BTN_MIDDLE: - return Qt::MiddleButton; - default: - return Qt::NoButton; - } -} - -ShellSurfaceGrabber::ShellSurfaceGrabber(ShellSurface *shellSurface, const struct wl_pointer_grab_interface *interface) - : shell_surface(shellSurface) +ShellSurfaceGrabber::ShellSurfaceGrabber(ShellSurface *shellSurface) + : PointerGrabber() + , shell_surface(shellSurface) { - base()->interface = interface; - base()->focus = shell_surface->surface(); } ShellSurfaceGrabber::~ShellSurfaceGrabber() { } - -void ShellSurfaceGrabber::destroy(wl_listener *listener, wl_resource *resource, uint32_t time) -{ - Q_UNUSED(resource); - Q_UNUSED(time); - Q_UNUSED(listener); - //ShellSurfaceGrabber *shell_surface_grabber = container_of(listener, ShellSurfaceGrabber,surface_destroy_listener); - Q_ASSERT(false); //hasn't been enabled yet - //wl_input_device_end_grab(shell_surface_grabber->base()->input_device,Compositor::currentTimeMsecs()); -} - - ShellSurfaceResizeGrabber::ShellSurfaceResizeGrabber(ShellSurface *shellSurface) - : ShellSurfaceGrabber(shellSurface,&resize_grabber_interface) + : ShellSurfaceGrabber(shellSurface) { } -void ShellSurfaceResizeGrabber::focus(wl_pointer_grab *grab, wl_surface *surface, int32_t x, int32_t y) +void ShellSurfaceResizeGrabber::focus() { - Q_UNUSED(grab); - Q_UNUSED(surface); - Q_UNUSED(x); - Q_UNUSED(y); } -void ShellSurfaceResizeGrabber::motion(wl_pointer_grab *grab, uint32_t time, int32_t x, int32_t y) +void ShellSurfaceResizeGrabber::motion(uint32_t time) { Q_UNUSED(time); - Q_UNUSED(x); - Q_UNUSED(y); - //Should be more structured - ShellSurfaceResizeGrabber *resize_grabber = reinterpret_cast<ShellSurfaceResizeGrabber *>(grab); - ShellSurface *shell_surface = resize_grabber->shell_surface; - wl_pointer *pointer = grab->pointer; - int width_delta = wl_fixed_to_int(grab->x) - wl_fixed_to_int(pointer->x); - int height_delta = wl_fixed_to_int(grab->y) - wl_fixed_to_int(pointer->y); - int new_width = resize_grabber->width; - int new_height = resize_grabber->height; - if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP_LEFT) { - if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP) { - if (new_height + height_delta > 0) { - new_height += height_delta; - } else { - new_height = 1; - } - } - if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_LEFT) { - if (new_width + width_delta > 0) { - new_width += width_delta; - } else { - new_width = 1; - } - } - } - if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) { - if (new_height - height_delta > 0) { - new_height -= height_delta; - } else { - new_height = 1; - } - } - if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_RIGHT) { - if (new_width - width_delta > 0) { - new_width -= width_delta; - } else { - new_width =1; - } - } + int width_delta = point.x() - m_pointer->position().x(); + int height_delta = point.y() - m_pointer->position().y(); + + int new_height = height; + if (resize_edges & WL_SHELL_SURFACE_RESIZE_TOP) + new_height = qMax(new_height + height_delta, 1); + else if (resize_edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) + new_height = qMax(new_height - height_delta, 1); + + int new_width = width; + if (resize_edges & WL_SHELL_SURFACE_RESIZE_LEFT) + new_width = qMax(new_width + width_delta, 1); + else if (resize_edges & WL_SHELL_SURFACE_RESIZE_RIGHT) + new_width = qMax(new_width - width_delta, 1); - shell_surface->sendConfigure(resize_grabber->resize_edges,new_width,new_height); + shell_surface->sendConfigure(resize_edges, new_width, new_height); } -void ShellSurfaceResizeGrabber::button(wl_pointer_grab *grab, uint32_t time, uint32_t button, uint32_t state) +void ShellSurfaceResizeGrabber::button(uint32_t time, Qt::MouseButton button, uint32_t state) { Q_UNUSED(time) - ShellSurfaceResizeGrabber *self = reinterpret_cast<ShellSurfaceResizeGrabber *>(grab); - ShellSurface *shell_surface = self->shell_surface; - if (toQtButton(button) == Qt::LeftButton && !state) { - wl_pointer_end_grab(grab->pointer); + + if (button == Qt::LeftButton && !state) { + m_pointer->endGrab(); shell_surface->resetResizeGrabber(); - delete self; + delete this; } } -const struct wl_pointer_grab_interface ShellSurfaceResizeGrabber::resize_grabber_interface = { - ShellSurfaceResizeGrabber::focus, - ShellSurfaceResizeGrabber::motion, - ShellSurfaceResizeGrabber::button -}; - -ShellSurfaceMoveGrabber::ShellSurfaceMoveGrabber(ShellSurface *shellSurface) - : ShellSurfaceGrabber(shellSurface,&move_grabber_interface) +ShellSurfaceMoveGrabber::ShellSurfaceMoveGrabber(ShellSurface *shellSurface, const QPointF &offset) + : ShellSurfaceGrabber(shellSurface) + , m_offset(offset) { } -void ShellSurfaceMoveGrabber::focus(wl_pointer_grab *grab, wl_surface *surface, int32_t x, int32_t y) +void ShellSurfaceMoveGrabber::focus() { - Q_UNUSED(grab); - Q_UNUSED(surface); - Q_UNUSED(x); - Q_UNUSED(y); } -void ShellSurfaceMoveGrabber::motion(wl_pointer_grab *grab, uint32_t time, int32_t x, int32_t y) +void ShellSurfaceMoveGrabber::motion(uint32_t time) { Q_UNUSED(time); - Q_UNUSED(x); - Q_UNUSED(y); - ShellSurfaceMoveGrabber *shell_surface_grabber = reinterpret_cast<ShellSurfaceMoveGrabber *>(grab); - ShellSurface *shell_surface = shell_surface_grabber->shell_surface; - wl_pointer *pointer = grab->pointer; - QPointF pos(wl_fixed_to_int(pointer->x) - shell_surface_grabber->offset_x, - wl_fixed_to_int(pointer->y) - shell_surface_grabber->offset_y); + + QPointF pos(m_pointer->position() - m_offset); shell_surface->surface()->setPos(pos); if (shell_surface->transientParent()) shell_surface->setOffset(pos - shell_surface->transientParent()->surface()->pos()); } -void ShellSurfaceMoveGrabber::button(wl_pointer_grab *grab, uint32_t time, uint32_t button, uint32_t state) +void ShellSurfaceMoveGrabber::button(uint32_t time, Qt::MouseButton button, uint32_t state) { Q_UNUSED(time) - ShellSurfaceResizeGrabber *self = reinterpret_cast<ShellSurfaceResizeGrabber *>(grab); - ShellSurface *shell_surface = self->shell_surface; - if (toQtButton(button) == Qt::LeftButton && !state) { - wl_pointer_set_focus(grab->pointer, 0, 0, 0); - wl_pointer_end_grab(grab->pointer); + + if (button == Qt::LeftButton && !state) { + m_pointer->setFocus(0, QPointF()); + m_pointer->endGrab(); shell_surface->resetMoveGrabber(); - delete self; + delete this; } } -const struct wl_pointer_grab_interface ShellSurfaceMoveGrabber::move_grabber_interface = { - ShellSurfaceMoveGrabber::focus, - ShellSurfaceMoveGrabber::motion, - ShellSurfaceMoveGrabber::button -}; - } QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlshellsurface_p.h b/src/compositor/wayland_wrapper/qwlshellsurface_p.h index 4c296a97..40d8f1f4 100644 --- a/src/compositor/wayland_wrapper/qwlshellsurface_p.h +++ b/src/compositor/wayland_wrapper/qwlshellsurface_p.h @@ -44,6 +44,7 @@ #include <wayland-server.h> #include <qwaylandobject.h> #include <QPoint> +#include <private/qwlpointer_p.h> #include <qwayland-server-wayland.h> @@ -136,16 +137,12 @@ private: const QString &class_) Q_DECL_OVERRIDE; }; -class ShellSurfaceGrabber : public Object<struct ::wl_pointer_grab> +class ShellSurfaceGrabber : public PointerGrabber { public: - ShellSurfaceGrabber(ShellSurface *shellSurface, const struct wl_pointer_grab_interface *interface); + ShellSurfaceGrabber(ShellSurface *shellSurface); ~ShellSurfaceGrabber(); - struct wl_listener surface_destroy_listener; - static void destroy(struct wl_listener *listener, - struct wl_resource *resource, uint32_t time); - ShellSurface *shell_surface; }; @@ -154,35 +151,27 @@ class ShellSurfaceResizeGrabber : public ShellSurfaceGrabber public: ShellSurfaceResizeGrabber(ShellSurface *shellSurface); - + QPointF point; enum wl_shell_surface_resize resize_edges; int32_t width; int32_t height; - static void focus(struct wl_pointer_grab *grab, - struct wl_surface *surface, int32_t x, int32_t y); - static void motion(struct wl_pointer_grab *grab, - uint32_t time, int32_t x, int32_t y); - static void button(struct wl_pointer_grab *grab, - uint32_t time, uint32_t mouse_grabber_button, uint32_t state); - static const struct wl_pointer_grab_interface resize_grabber_interface; + void focus() Q_DECL_OVERRIDE; + void motion(uint32_t time) Q_DECL_OVERRIDE; + void button(uint32_t time, Qt::MouseButton button, uint32_t state) Q_DECL_OVERRIDE; }; class ShellSurfaceMoveGrabber : public ShellSurfaceGrabber { public: - ShellSurfaceMoveGrabber(ShellSurface *shellSurface); - - int32_t offset_x; - int32_t offset_y; - - static void focus(struct wl_pointer_grab *grab, - struct wl_surface *surface, int32_t x, int32_t y); - static void motion(struct wl_pointer_grab *grab, - uint32_t time, int32_t x, int32_t y); - static void button(struct wl_pointer_grab *grab, - uint32_t time, uint32_t mouse_grabber_button, uint32_t state); - static const struct wl_pointer_grab_interface move_grabber_interface; + ShellSurfaceMoveGrabber(ShellSurface *shellSurface, const QPointF &offset); + + void focus() Q_DECL_OVERRIDE; + void motion(uint32_t time) Q_DECL_OVERRIDE; + void button(uint32_t time, Qt::MouseButton button, uint32_t state) Q_DECL_OVERRIDE; + +private: + QPointF m_offset; }; } diff --git a/src/compositor/wayland_wrapper/qwltouch.cpp b/src/compositor/wayland_wrapper/qwltouch.cpp index 7142c985..54290136 100644 --- a/src/compositor/wayland_wrapper/qwltouch.cpp +++ b/src/compositor/wayland_wrapper/qwltouch.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Compositor. @@ -39,142 +40,67 @@ ****************************************************************************/ #include "qwltouch_p.h" -#include "qwlsurface_p.h" -#include <QTouchEvent> -#include <QWindow> -QT_BEGIN_NAMESPACE +#include "qwlcompositor_p.h" +#include "qwlsurface_p.h" namespace QtWayland { -static void dummy(wl_client *, wl_resource *) +Touch::Touch(Compositor *compositor) + : wl_touch() + , m_compositor(compositor) + , m_focus() + , m_focusResource() { } -const struct qt_touch_extension_interface TouchExtensionGlobal::touch_interface = { - dummy -}; - -static const int maxRawPos = 24; - -TouchExtensionGlobal::TouchExtensionGlobal(Compositor *compositor) - : m_compositor(compositor), - m_flags(0) +void Touch::setFocus(Surface *surface) { - wl_array_init(&m_rawdata_array); - m_rawdata_ptr = static_cast<float *>(wl_array_add(&m_rawdata_array, maxRawPos * sizeof(float) * 2)); - - wl_display_add_global(compositor->wl_display(), - &qt_touch_extension_interface, - this, - TouchExtensionGlobal::bind_func); + m_focus = surface; + struct ::wl_resource *r = Compositor::resourceForSurface(resourceList(), surface); + m_focusResource = r ? Resource::fromResource(r) : 0; } -TouchExtensionGlobal::~TouchExtensionGlobal() +void Touch::sendCancel() { - wl_array_release(&m_rawdata_array); + if (m_focusResource) + send_cancel(m_focusResource->handle); } -void TouchExtensionGlobal::destroy_resource(wl_resource *resource) +void Touch::sendFrame() { - TouchExtensionGlobal *self = static_cast<TouchExtensionGlobal *>(resource->data); - self->m_resources.removeOne(resource); - free(resource); + if (m_focusResource) + send_frame(m_focusResource->handle); } -void TouchExtensionGlobal::bind_func(wl_client *client, void *data, uint32_t version, uint32_t id) +void Touch::sendDown(int touch_id, const QPointF &position) { - Q_UNUSED(version); - wl_resource *resource = wl_client_add_object(client, &qt_touch_extension_interface, &touch_interface, id, data); - resource->destroy = destroy_resource; - TouchExtensionGlobal *self = static_cast<TouchExtensionGlobal *>(resource->data); - self->m_resources.append(resource); - qt_touch_extension_send_configure(resource, self->m_flags); + if (!m_focusResource || !m_focus) + return; + + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + + send_down(m_focusResource->handle, serial, Compositor::currentTimeMsecs(), m_focus->resource()->handle, touch_id, + wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y())); } -static inline int toFixed(qreal f) +void Touch::sendMotion(int touch_id, const QPointF &position) { - return int(f * 10000); + if (!m_focusResource) + return; + + send_motion(m_focusResource->handle, Compositor::currentTimeMsecs(), touch_id, + wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y())); } -bool TouchExtensionGlobal::postTouchEvent(QTouchEvent *event, Surface *surface) +void Touch::sendUp(int touch_id) { - const QList<QTouchEvent::TouchPoint> points = event->touchPoints(); - const int pointCount = points.count(); - if (!pointCount) - return false; - - QPointF surfacePos = surface->pos(); - wl_client *surfaceClient = surface->resource()->client(); - uint32_t time = m_compositor->currentTimeMsecs(); - const int rescount = m_resources.count(); - - for (int res = 0; res < rescount; ++res) { - wl_resource *target = m_resources.at(res); - if (target->client != surfaceClient) - continue; - - // We will use no touch_frame type of event, to reduce the number of - // events flowing through the wire. Instead, the number of points sent is - // included in the touch point events. - int sentPointCount = 0; - for (int i = 0; i < pointCount; ++i) { - if (points.at(i).state() != Qt::TouchPointStationary) - ++sentPointCount; - } - - for (int i = 0; i < pointCount; ++i) { - const QTouchEvent::TouchPoint &tp(points.at(i)); - // Stationary points are never sent. They are cached on client side. - if (tp.state() == Qt::TouchPointStationary) - continue; - - uint32_t id = tp.id(); - uint32_t state = (tp.state() & 0xFFFF) | (sentPointCount << 16); - uint32_t flags = (tp.flags() & 0xFFFF) | (int(event->device()->capabilities()) << 16); - - QPointF p = tp.pos() - surfacePos; // surface-relative - int x = toFixed(p.x()); - int y = toFixed(p.y()); - int nx = toFixed(tp.normalizedPos().x()); - int ny = toFixed(tp.normalizedPos().y()); - int w = toFixed(tp.rect().width()); - int h = toFixed(tp.rect().height()); - int vx = toFixed(tp.velocity().x()); - int vy = toFixed(tp.velocity().y()); - uint32_t pressure = uint32_t(tp.pressure() * 255); - - wl_array *rawData = 0; - QVector<QPointF> rawPosList = tp.rawScreenPositions(); - int rawPosCount = rawPosList.count(); - if (rawPosCount) { - rawPosCount = qMin(maxRawPos, rawPosCount); - rawData = &m_rawdata_array; - rawData->size = rawPosCount * sizeof(float) * 2; - float *p = m_rawdata_ptr; - for (int rpi = 0; rpi < rawPosCount; ++rpi) { - const QPointF &rawPos(rawPosList.at(rpi)); - // This will stay in screen coordinates for performance - // reasons, clients using this data will presumably know - // what they are doing. - *p++ = float(rawPos.x()); - *p++ = float(rawPos.y()); - } - } - - qt_touch_extension_send_touch(target, - time, id, state, - x, y, nx, ny, w, h, - pressure, vx, vy, - flags, rawData); - } - - return true; - } - - return false; -} + if (!m_focusResource) + return; + + uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); + send_up(m_focusResource->handle, serial, Compositor::currentTimeMsecs(), touch_id); } -QT_END_NAMESPACE +} // namespace QtWayland diff --git a/src/compositor/wayland_wrapper/qwltouch_p.h b/src/compositor/wayland_wrapper/qwltouch_p.h index 955aa5f8..6b597e29 100644 --- a/src/compositor/wayland_wrapper/qwltouch_p.h +++ b/src/compositor/wayland_wrapper/qwltouch_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Compositor. @@ -38,48 +39,43 @@ ** ****************************************************************************/ -#ifndef WLTOUCH_H -#define WLTOUCH_H +#ifndef QTWAYLAND_QWLTOUCH_P_H +#define QTWAYLAND_QWLTOUCH_P_H -#include <private/qwlcompositor_p.h> -#include "wayland-touch-extension-server-protocol.h" -#include "wayland-util.h" +#include <QtCore/QPoint> + +#include <qwayland-server-wayland.h> QT_BEGIN_NAMESPACE +namespace QtWayland { + class Compositor; class Surface; -class QTouchEvent; - -namespace QtWayland { -class TouchExtensionGlobal +class Touch : public QtWaylandServer::wl_touch { public: - TouchExtensionGlobal(Compositor *compositor); - ~TouchExtensionGlobal(); + explicit Touch(Compositor *compositor); - bool postTouchEvent(QTouchEvent *event, Surface *surface); + void setFocus(Surface *surface); - void setFlags(int flags) { m_flags = flags; } + void sendCancel(); + void sendFrame(); -private: - static void bind_func(struct wl_client *client, void *data, - uint32_t version, uint32_t id); - - static void destroy_resource(wl_resource *resource); - - static const struct qt_touch_extension_interface touch_interface; + void sendDown(int touch_id, const QPointF &position); + void sendMotion(int touch_id, const QPointF &position); + void sendUp(int touch_id); +private: Compositor *m_compositor; - int m_flags; - QList<wl_resource *> m_resources; - wl_array m_rawdata_array; - float *m_rawdata_ptr; + + Surface *m_focus; + Resource *m_focusResource; }; -} +} // namespace QtWayland QT_END_NAMESPACE -#endif // WLTOUCH_H +#endif // QTWAYLAND_QWLTOUCH_P_H diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri index c425e2e5..663638ec 100644 --- a/src/compositor/wayland_wrapper/wayland_wrapper.pri +++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri @@ -17,8 +17,11 @@ HEADERS += \ wayland_wrapper/qwlextendedoutput_p.h \ wayland_wrapper/qwlextendedsurface_p.h \ wayland_wrapper/qwlinputdevice_p.h \ + wayland_wrapper/qwlkeyboard_p.h \ wayland_wrapper/qwloutput_p.h \ + wayland_wrapper/qwlpointer_p.h \ wayland_wrapper/qwlqtkey_p.h \ + wayland_wrapper/qwlqttouch_p.h \ wayland_wrapper/qwlregion_p.h \ wayland_wrapper/qwlshellsurface_p.h \ wayland_wrapper/qwlsubsurface_p.h \ @@ -36,8 +39,11 @@ SOURCES += \ wayland_wrapper/qwlextendedoutput.cpp \ wayland_wrapper/qwlextendedsurface.cpp \ wayland_wrapper/qwlinputdevice.cpp \ + wayland_wrapper/qwlkeyboard.cpp \ wayland_wrapper/qwloutput.cpp \ + wayland_wrapper/qwlpointer.cpp \ wayland_wrapper/qwlqtkey.cpp \ + wayland_wrapper/qwlqttouch.cpp \ wayland_wrapper/qwlregion.cpp \ wayland_wrapper/qwlshellsurface.cpp \ wayland_wrapper/qwlsubsurface.cpp \ |