Split out pointer related handling from InputRedirection
All pointer related code is moved into a new class called PointerInputRedirection. The main idea is to simplify the code and make it easier to maintain. Therefore also a few changes in the setup were performed: * before init() is called, no processing is performed * init() is only called on Wayland and after Workspace is created * init property is set to false once Workspace or WaylandServer is destroyed Thus code can operate on the following assumptions: * Workspace is valid * WaylandServer is valid * ScreenLocker integration is used The various checks whether there is a waylandServer() and whether there is a seat are no longer needed. Some of the checks have been reordered to be faster in the most common use case of using libinput. E.g. whether warping is supported is first evaluated by the variable bound to whether we have libinput and only if that is false the backend is checked. The new class doesn't have signals but invokes the signals provided by InputRedirection. I didn't want to add new signals as I consider them as not needed. The areas in KWin needing those signals should be ported to InputEventFilters.icc-effect-5.14.5
parent
768f1be939
commit
c044ad98be
|
@ -332,6 +332,7 @@ set(kwin_KDEINIT_SRCS
|
|||
focuschain.cpp
|
||||
globalshortcuts.cpp
|
||||
input.cpp
|
||||
pointer_input.cpp
|
||||
netinfo.cpp
|
||||
placement.cpp
|
||||
atoms.cpp
|
||||
|
|
384
input.cpp
384
input.cpp
|
@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "input.h"
|
||||
#include "pointer_input.h"
|
||||
#include "client.h"
|
||||
#include "effects.h"
|
||||
#include "globalshortcuts.h"
|
||||
|
@ -358,7 +359,7 @@ public:
|
|||
if (event->type() == QEvent::MouseMove) {
|
||||
if (event->buttons() == Qt::NoButton) {
|
||||
// update pointer window only if no button is pressed
|
||||
input()->updatePointerWindow();
|
||||
input()->pointer()->update();
|
||||
}
|
||||
if (pointerSurfaceAllowed()) {
|
||||
seat->setPointerPos(event->screenPos().toPoint());
|
||||
|
@ -567,7 +568,7 @@ public:
|
|||
class InternalWindowEventFilter : public InputEventFilter {
|
||||
bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override {
|
||||
Q_UNUSED(nativeButton)
|
||||
auto internal = input()->m_pointerInternalWindow;
|
||||
auto internal = input()->pointer()->internalWindow();
|
||||
if (!internal) {
|
||||
return false;
|
||||
}
|
||||
|
@ -580,7 +581,7 @@ class InternalWindowEventFilter : public InputEventFilter {
|
|||
return e.isAccepted();
|
||||
}
|
||||
bool wheelEvent(QWheelEvent *event) override {
|
||||
auto internal = input()->m_pointerInternalWindow;
|
||||
auto internal = input()->pointer()->internalWindow();
|
||||
if (!internal) {
|
||||
return false;
|
||||
}
|
||||
|
@ -598,7 +599,7 @@ class InternalWindowEventFilter : public InputEventFilter {
|
|||
return e.isAccepted();
|
||||
}
|
||||
bool keyEvent(QKeyEvent *event) override {
|
||||
auto internal = input()->m_pointerInternalWindow;
|
||||
auto internal = input()->pointer()->internalWindow();
|
||||
if (!internal) {
|
||||
return false;
|
||||
}
|
||||
|
@ -612,7 +613,7 @@ class DecorationEventFilter : public InputEventFilter {
|
|||
public:
|
||||
bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override {
|
||||
Q_UNUSED(nativeButton)
|
||||
auto decoration = input()->m_pointerDecoration;
|
||||
auto decoration = input()->pointer()->decoration();
|
||||
if (!decoration) {
|
||||
return false;
|
||||
}
|
||||
|
@ -638,7 +639,7 @@ public:
|
|||
if (event->type() == QEvent::MouseButtonRelease) {
|
||||
decoration->client()->processDecorationButtonRelease(&e);
|
||||
}
|
||||
input()->installCursorFromDecoration();
|
||||
input()->pointer()->installCursorFromDecoration();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
|
@ -647,7 +648,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
bool wheelEvent(QWheelEvent *event) override {
|
||||
auto decoration = input()->m_pointerDecoration;
|
||||
auto decoration = input()->pointer()->decoration();
|
||||
if (!decoration) {
|
||||
return false;
|
||||
}
|
||||
|
@ -711,13 +712,13 @@ public:
|
|||
case QEvent::MouseMove:
|
||||
if (event->buttons() == Qt::NoButton) {
|
||||
// update pointer window only if no button is pressed
|
||||
input()->updatePointerWindow();
|
||||
input()->pointer()->update();
|
||||
}
|
||||
seat->setPointerPos(event->globalPos());
|
||||
break;
|
||||
case QEvent::MouseButtonPress: {
|
||||
bool passThrough = true;
|
||||
if (AbstractClient *c = dynamic_cast<AbstractClient*>(input()->m_pointerWindow.data())) {
|
||||
if (AbstractClient *c = dynamic_cast<AbstractClient*>(input()->pointer()->window().data())) {
|
||||
bool wasAction = false;
|
||||
const Options::MouseCommand command = c->getMouseCommand(event->button(), &wasAction);
|
||||
if (wasAction) {
|
||||
|
@ -732,7 +733,7 @@ public:
|
|||
case QEvent::MouseButtonRelease:
|
||||
seat->pointerButtonReleased(nativeButton);
|
||||
if (event->buttons() == Qt::NoButton) {
|
||||
input()->updatePointerWindow();
|
||||
input()->pointer()->update();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -820,8 +821,8 @@ KWIN_SINGLETON_FACTORY(InputRedirection)
|
|||
|
||||
InputRedirection::InputRedirection(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_pointer(new PointerInputRedirection(this))
|
||||
, m_xkb(new Xkb(this))
|
||||
, m_pointerWindow()
|
||||
, m_shortcuts(new GlobalShortcutsManager(this))
|
||||
{
|
||||
qRegisterMetaType<KWin::InputRedirection::KeyboardKeyState>();
|
||||
|
@ -879,19 +880,19 @@ void InputRedirection::setupWorkspace()
|
|||
connect(device, &FakeInputDevice::pointerMotionRequested, this,
|
||||
[this] (const QSizeF &delta) {
|
||||
// TODO: Fix time
|
||||
processPointerMotion(globalPointer() + QPointF(delta.width(), delta.height()), 0);
|
||||
m_pointer->processMotion(globalPointer() + QPointF(delta.width(), delta.height()), 0);
|
||||
}
|
||||
);
|
||||
connect(device, &FakeInputDevice::pointerButtonPressRequested, this,
|
||||
[this] (quint32 button) {
|
||||
// TODO: Fix time
|
||||
processPointerButton(button, InputRedirection::PointerButtonPressed, 0);
|
||||
m_pointer->processButton(button, InputRedirection::PointerButtonPressed, 0);
|
||||
}
|
||||
);
|
||||
connect(device, &FakeInputDevice::pointerButtonReleaseRequested, this,
|
||||
[this] (quint32 button) {
|
||||
// TODO: Fix time
|
||||
processPointerButton(button, InputRedirection::PointerButtonReleased, 0);
|
||||
m_pointer->processButton(button, InputRedirection::PointerButtonReleased, 0);
|
||||
}
|
||||
);
|
||||
connect(device, &FakeInputDevice::pointerAxisRequested, this,
|
||||
|
@ -910,7 +911,7 @@ void InputRedirection::setupWorkspace()
|
|||
break;
|
||||
}
|
||||
// TODO: Fix time
|
||||
processPointerAxis(axis, delta, 0);
|
||||
m_pointer->processAxis(axis, delta, 0);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -927,9 +928,9 @@ void InputRedirection::setupWorkspace()
|
|||
}
|
||||
);
|
||||
connect(workspace(), &Workspace::configChanged, this, &InputRedirection::reconfigure);
|
||||
connect(screens(), &Screens::changed, this, &InputRedirection::updatePointerAfterScreenChange);
|
||||
|
||||
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &InputRedirection::updatePointerWindow);
|
||||
m_pointer->init();
|
||||
|
||||
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &InputRedirection::updateKeyboardWindow);
|
||||
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this,
|
||||
[this] {
|
||||
|
@ -1002,24 +1003,23 @@ void InputRedirection::setupLibInput()
|
|||
m_libInput = conn;
|
||||
if (conn) {
|
||||
conn->setup();
|
||||
m_pointerWarping = true;
|
||||
connect(conn, &LibInput::Connection::eventsRead, this,
|
||||
[this] {
|
||||
m_libInput->processEvents();
|
||||
}, Qt::QueuedConnection
|
||||
);
|
||||
connect(conn, &LibInput::Connection::pointerButtonChanged, this, &InputRedirection::processPointerButton);
|
||||
connect(conn, &LibInput::Connection::pointerAxisChanged, this, &InputRedirection::processPointerAxis);
|
||||
connect(conn, &LibInput::Connection::pointerButtonChanged, m_pointer, &PointerInputRedirection::processButton);
|
||||
connect(conn, &LibInput::Connection::pointerAxisChanged, m_pointer, &PointerInputRedirection::processAxis);
|
||||
connect(conn, &LibInput::Connection::keyChanged, this, &InputRedirection::processKeyboardKey);
|
||||
connect(conn, &LibInput::Connection::pointerMotion, this,
|
||||
[this] (QPointF delta, uint32_t time) {
|
||||
processPointerMotion(m_globalPointer + delta, time);
|
||||
m_pointer->processMotion(m_pointer->pos() + delta, time);
|
||||
}
|
||||
);
|
||||
connect(conn, &LibInput::Connection::pointerMotionAbsolute, this,
|
||||
[this] (QPointF orig, QPointF screen, uint32_t time) {
|
||||
Q_UNUSED(orig)
|
||||
processPointerMotion(screen, time);
|
||||
m_pointer->processMotion(screen, time);
|
||||
}
|
||||
);
|
||||
connect(conn, &LibInput::Connection::touchDown, this, &InputRedirection::processTouchDown);
|
||||
|
@ -1084,189 +1084,9 @@ void InputRedirection::setupLibInputWithScreens()
|
|||
m_libInput->setScreenSize(screens()->size());
|
||||
}
|
||||
);
|
||||
// set pos to center of all screens
|
||||
m_globalPointer = screens()->geometry().center();
|
||||
emit globalPointerChanged(m_globalPointer);
|
||||
// sanitize
|
||||
updatePointerAfterScreenChange();
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputRedirection::updatePointerWindow()
|
||||
{
|
||||
// TODO: handle pointer grab aka popups
|
||||
Toplevel *t = findToplevel(m_globalPointer.toPoint());
|
||||
updatePointerInternalWindow();
|
||||
if (!m_pointerInternalWindow) {
|
||||
updatePointerDecoration(t);
|
||||
} else {
|
||||
m_pointerDecoration.clear();
|
||||
}
|
||||
if (m_pointerDecoration || m_pointerInternalWindow) {
|
||||
t = nullptr;
|
||||
}
|
||||
auto oldWindow = m_pointerWindow;
|
||||
if (!oldWindow.isNull() && t == m_pointerWindow.data()) {
|
||||
return;
|
||||
}
|
||||
if (auto seat = findSeat()) {
|
||||
// disconnect old surface
|
||||
if (oldWindow) {
|
||||
disconnect(oldWindow.data(), &Toplevel::geometryChanged, this, &InputRedirection::updateFocusedPointerPosition);
|
||||
if (AbstractBackend *b = waylandServer()->backend()) {
|
||||
if (auto p = seat->focusedPointer()) {
|
||||
if (auto c = p->cursor()) {
|
||||
disconnect(c, &KWayland::Server::Cursor::changed, b, &AbstractBackend::installCursorFromServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (t && t->surface()) {
|
||||
seat->setFocusedPointerSurface(t->surface(), t->inputTransformation());
|
||||
connect(t, &Toplevel::geometryChanged, this, &InputRedirection::updateFocusedPointerPosition);
|
||||
if (AbstractBackend *b = waylandServer()->backend()) {
|
||||
b->installCursorFromServer();
|
||||
if (auto p = seat->focusedPointer()) {
|
||||
if (auto c = p->cursor()) {
|
||||
connect(c, &KWayland::Server::Cursor::changed, b, &AbstractBackend::installCursorFromServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
seat->setFocusedPointerSurface(nullptr);
|
||||
t = nullptr;
|
||||
}
|
||||
}
|
||||
if (!t) {
|
||||
m_pointerWindow.clear();
|
||||
return;
|
||||
}
|
||||
m_pointerWindow = QWeakPointer<Toplevel>(t);
|
||||
}
|
||||
|
||||
void InputRedirection::updatePointerDecoration(Toplevel *t)
|
||||
{
|
||||
const auto oldDeco = m_pointerDecoration;
|
||||
bool needsReset = waylandServer() && waylandServer()->isScreenLocked();
|
||||
if (AbstractClient *c = dynamic_cast<AbstractClient*>(t)) {
|
||||
// check whether it's on a Decoration
|
||||
if (c->decoratedClient()) {
|
||||
const QRect clientRect = QRect(c->clientPos(), c->clientSize()).translated(c->pos());
|
||||
if (!clientRect.contains(m_globalPointer.toPoint())) {
|
||||
m_pointerDecoration = c->decoratedClient();
|
||||
} else {
|
||||
needsReset = true;
|
||||
}
|
||||
} else {
|
||||
needsReset = true;
|
||||
}
|
||||
} else {
|
||||
needsReset = true;
|
||||
}
|
||||
if (needsReset) {
|
||||
m_pointerDecoration.clear();
|
||||
}
|
||||
|
||||
if (oldDeco && oldDeco != m_pointerDecoration) {
|
||||
// send leave
|
||||
QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF());
|
||||
QCoreApplication::instance()->sendEvent(oldDeco->decoration(), &event);
|
||||
if (!m_pointerDecoration && waylandServer()) {
|
||||
waylandServer()->backend()->installCursorImage(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
if (m_pointerDecoration) {
|
||||
const QPointF p = m_globalPointer - t->pos();
|
||||
QHoverEvent event(QEvent::HoverMove, p, p);
|
||||
QCoreApplication::instance()->sendEvent(m_pointerDecoration->decoration(), &event);
|
||||
m_pointerDecoration->client()->processDecorationMove();
|
||||
installCursorFromDecoration();
|
||||
}
|
||||
}
|
||||
|
||||
void InputRedirection::updatePointerInternalWindow()
|
||||
{
|
||||
const auto oldInternalWindow = m_pointerInternalWindow;
|
||||
if (waylandServer()) {
|
||||
bool found = false;
|
||||
bool needsReset = waylandServer()->isScreenLocked();
|
||||
const auto &internalClients = waylandServer()->internalClients();
|
||||
const bool change = m_pointerInternalWindow.isNull() || !(m_pointerInternalWindow->flags().testFlag(Qt::Popup) && m_pointerInternalWindow->isVisible());
|
||||
if (!internalClients.isEmpty() && change) {
|
||||
auto it = internalClients.end();
|
||||
do {
|
||||
it--;
|
||||
if (QWindow *w = (*it)->internalWindow()) {
|
||||
if (!w->isVisible()) {
|
||||
continue;
|
||||
}
|
||||
if (w->geometry().contains(m_globalPointer.toPoint())) {
|
||||
m_pointerInternalWindow = QPointer<QWindow>(w);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (it != internalClients.begin());
|
||||
if (!found) {
|
||||
needsReset = true;
|
||||
}
|
||||
}
|
||||
if (needsReset) {
|
||||
m_pointerInternalWindow.clear();
|
||||
}
|
||||
}
|
||||
if (oldInternalWindow != m_pointerInternalWindow) {
|
||||
// changed
|
||||
if (oldInternalWindow) {
|
||||
disconnect(oldInternalWindow.data(), &QWindow::visibleChanged, this, &InputRedirection::pointerInternalWindowVisibilityChanged);
|
||||
QEvent event(QEvent::Leave);
|
||||
QCoreApplication::sendEvent(oldInternalWindow.data(), &event);
|
||||
}
|
||||
if (m_pointerInternalWindow) {
|
||||
connect(oldInternalWindow.data(), &QWindow::visibleChanged, this, &InputRedirection::pointerInternalWindowVisibilityChanged);
|
||||
QEnterEvent event(m_globalPointer - m_pointerInternalWindow->position(),
|
||||
m_globalPointer - m_pointerInternalWindow->position(),
|
||||
m_globalPointer);
|
||||
QCoreApplication::sendEvent(m_pointerInternalWindow.data(), &event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputRedirection::pointerInternalWindowVisibilityChanged(bool visible)
|
||||
{
|
||||
if (!visible) {
|
||||
updatePointerWindow();
|
||||
}
|
||||
}
|
||||
|
||||
void InputRedirection::installCursorFromDecoration()
|
||||
{
|
||||
if (waylandServer() && m_pointerDecoration) {
|
||||
waylandServer()->backend()->installCursorImage(m_pointerDecoration->client()->cursor());
|
||||
}
|
||||
}
|
||||
|
||||
void InputRedirection::updateFocusedPointerPosition()
|
||||
{
|
||||
if (!workspace()) {
|
||||
return;
|
||||
}
|
||||
if (m_pointerWindow.isNull()) {
|
||||
return;
|
||||
}
|
||||
if (workspace()->getMovingClient()) {
|
||||
// don't update while moving
|
||||
return;
|
||||
}
|
||||
if (auto seat = findSeat()) {
|
||||
if (m_pointerWindow.data()->surface() != seat->focusedPointerSurface()) {
|
||||
return;
|
||||
}
|
||||
seat->setFocusedPointerSurfaceTransformation(m_pointerWindow.data()->inputTransformation());
|
||||
}
|
||||
}
|
||||
|
||||
void InputRedirection::updateFocusedTouchPosition()
|
||||
{
|
||||
if (m_touchWindow.isNull()) {
|
||||
|
@ -1282,66 +1102,17 @@ void InputRedirection::updateFocusedTouchPosition()
|
|||
|
||||
void InputRedirection::processPointerMotion(const QPointF &pos, uint32_t time)
|
||||
{
|
||||
if (!workspace()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// first update to new mouse position
|
||||
// const QPointF oldPos = m_globalPointer;
|
||||
updatePointerPosition(pos);
|
||||
|
||||
// TODO: check which part of KWin would like to intercept the event
|
||||
QMouseEvent event(QEvent::MouseMove, m_globalPointer.toPoint(), m_globalPointer.toPoint(),
|
||||
Qt::NoButton, qtButtonStates(), keyboardModifiers());
|
||||
event.setTimestamp(time);
|
||||
|
||||
for (auto it = m_filters.constBegin(), end = m_filters.constEnd(); it != end; it++) {
|
||||
if ((*it)->pointerEvent(&event, 0)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_pointer->processMotion(pos, time);
|
||||
}
|
||||
|
||||
void InputRedirection::processPointerButton(uint32_t button, InputRedirection::PointerButtonState state, uint32_t time)
|
||||
{
|
||||
if (!workspace()) {
|
||||
return;
|
||||
}
|
||||
m_pointerButtons[button] = state;
|
||||
emit pointerButtonStateChanged(button, state);
|
||||
|
||||
QMouseEvent event(buttonStateToEvent(state), m_globalPointer.toPoint(), m_globalPointer.toPoint(),
|
||||
buttonToQtMouseButton(button), qtButtonStates(), keyboardModifiers());
|
||||
event.setTimestamp(time);
|
||||
|
||||
for (auto it = m_filters.constBegin(), end = m_filters.constEnd(); it != end; it++) {
|
||||
if ((*it)->pointerEvent(&event, button)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_pointer->processButton(button, state, time);
|
||||
}
|
||||
|
||||
void InputRedirection::processPointerAxis(InputRedirection::PointerAxis axis, qreal delta, uint32_t time)
|
||||
{
|
||||
if (delta == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit pointerAxisChanged(axis, delta);
|
||||
|
||||
QWheelEvent wheelEvent(m_globalPointer, m_globalPointer, QPoint(),
|
||||
(axis == PointerAxisHorizontal) ? QPoint(delta, 0) : QPoint(0, delta),
|
||||
delta,
|
||||
(axis == PointerAxisHorizontal) ? Qt::Horizontal : Qt::Vertical,
|
||||
qtButtonStates(),
|
||||
m_xkb->modifiers());
|
||||
wheelEvent.setTimestamp(time);
|
||||
|
||||
for (auto it = m_filters.constBegin(), end = m_filters.constEnd(); it != end; it++) {
|
||||
if ((*it)->wheelEvent(&wheelEvent)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_pointer->processAxis(axis, delta, time);
|
||||
}
|
||||
|
||||
void InputRedirection::updateKeyboardWindow()
|
||||
|
@ -1517,47 +1288,9 @@ void InputRedirection::removeTouchId(quint32 internalId)
|
|||
m_touchIdMapper.remove(internalId);
|
||||
}
|
||||
|
||||
QEvent::Type InputRedirection::buttonStateToEvent(InputRedirection::PointerButtonState state)
|
||||
{
|
||||
switch (state) {
|
||||
case KWin::InputRedirection::PointerButtonReleased:
|
||||
return QEvent::MouseButtonRelease;
|
||||
case KWin::InputRedirection::PointerButtonPressed:
|
||||
return QEvent::MouseButtonPress;
|
||||
}
|
||||
return QEvent::None;
|
||||
}
|
||||
|
||||
Qt::MouseButton InputRedirection::buttonToQtMouseButton(uint32_t button)
|
||||
{
|
||||
switch (button) {
|
||||
case BTN_LEFT:
|
||||
return Qt::LeftButton;
|
||||
case BTN_MIDDLE:
|
||||
return Qt::MiddleButton;
|
||||
case BTN_RIGHT:
|
||||
return Qt::RightButton;
|
||||
case BTN_BACK:
|
||||
return Qt::XButton1;
|
||||
case BTN_FORWARD:
|
||||
return Qt::XButton2;
|
||||
}
|
||||
return Qt::NoButton;
|
||||
}
|
||||
|
||||
Qt::MouseButtons InputRedirection::qtButtonStates() const
|
||||
{
|
||||
Qt::MouseButtons buttons;
|
||||
for (auto it = m_pointerButtons.constBegin(); it != m_pointerButtons.constEnd(); ++it) {
|
||||
if (it.value() == KWin::InputRedirection::PointerButtonReleased) {
|
||||
continue;
|
||||
}
|
||||
Qt::MouseButton button = buttonToQtMouseButton(it.key());
|
||||
if (button != Qt::NoButton) {
|
||||
buttons |= button;
|
||||
}
|
||||
}
|
||||
return buttons;
|
||||
return m_pointer->buttons();
|
||||
}
|
||||
|
||||
static bool acceptsInput(Toplevel *t, const QPoint &pos)
|
||||
|
@ -1654,69 +1387,20 @@ void InputRedirection::registerShortcutForGlobalAccelTimestamp(QAction *action)
|
|||
});
|
||||
}
|
||||
|
||||
static bool screenContainsPos(const QPointF &pos)
|
||||
{
|
||||
for (int i = 0; i < screens()->count(); ++i) {
|
||||
if (screens()->geometry(i).contains(pos.toPoint())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void InputRedirection::updatePointerPosition(const QPointF &pos)
|
||||
{
|
||||
// verify that at least one screen contains the pointer position
|
||||
QPointF p = pos;
|
||||
if (!screenContainsPos(p)) {
|
||||
// allow either x or y to pass
|
||||
p = QPointF(m_globalPointer.x(), pos.y());
|
||||
if (!screenContainsPos(p)) {
|
||||
p = QPointF(pos.x(), m_globalPointer.y());
|
||||
if (!screenContainsPos(p)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_globalPointer = p;
|
||||
emit globalPointerChanged(m_globalPointer);
|
||||
}
|
||||
|
||||
void InputRedirection::updatePointerAfterScreenChange()
|
||||
{
|
||||
if (screenContainsPos(m_globalPointer)) {
|
||||
// pointer still on a screen
|
||||
return;
|
||||
}
|
||||
// pointer no longer on a screen, reposition to closes screen
|
||||
const QPointF pos = screens()->geometry(screens()->number(m_globalPointer.toPoint())).center();
|
||||
quint32 timestamp = 0;
|
||||
if (auto seat = findSeat()) {
|
||||
timestamp = seat->timestamp();
|
||||
}
|
||||
// TODO: better way to get timestamps
|
||||
processPointerMotion(pos, timestamp);
|
||||
}
|
||||
|
||||
void InputRedirection::warpPointer(const QPointF &pos)
|
||||
{
|
||||
if (supportsPointerWarping()) {
|
||||
quint32 timestamp = 0;
|
||||
if (waylandServer()) {
|
||||
waylandServer()->backend()->warpPointer(pos);
|
||||
timestamp = waylandServer()->seat()->timestamp();
|
||||
}
|
||||
// TODO: better way to get timestamps
|
||||
processPointerMotion(pos, timestamp);
|
||||
}
|
||||
m_pointer->warp(pos);
|
||||
}
|
||||
|
||||
bool InputRedirection::supportsPointerWarping() const
|
||||
{
|
||||
if (waylandServer() && waylandServer()->backend()->supportsPointerWarping()) {
|
||||
return true;
|
||||
}
|
||||
return m_pointerWarping;
|
||||
return m_pointer->supportsWarping();
|
||||
}
|
||||
|
||||
|
||||
QPointF InputRedirection::globalPointer() const
|
||||
{
|
||||
return m_pointer->pos();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
41
input.h
41
input.h
|
@ -44,6 +44,7 @@ class GlobalShortcutsManager;
|
|||
class Toplevel;
|
||||
class Xkb;
|
||||
class InputEventFilter;
|
||||
class PointerInputRedirection;
|
||||
|
||||
namespace Decoration
|
||||
{
|
||||
|
@ -86,7 +87,7 @@ public:
|
|||
/**
|
||||
* @return const QPointF& The current global pointer position
|
||||
*/
|
||||
const QPointF &globalPointer() const;
|
||||
QPointF globalPointer() const;
|
||||
Qt::MouseButtons qtButtonStates() const;
|
||||
Qt::KeyboardModifiers keyboardModifiers() const;
|
||||
|
||||
|
@ -150,8 +151,12 @@ public:
|
|||
void updateKeyboardWindow();
|
||||
void updateTouchWindow(const QPointF &pos);
|
||||
|
||||
public Q_SLOTS:
|
||||
void updatePointerWindow();
|
||||
QVector<InputEventFilter*> filters() const {
|
||||
return m_filters;
|
||||
}
|
||||
PointerInputRedirection *pointer() const {
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
|
@ -193,36 +198,16 @@ Q_SIGNALS:
|
|||
void keyStateChanged(quint32 keyCode, InputRedirection::KeyboardKeyState state);
|
||||
|
||||
private:
|
||||
static QEvent::Type buttonStateToEvent(PointerButtonState state);
|
||||
static Qt::MouseButton buttonToQtMouseButton(uint32_t button);
|
||||
void setupLibInput();
|
||||
void setupLibInputWithScreens();
|
||||
void updatePointerPosition(const QPointF &pos);
|
||||
void updatePointerAfterScreenChange();
|
||||
void registerShortcutForGlobalAccelTimestamp(QAction *action);
|
||||
void updateFocusedPointerPosition();
|
||||
void updateFocusedTouchPosition();
|
||||
void updatePointerDecoration(Toplevel *t);
|
||||
void updatePointerInternalWindow();
|
||||
void pointerInternalWindowVisibilityChanged(bool visible);
|
||||
void installCursorFromDecoration();
|
||||
void setupWorkspace();
|
||||
void reconfigure();
|
||||
void setupInputFilters();
|
||||
void installInputEventFilter(InputEventFilter *filter);
|
||||
QPointF m_globalPointer;
|
||||
QHash<uint32_t, PointerButtonState> m_pointerButtons;
|
||||
PointerInputRedirection *m_pointer;
|
||||
QScopedPointer<Xkb> m_xkb;
|
||||
/**
|
||||
* @brief The Toplevel which currently receives pointer events
|
||||
*/
|
||||
QWeakPointer<Toplevel> m_pointerWindow;
|
||||
/**
|
||||
* @brief The Decoration which currently receives pointer events.
|
||||
* Decoration belongs to the pointerWindow
|
||||
**/
|
||||
QPointer<Decoration::DecoratedClientImpl> m_pointerDecoration;
|
||||
QPointer<QWindow> m_pointerInternalWindow;
|
||||
/**
|
||||
* @brief The Toplevel which currently receives touch events
|
||||
*/
|
||||
|
@ -236,8 +221,6 @@ private:
|
|||
|
||||
LibInput::Connection *m_libInput = nullptr;
|
||||
|
||||
bool m_pointerWarping = false;
|
||||
|
||||
QVector<InputEventFilter*> m_filters;
|
||||
|
||||
KWIN_SINGLETON(InputRedirection)
|
||||
|
@ -344,12 +327,6 @@ InputRedirection *input()
|
|||
return InputRedirection::s_self;
|
||||
}
|
||||
|
||||
inline
|
||||
const QPointF &InputRedirection::globalPointer() const
|
||||
{
|
||||
return m_globalPointer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline
|
||||
void InputRedirection::registerShortcut(const QKeySequence &shortcut, QAction *action, T *receiver, void (T::*slot)()) {
|
||||
|
|
|
@ -47,3 +47,8 @@ bool KWin::InputRedirection::supportsPointerWarping() const
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QPointF KWin::InputRedirection::globalPointer() const
|
||||
{
|
||||
return QPointF();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2013, 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "pointer_input.h"
|
||||
#include "abstract_backend.h"
|
||||
#include "screens.h"
|
||||
#include "shell_client.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "decorations/decoratedclient.h"
|
||||
// KDecoration
|
||||
#include <KDecoration2/Decoration>
|
||||
// KWayland
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
// screenlocker
|
||||
#include <KScreenLocker/KsldApp>
|
||||
|
||||
#include <QHoverEvent>
|
||||
#include <QWindow>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
static Qt::MouseButton buttonToQtMouseButton(uint32_t button)
|
||||
{
|
||||
switch (button) {
|
||||
case BTN_LEFT:
|
||||
return Qt::LeftButton;
|
||||
case BTN_MIDDLE:
|
||||
return Qt::MiddleButton;
|
||||
case BTN_RIGHT:
|
||||
return Qt::RightButton;
|
||||
case BTN_BACK:
|
||||
return Qt::XButton1;
|
||||
case BTN_FORWARD:
|
||||
return Qt::XButton2;
|
||||
}
|
||||
return Qt::NoButton;
|
||||
}
|
||||
|
||||
static bool screenContainsPos(const QPointF &pos)
|
||||
{
|
||||
for (int i = 0; i < screens()->count(); ++i) {
|
||||
if (screens()->geometry(i).contains(pos.toPoint())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PointerInputRedirection::PointerInputRedirection(InputRedirection* parent)
|
||||
: QObject(parent)
|
||||
, m_input(parent)
|
||||
, m_supportsWarping(Application::usesLibinput())
|
||||
{
|
||||
}
|
||||
|
||||
PointerInputRedirection::~PointerInputRedirection() = default;
|
||||
|
||||
void PointerInputRedirection::init()
|
||||
{
|
||||
Q_ASSERT(!m_inited);
|
||||
m_inited = true;
|
||||
connect(workspace(), &Workspace::stackingOrderChanged, this, &PointerInputRedirection::update);
|
||||
connect(screens(), &Screens::changed, this, &PointerInputRedirection::updateAfterScreenChange);
|
||||
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &PointerInputRedirection::update);
|
||||
connect(workspace(), &QObject::destroyed, this, [this] { m_inited = false; });
|
||||
connect(waylandServer(), &QObject::destroyed, this, [this] { m_inited = false; });
|
||||
|
||||
// warp the cursor to center of screen
|
||||
warp(screens()->geometry().center());
|
||||
updateAfterScreenChange();
|
||||
}
|
||||
|
||||
void PointerInputRedirection::processMotion(const QPointF &pos, uint32_t time)
|
||||
{
|
||||
if (!m_inited) {
|
||||
return;
|
||||
}
|
||||
updatePosition(pos);
|
||||
QMouseEvent event(QEvent::MouseMove, m_pos.toPoint(), m_pos.toPoint(),
|
||||
Qt::NoButton, m_qtButtons, m_input->keyboardModifiers());
|
||||
event.setTimestamp(time);
|
||||
|
||||
const auto &filters = m_input->filters();
|
||||
for (auto it = filters.begin(), end = filters.end(); it != end; it++) {
|
||||
if ((*it)->pointerEvent(&event, 0)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PointerInputRedirection::processButton(uint32_t button, InputRedirection::PointerButtonState state, uint32_t time)
|
||||
{
|
||||
if (!m_inited) {
|
||||
return;
|
||||
}
|
||||
updateButton(button, state);
|
||||
|
||||
QEvent::Type type;
|
||||
switch (state) {
|
||||
case InputRedirection::PointerButtonReleased:
|
||||
type = QEvent::MouseButtonRelease;
|
||||
break;
|
||||
case InputRedirection::PointerButtonPressed:
|
||||
type = QEvent::MouseButtonPress;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
QMouseEvent event(type, m_pos.toPoint(), m_pos.toPoint(),
|
||||
buttonToQtMouseButton(button), m_qtButtons, m_input->keyboardModifiers());
|
||||
event.setTimestamp(time);
|
||||
|
||||
const auto &filters = m_input->filters();
|
||||
for (auto it = filters.begin(), end = filters.end(); it != end; it++) {
|
||||
if ((*it)->pointerEvent(&event, button)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PointerInputRedirection::processAxis(InputRedirection::PointerAxis axis, qreal delta, uint32_t time)
|
||||
{
|
||||
if (!m_inited) {
|
||||
return;
|
||||
}
|
||||
if (delta == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit m_input->pointerAxisChanged(axis, delta);
|
||||
|
||||
QWheelEvent wheelEvent(m_pos, m_pos, QPoint(),
|
||||
(axis == InputRedirection::PointerAxisHorizontal) ? QPoint(delta, 0) : QPoint(0, delta),
|
||||
delta,
|
||||
(axis == InputRedirection::PointerAxisHorizontal) ? Qt::Horizontal : Qt::Vertical,
|
||||
m_qtButtons,
|
||||
m_input->keyboardModifiers());
|
||||
wheelEvent.setTimestamp(time);
|
||||
|
||||
const auto &filters = m_input->filters();
|
||||
for (auto it = filters.begin(), end = filters.end(); it != end; it++) {
|
||||
if ((*it)->wheelEvent(&wheelEvent)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PointerInputRedirection::update()
|
||||
{
|
||||
if (!m_inited) {
|
||||
return;
|
||||
}
|
||||
// TODO: handle pointer grab aka popups
|
||||
Toplevel *t = m_input->findToplevel(m_pos.toPoint());
|
||||
updateInternalWindow();
|
||||
if (!m_internalWindow) {
|
||||
updateDecoration(t);
|
||||
} else {
|
||||
// TODO: send hover leave to decoration
|
||||
m_decoration.clear();
|
||||
}
|
||||
if (m_decoration || m_internalWindow) {
|
||||
t = nullptr;
|
||||
}
|
||||
auto oldWindow = m_window;
|
||||
if (!oldWindow.isNull() && t == m_window.data()) {
|
||||
return;
|
||||
}
|
||||
auto seat = waylandServer()->seat();
|
||||
// disconnect old surface
|
||||
if (oldWindow) {
|
||||
disconnect(m_windowGeometryConnection);
|
||||
m_windowGeometryConnection = QMetaObject::Connection();
|
||||
if (auto p = seat->focusedPointer()) {
|
||||
if (auto c = p->cursor()) {
|
||||
disconnect(c, &KWayland::Server::Cursor::changed, waylandServer()->backend(), &AbstractBackend::installCursorFromServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (t && t->surface()) {
|
||||
seat->setFocusedPointerSurface(t->surface(), t->inputTransformation());
|
||||
m_windowGeometryConnection = connect(t, &Toplevel::geometryChanged, this,
|
||||
[this] {
|
||||
if (m_window.isNull()) {
|
||||
return;
|
||||
}
|
||||
// TODO: can we check on the client instead?
|
||||
if (workspace()->getMovingClient()) {
|
||||
// don't update while moving
|
||||
return;
|
||||
}
|
||||
auto seat = waylandServer()->seat();
|
||||
if (m_window.data()->surface() != seat->focusedPointerSurface()) {
|
||||
return;
|
||||
}
|
||||
seat->setFocusedPointerSurfaceTransformation(m_window.data()->inputTransformation());
|
||||
}
|
||||
);
|
||||
waylandServer()->backend()->installCursorFromServer();
|
||||
if (auto p = seat->focusedPointer()) {
|
||||
if (auto c = p->cursor()) {
|
||||
connect(c, &KWayland::Server::Cursor::changed, waylandServer()->backend(), &AbstractBackend::installCursorFromServer);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
seat->setFocusedPointerSurface(nullptr);
|
||||
t = nullptr;
|
||||
}
|
||||
if (!t) {
|
||||
m_window.clear();
|
||||
return;
|
||||
}
|
||||
m_window = QPointer<Toplevel>(t);
|
||||
}
|
||||
|
||||
void PointerInputRedirection::updateInternalWindow()
|
||||
{
|
||||
const auto oldInternalWindow = m_internalWindow;
|
||||
bool found = false;
|
||||
// TODO: screen locked check without going through wayland server
|
||||
bool needsReset = waylandServer()->isScreenLocked();
|
||||
const auto &internalClients = waylandServer()->internalClients();
|
||||
const bool change = m_internalWindow.isNull() || !(m_internalWindow->flags().testFlag(Qt::Popup) && m_internalWindow->isVisible());
|
||||
if (!internalClients.isEmpty() && change) {
|
||||
auto it = internalClients.end();
|
||||
do {
|
||||
it--;
|
||||
if (QWindow *w = (*it)->internalWindow()) {
|
||||
if (!w->isVisible()) {
|
||||
continue;
|
||||
}
|
||||
if (w->geometry().contains(m_pos.toPoint())) {
|
||||
m_internalWindow = QPointer<QWindow>(w);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (it != internalClients.begin());
|
||||
if (!found) {
|
||||
needsReset = true;
|
||||
}
|
||||
}
|
||||
if (needsReset) {
|
||||
m_internalWindow.clear();
|
||||
}
|
||||
if (oldInternalWindow != m_internalWindow) {
|
||||
// changed
|
||||
if (oldInternalWindow) {
|
||||
disconnect(m_internalWindowConnection);
|
||||
m_internalWindowConnection = QMetaObject::Connection();
|
||||
QEvent event(QEvent::Leave);
|
||||
QCoreApplication::sendEvent(oldInternalWindow.data(), &event);
|
||||
}
|
||||
if (m_internalWindow) {
|
||||
m_internalWindowConnection = connect(m_internalWindow.data(), &QWindow::visibleChanged, this,
|
||||
[this] (bool visible) {
|
||||
if (!visible) {
|
||||
update();
|
||||
}
|
||||
});
|
||||
QEnterEvent event(m_pos - m_internalWindow->position(),
|
||||
m_pos - m_internalWindow->position(),
|
||||
m_pos);
|
||||
QCoreApplication::sendEvent(m_internalWindow.data(), &event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PointerInputRedirection::updateDecoration(Toplevel *t)
|
||||
{
|
||||
const auto oldDeco = m_decoration;
|
||||
bool needsReset = waylandServer()->isScreenLocked();
|
||||
if (AbstractClient *c = dynamic_cast<AbstractClient*>(t)) {
|
||||
// check whether it's on a Decoration
|
||||
if (c->decoratedClient()) {
|
||||
const QRect clientRect = QRect(c->clientPos(), c->clientSize()).translated(c->pos());
|
||||
if (!clientRect.contains(m_pos.toPoint())) {
|
||||
m_decoration = c->decoratedClient();
|
||||
} else {
|
||||
needsReset = true;
|
||||
}
|
||||
} else {
|
||||
needsReset = true;
|
||||
}
|
||||
} else {
|
||||
needsReset = true;
|
||||
}
|
||||
if (needsReset) {
|
||||
m_decoration.clear();
|
||||
}
|
||||
|
||||
if (oldDeco && oldDeco != m_decoration) {
|
||||
// send leave
|
||||
QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF());
|
||||
QCoreApplication::instance()->sendEvent(oldDeco->decoration(), &event);
|
||||
if (!m_decoration) {
|
||||
waylandServer()->backend()->installCursorImage(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
if (m_decoration) {
|
||||
const QPointF p = m_pos - t->pos();
|
||||
QHoverEvent event(QEvent::HoverMove, p, p);
|
||||
QCoreApplication::instance()->sendEvent(m_decoration->decoration(), &event);
|
||||
m_decoration->client()->processDecorationMove();
|
||||
installCursorFromDecoration();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerInputRedirection::updatePosition(const QPointF &pos)
|
||||
{
|
||||
// verify that at least one screen contains the pointer position
|
||||
QPointF p = pos;
|
||||
if (!screenContainsPos(p)) {
|
||||
// allow either x or y to pass
|
||||
p = QPointF(m_pos.x(), pos.y());
|
||||
if (!screenContainsPos(p)) {
|
||||
p = QPointF(pos.x(), m_pos.y());
|
||||
if (!screenContainsPos(p)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_pos = p;
|
||||
emit m_input->globalPointerChanged(m_pos);
|
||||
}
|
||||
|
||||
void PointerInputRedirection::updateButton(uint32_t button, InputRedirection::PointerButtonState state)
|
||||
{
|
||||
m_buttons[button] = state;
|
||||
|
||||
// update Qt buttons
|
||||
m_qtButtons = Qt::NoButton;
|
||||
for (auto it = m_buttons.constBegin(); it != m_buttons.constEnd(); ++it) {
|
||||
if (it.value() == InputRedirection::PointerButtonReleased) {
|
||||
continue;
|
||||
}
|
||||
Qt::MouseButton button = buttonToQtMouseButton(it.key());
|
||||
// TODO: we need to map all buttons, otherwise checks for are buttons pressed fail
|
||||
if (button != Qt::NoButton) {
|
||||
m_qtButtons |= button;
|
||||
}
|
||||
}
|
||||
|
||||
emit m_input->pointerButtonStateChanged(button, state);
|
||||
}
|
||||
|
||||
void PointerInputRedirection::warp(const QPointF &pos)
|
||||
{
|
||||
if (supportsWarping()) {
|
||||
waylandServer()->backend()->warpPointer(pos);
|
||||
processMotion(pos, waylandServer()->seat()->timestamp());
|
||||
}
|
||||
}
|
||||
|
||||
bool PointerInputRedirection::supportsWarping() const
|
||||
{
|
||||
if (!m_inited) {
|
||||
return false;
|
||||
}
|
||||
if (m_supportsWarping) {
|
||||
return true;
|
||||
}
|
||||
if (waylandServer()->backend()->supportsPointerWarping()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PointerInputRedirection::installCursorFromDecoration()
|
||||
{
|
||||
if (!m_inited || !m_decoration) {
|
||||
return;
|
||||
}
|
||||
waylandServer()->backend()->installCursorImage(m_decoration->client()->cursor());
|
||||
}
|
||||
|
||||
void PointerInputRedirection::updateAfterScreenChange()
|
||||
{
|
||||
if (!m_inited) {
|
||||
return;
|
||||
}
|
||||
if (screenContainsPos(m_pos)) {
|
||||
// pointer still on a screen
|
||||
return;
|
||||
}
|
||||
// pointer no longer on a screen, reposition to closes screen
|
||||
const QPointF pos = screens()->geometry(screens()->number(m_pos.toPoint())).center();
|
||||
// TODO: better way to get timestamps
|
||||
processMotion(pos, waylandServer()->seat()->timestamp());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2013, 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#ifndef KWIN_POINTER_INPUT_H
|
||||
#define KWIN_POINTER_INPUT_H
|
||||
|
||||
#include "input.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QPointF>
|
||||
|
||||
class QWindow;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class InputRedirection;
|
||||
class Toplevel;
|
||||
|
||||
namespace Decoration
|
||||
{
|
||||
class DecoratedClientImpl;
|
||||
}
|
||||
|
||||
class PointerInputRedirection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PointerInputRedirection(InputRedirection *parent);
|
||||
virtual ~PointerInputRedirection();
|
||||
|
||||
void init();
|
||||
|
||||
void update();
|
||||
void updateAfterScreenChange();
|
||||
bool supportsWarping() const;
|
||||
void warp(const QPointF &pos);
|
||||
|
||||
QPointF pos() const {
|
||||
return m_pos;
|
||||
}
|
||||
Qt::MouseButtons buttons() const {
|
||||
return m_qtButtons;
|
||||
}
|
||||
QPointer<Toplevel> window() const {
|
||||
return m_window;
|
||||
}
|
||||
QPointer<Decoration::DecoratedClientImpl> decoration() const {
|
||||
return m_decoration;
|
||||
}
|
||||
QPointer<QWindow> internalWindow() const {
|
||||
return m_internalWindow;
|
||||
}
|
||||
|
||||
void installCursorFromDecoration();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
void processMotion(const QPointF &pos, uint32_t time);
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
void processButton(uint32_t button, InputRedirection::PointerButtonState state, uint32_t time);
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
void processAxis(InputRedirection::PointerAxis axis, qreal delta, uint32_t time);
|
||||
|
||||
private:
|
||||
void updatePosition(const QPointF &pos);
|
||||
void updateButton(uint32_t button, InputRedirection::PointerButtonState state);
|
||||
void updateInternalWindow();
|
||||
void updateDecoration(Toplevel *t);
|
||||
InputRedirection *m_input;
|
||||
bool m_inited = false;
|
||||
bool m_supportsWarping;
|
||||
QPointF m_pos;
|
||||
QHash<uint32_t, InputRedirection::PointerButtonState> m_buttons;
|
||||
Qt::MouseButtons m_qtButtons;
|
||||
/**
|
||||
* @brief The Toplevel which currently receives pointer events
|
||||
*/
|
||||
QPointer<Toplevel> m_window;
|
||||
/**
|
||||
* @brief The Decoration which currently receives pointer events.
|
||||
* Decoration belongs to the pointerWindow
|
||||
**/
|
||||
QPointer<Decoration::DecoratedClientImpl> m_decoration;
|
||||
QPointer<QWindow> m_internalWindow;
|
||||
QMetaObject::Connection m_windowGeometryConnection;
|
||||
QMetaObject::Connection m_internalWindowConnection;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -133,11 +133,6 @@ Workspace::Workspace(const QString &sessionKey)
|
|||
// first initialize the extensions
|
||||
Xcb::Extensions::self();
|
||||
|
||||
// start the Wayland Backend - will only be created if WAYLAND_DISPLAY is present
|
||||
if (kwinApp()->operationMode() != Application::OperationModeX11) {
|
||||
connect(this, SIGNAL(stackingOrderChanged()), input(), SLOT(updatePointerWindow()));
|
||||
}
|
||||
|
||||
#ifdef KWIN_BUILD_ACTIVITIES
|
||||
Activities *activities = nullptr;
|
||||
if (kwinApp()->usesKActivities()) {
|
||||
|
|
Loading…
Reference in New Issue