/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** 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 The Qt Company Ltd 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 "qwlinputdevice_p.h" #include "qwlcompositor_p.h" #include "qwldatadevice_p.h" #include "qwlinputmethod_p.h" #include "qwlsurface_p.h" #include "qwlqttouch_p.h" #include "qwlqtkey_p.h" #include "qwaylandcompositor.h" #include "qwaylanddrag.h" #include "qwlpointer_p.h" #include "qwlkeyboard_p.h" #include "qwltouch_p.h" #include "qwaylandsurfaceview.h" #include QT_BEGIN_NAMESPACE namespace QtWayland { InputDevice::InputDevice(QWaylandInputDevice *handle, Compositor *compositor, QWaylandInputDevice::CapabilityFlags caps) : QtWaylandServer::wl_seat(compositor->wl_display(), 3) , m_handle(handle) , m_dragHandle(new QWaylandDrag(this)) , m_compositor(compositor) , m_capabilities(caps) , m_pointer(m_capabilities & QWaylandInputDevice::Pointer ? new Pointer(m_compositor, this) : 0) , m_keyboard(m_capabilities & QWaylandInputDevice::Keyboard ? new Keyboard(m_compositor, this) : 0) , m_touch(m_capabilities & QWaylandInputDevice::Touch ? new Touch(m_compositor) : 0) , m_inputMethod(m_compositor->extensions() & QWaylandCompositor::TextInputExtension ? new InputMethod(m_compositor, this) : 0) , m_data_device() { } InputDevice::~InputDevice() { } Pointer *InputDevice::pointerDevice() { return m_pointer.data(); } Keyboard *InputDevice::keyboardDevice() { return m_keyboard.data(); } Touch *InputDevice::touchDevice() { return m_touch.data(); } InputMethod *InputDevice::inputMethod() { return m_inputMethod.data(); } const Pointer *InputDevice::pointerDevice() const { return m_pointer.data(); } const Keyboard *InputDevice::keyboardDevice() const { return m_keyboard.data(); } const Touch *InputDevice::touchDevice() const { return m_touch.data(); } void InputDevice::seat_destroy_resource(wl_seat::Resource *) { // cleanupDataDeviceForClient(resource->client(), true); } void InputDevice::seat_bind_resource(wl_seat::Resource *resource) { // The order of m_capabilities matches the order defined in the wayland protocol wl_seat::send_capabilities(resource->handle, (uint32_t)m_capabilities); } void InputDevice::setCapabilities(QWaylandInputDevice::CapabilityFlags caps) { if (m_capabilities != caps) { QWaylandInputDevice::CapabilityFlags changed = caps ^ m_capabilities; if (changed & QWaylandInputDevice::Pointer) { m_pointer.reset(m_pointer.isNull() ? new Pointer(m_compositor, this) : 0); } if (changed & QWaylandInputDevice::Keyboard) { m_keyboard.reset(m_keyboard.isNull() ? new Keyboard(m_compositor, this) : 0); } if (changed & QWaylandInputDevice::Touch) { m_touch.reset(m_touch.isNull() ? new Touch(m_compositor) : 0); } m_capabilities = caps; QList resources = resourceMap().values(); for (int i = 0; i < resources.size(); i++) { wl_seat::send_capabilities(resources.at(i)->handle, (uint32_t)m_capabilities); } } } void InputDevice::seat_get_pointer(wl_seat::Resource *resource, uint32_t id) { if (!m_pointer.isNull()) { m_pointer->add(resource->client(), id, resource->version()); } } void InputDevice::seat_get_keyboard(wl_seat::Resource *resource, uint32_t id) { if (!m_keyboard.isNull()) { m_keyboard->add(resource->client(), id, resource->version()); } } void InputDevice::seat_get_touch(wl_seat::Resource *resource, uint32_t id) { if (!m_touch.isNull()) { m_touch->add(resource->client(), id, resource->version()); } } void InputDevice::sendMousePressEvent(Qt::MouseButton button, const QPointF &localPos, const QPointF &globalPos) { pointerDevice()->sendMousePressEvent(button, localPos, globalPos); } void InputDevice::sendMouseReleaseEvent(Qt::MouseButton button, const QPointF &localPos, const QPointF &globalPos) { pointerDevice()->sendMouseReleaseEvent(button, localPos, globalPos); } void InputDevice::sendMouseMoveEvent(const QPointF &localPos, const QPointF &globalPos) { pointerDevice()->sendMouseMoveEvent(localPos, globalPos); } void InputDevice::sendMouseMoveEvent(QWaylandSurfaceView *surface, const QPointF &localPos, const QPointF &globalPos) { setMouseFocus(surface,localPos,globalPos); sendMouseMoveEvent(localPos,globalPos); } void InputDevice::sendMouseWheelEvent(Qt::Orientation orientation, int delta) { pointerDevice()->sendMouseWheelEvent(orientation, delta); } void InputDevice::sendTouchPointEvent(int id, double x, double y, Qt::TouchPointState state) { if (m_touch.isNull()) { return; } switch (state) { case Qt::TouchPointPressed: m_touch->sendDown(id, QPointF(x, y)); break; case Qt::TouchPointMoved: m_touch->sendMotion(id, QPointF(x, y)); break; case Qt::TouchPointReleased: m_touch->sendUp(id); break; case Qt::TouchPointStationary: // stationary points are not sent through wayland, the client must cache them break; default: break; } } void InputDevice::sendTouchFrameEvent() { if (!m_touch.isNull()) { m_touch->sendFrame(); } } void InputDevice::sendTouchCancelEvent() { if (!m_touch.isNull()) { m_touch->sendCancel(); } } void InputDevice::sendFullKeyEvent(QKeyEvent *event) { if (!keyboardFocus()) { qWarning("Cannot send key event, no keyboard focus, fix the compositor"); return; } QtKeyExtensionGlobal *ext = m_compositor->qtkeyExtension(); if (ext && ext->postQtKeyEvent(event, keyboardFocus())) return; if (!m_keyboard.isNull() && !event->isAutoRepeat()) { if (event->type() == QEvent::KeyPress) m_keyboard->sendKeyPressEvent(event->nativeScanCode()); else if (event->type() == QEvent::KeyRelease) m_keyboard->sendKeyReleaseEvent(event->nativeScanCode()); } } void InputDevice::sendFullKeyEvent(Surface *surface, QKeyEvent *event) { QtKeyExtensionGlobal *ext = m_compositor->qtkeyExtension(); if (ext) ext->postQtKeyEvent(event, surface); } void InputDevice::sendFullTouchEvent(QTouchEvent *event) { if (!mouseFocus()) { qWarning("Cannot send touch event, no pointer focus, fix the compositor"); return; } if (event->type() == QEvent::TouchCancel) { sendTouchCancelEvent(); return; } TouchExtensionGlobal *ext = m_compositor->touchExtension(); if (ext && ext->postTouchEvent(event, mouseFocus())) return; const QList points = event->touchPoints(); if (points.isEmpty()) return; const int pointCount = points.count(); QPointF pos = mouseFocus()->pos(); for (int i = 0; i < pointCount; ++i) { const QTouchEvent::TouchPoint &tp(points.at(i)); // Convert the local pos in the compositor window to surface-relative. QPointF p = tp.pos() - pos; sendTouchPointEvent(tp.id(), p.x(), p.y(), tp.state()); } sendTouchFrameEvent(); } Surface *InputDevice::keyboardFocus() const { return m_keyboard.isNull() ? 0 : m_keyboard->focus(); } /*! * \return True if the keyboard focus is changed successfully. False for inactive transient surfaces. */ bool InputDevice::setKeyboardFocus(Surface *surface) { if (surface && (surface->transientInactive() || surface->isDestroyed())) return false; if (!m_keyboard.isNull()) { m_keyboard->setFocus(surface); if (m_data_device) m_data_device->setFocus(m_keyboard->focusResource()); return true; } return false; } QWaylandSurfaceView *InputDevice::mouseFocus() const { return m_pointer.isNull() ? 0 : m_pointer->focusSurface(); } void InputDevice::setMouseFocus(QWaylandSurfaceView *view, const QPointF &localPos, const QPointF &globalPos) { if (view && view->surface()->handle()->isDestroyed()) return; if (!m_pointer.isNull()) { m_pointer->setMouseFocus(view, localPos, globalPos); } if (!m_touch.isNull()) { // 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. m_touch->setFocus(view); } } void InputDevice::clientRequestedDataDevice(DataDeviceManager *, struct wl_client *client, uint32_t id) { if (!m_data_device) m_data_device.reset(new DataDevice(this)); m_data_device->add(client, id, 1); } Compositor *InputDevice::compositor() const { return m_compositor; } QWaylandInputDevice *InputDevice::handle() const { return m_handle; } QWaylandDrag *InputDevice::dragHandle() const { return m_dragHandle.data(); } const DataDevice *InputDevice::dataDevice() const { return m_data_device.data(); } } QT_END_NAMESPACE