From 49e734f74389c3e01e8d132a9f00885e426cfa0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 24 Apr 2013 16:51:04 +0200 Subject: [PATCH] Change the way how effects can get mouse events With the removal of BoxSwitch all effects which want mouse events use the fullscreen input window. The available functionality is too complex both in EffectsHandler and in the Effects. With this change only fullscreen input windows are supported and all effects share the input window. This means there is at maximum one input window. This simplifies the code in the Effects as they don't have to keep track of the window they created any more. In EffectsHandler it means that only one window needs to be created, destroyed and raised. Also it means that we can properly react on screen size changes which had been ignored in the past. Also quite some roundtrips to X are no longer needed as we do not need to query the window geometry when creating the input window. REVIEW: 110156 --- effects.cpp | 224 +++++++++------------- effects.h | 13 +- effects/coverswitch/coverswitch.cpp | 10 +- effects/coverswitch/coverswitch.h | 3 +- effects/cube/cube.cpp | 13 +- effects/cube/cube.h | 3 +- effects/desktopgrid/desktopgrid.cpp | 15 +- effects/desktopgrid/desktopgrid.h | 3 +- effects/flipswitch/flipswitch.cpp | 12 +- effects/flipswitch/flipswitch.h | 3 +- effects/presentwindows/presentwindows.cpp | 19 +- effects/presentwindows/presentwindows.h | 3 +- libkwineffects/kwineffects.cpp | 12 +- libkwineffects/kwineffects.h | 38 +++- xcbutils.h | 8 + 15 files changed, 166 insertions(+), 213 deletions(-) diff --git a/effects.cpp b/effects.cpp index 9d4b3db2e1..073c9f8c9a 100644 --- a/effects.cpp +++ b/effects.cpp @@ -270,9 +270,6 @@ EffectsHandlerImpl::~EffectsHandlerImpl() ungrabKeyboard(); foreach (const EffectPair & ep, loaded_effects) unloadEffect(ep.first); - foreach (const InputWindowPair & pos, input_windows) { - xcb_destroy_window(connection(), pos.second); - } } void EffectsHandlerImpl::setupClientConnections(Client* c) @@ -689,6 +686,50 @@ void EffectsHandlerImpl::grabbedKeyboardEvent(QKeyEvent* e) keyboard_grab_effect->grabbedKeyboardEvent(e); } +void EffectsHandlerImpl::startMouseInterception(Effect *effect, Qt::CursorShape shape) +{ + if (m_grabbedMouseEffects.contains(effect)) { + return; + } + m_grabbedMouseEffects.append(effect); + if (m_grabbedMouseEffects.size() != 1) { + return; + } + // NOTE: it is intended to not perform an XPointerGrab on X11. See documentation in kwineffects.h + // The mouse grab is implemented by using a full screen input only window + if (!m_mouseInterceptionWindow.isValid()) { + const QRect geo(0, 0, displayWidth(), displayHeight()); + const uint32_t mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_CURSOR; + const uint32_t values[] = { + true, + XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION, + Cursor::x11Cursor(shape) + }; + m_mouseInterceptionWindow.reset(Xcb::createInputWindow(geo, mask, values)); + } + m_mouseInterceptionWindow.map(); + m_mouseInterceptionWindow.raise(); + // Raise electric border windows above the input windows + // so they can still be triggered. +#ifdef KWIN_BUILD_SCREENEDGES + ScreenEdges::self()->ensureOnTop(); +#endif +} + +void EffectsHandlerImpl::stopMouseInterception(Effect *effect) +{ + if (!m_grabbedMouseEffects.contains(effect)) { + return; + } + m_grabbedMouseEffects.removeAll(effect); + if (m_grabbedMouseEffects.isEmpty()) { + m_mouseInterceptionWindow.unmap(); +#ifdef KWIN_BUILD_SCREENEDGES + Workspace::self()->stackScreenEdgesUnderOverrideRedirect(); +#endif + } +} + void* EffectsHandlerImpl::getProxy(QString name) { // All effects start with "kwin4_effect_", prepend it to the name @@ -719,6 +760,9 @@ bool EffectsHandlerImpl::hasKeyboardGrab() const void EffectsHandlerImpl::desktopResized(const QSize &size) { m_scene->screenGeometryChanged(size); + if (m_mouseInterceptionWindow.isValid()) { + m_mouseInterceptionWindow.setGeometry(QRect(0, 0, size.width(), size.height())); + } emit screenGeometryChanged(size); } @@ -1130,158 +1174,65 @@ QRect EffectsHandlerImpl::clientArea(clientAreaOption opt, const QPoint& p, int return Workspace::self()->clientArea(opt, p, desktop); } -xcb_window_t EffectsHandlerImpl::createInputWindow(Effect* e, int x, int y, int w, int h, const QCursor& cursor) +void EffectsHandlerImpl::defineCursor(Qt::CursorShape shape) { - xcb_window_t win = XCB_WINDOW_NONE; - QList::iterator it = input_windows.begin(); - while (it != input_windows.end()) { - if (it->first != e) { - ++it; - continue; - } - Xcb::WindowAttributes attributes(it->second); - Xcb::WindowGeometry geometry(it->second); - if (!attributes) { - // this is some random junk that certainly should no be here - kDebug(1212) << "found input window that is NOT on the server, something is VERY broken here"; - Q_ASSERT(false); // exit in debug mode - for releases we'll be a bit more graceful - it = input_windows.erase(it); - continue; - } - if (geometry.rect() == QRect(x, y, w, h)) { - win = it->second; // re-use - break; - } else if (attributes->map_state == XCB_MAP_STATE_UNMAPPED) { - // probably old one, likely no longer of interest - xcb_destroy_window(connection(), it->second); - it = input_windows.erase(it); - continue; - } - ++it; + if (!m_mouseInterceptionWindow.isValid()) { + return; } - if (win == XCB_WINDOW_NONE) { - win = xcb_generate_id(connection()); - // TODO keeping on top? - // TODO enter/leave notify? - const uint32_t mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_CURSOR; - const uint32_t values[] = { - true, - XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION, - Cursor::x11Cursor(cursor.shape()) - }; - xcb_create_window(connection(), 0, win, rootWindow(), x, y, w, h, 0, XCB_WINDOW_CLASS_INPUT_ONLY, - XCB_COPY_FROM_PARENT, mask, values); - input_windows.append(qMakePair(e, win)); - } - xcb_map_window(connection(), win); - const uint32_t values[] = { XCB_STACK_MODE_ABOVE }; - xcb_configure_window(connection(), win, XCB_CONFIG_WINDOW_STACK_MODE, values); - // Raise electric border windows above the input windows - // so they can still be triggered. -#ifdef KWIN_BUILD_SCREENEDGES - ScreenEdges::self()->ensureOnTop(); -#endif - if (input_windows.count() > 10) // that sounds like some leak - could still be correct, thoug - so NO ABORT HERE! - kDebug() << "** warning ** there are now " << input_windows.count() << - "input windows what's a bit much - please have a look and if this counts up, better report a bug"; - return win; -} - -void EffectsHandlerImpl::destroyInputWindow(xcb_window_t w) -{ - foreach (const InputWindowPair & pos, input_windows) { - if (pos.second == w) { - xcb_unmap_window(connection(), w); -#ifdef KWIN_BUILD_SCREENEDGES - Workspace::self()->stackScreenEdgesUnderOverrideRedirect(); -#endif - return; - } - } - abort(); -} - -void EffectsHandlerImpl::defineCursor(xcb_window_t w, Qt::CursorShape shape) -{ - Xcb::defineCursor(w, Cursor::x11Cursor(shape)); + m_mouseInterceptionWindow.defineCursor(Cursor::x11Cursor(shape)); } bool EffectsHandlerImpl::checkInputWindowEvent(XEvent* e) { if (e->type != ButtonPress && e->type != ButtonRelease && e->type != MotionNotify) return false; - foreach (const InputWindowPair & pos, input_windows) { - if (pos.second == e->xany.window) { - switch(e->type) { - case ButtonPress: { - XButtonEvent* e2 = &e->xbutton; - Qt::MouseButton button = x11ToQtMouseButton(e2->button); - Qt::MouseButtons buttons = x11ToQtMouseButtons(e2->state) | button; - QMouseEvent ev(QEvent::MouseButtonPress, - QPoint(e2->x, e2->y), QPoint(e2->x_root, e2->y_root), - button, buttons, x11ToQtKeyboardModifiers(e2->state)); - pos.first->windowInputMouseEvent(pos.second, &ev); - break; // ---> - } - case ButtonRelease: { - XButtonEvent* e2 = &e->xbutton; - Qt::MouseButton button = x11ToQtMouseButton(e2->button); - Qt::MouseButtons buttons = x11ToQtMouseButtons(e2->state) & ~button; - QMouseEvent ev(QEvent::MouseButtonRelease, - QPoint(e2->x, e2->y), QPoint(e2->x_root, e2->y_root), - button, buttons, x11ToQtKeyboardModifiers(e2->state)); - pos.first->windowInputMouseEvent(pos.second, &ev); - break; // ---> - } - case MotionNotify: { - XMotionEvent* e2 = &e->xmotion; - QMouseEvent ev(QEvent::MouseMove, QPoint(e2->x, e2->y), QPoint(e2->x_root, e2->y_root), - Qt::NoButton, x11ToQtMouseButtons(e2->state), x11ToQtKeyboardModifiers(e2->state)); - pos.first->windowInputMouseEvent(pos.second, &ev); - break; // ---> - } - } - return true; // eat event + if (m_grabbedMouseEffects.isEmpty() || m_mouseInterceptionWindow != e->xany.window) { + return false; + } + foreach (Effect *effect, m_grabbedMouseEffects) { + switch(e->type) { + case ButtonPress: { + XButtonEvent* e2 = &e->xbutton; + Qt::MouseButton button = x11ToQtMouseButton(e2->button); + Qt::MouseButtons buttons = x11ToQtMouseButtons(e2->state) | button; + QMouseEvent ev(QEvent::MouseButtonPress, + QPoint(e2->x, e2->y), QPoint(e2->x_root, e2->y_root), + button, buttons, x11ToQtKeyboardModifiers(e2->state)); + effect->windowInputMouseEvent(&ev); + break; // ---> + } + case ButtonRelease: { + XButtonEvent* e2 = &e->xbutton; + Qt::MouseButton button = x11ToQtMouseButton(e2->button); + Qt::MouseButtons buttons = x11ToQtMouseButtons(e2->state) & ~button; + QMouseEvent ev(QEvent::MouseButtonRelease, + QPoint(e2->x, e2->y), QPoint(e2->x_root, e2->y_root), + button, buttons, x11ToQtKeyboardModifiers(e2->state)); + effect->windowInputMouseEvent(&ev); + break; // ---> + } + case MotionNotify: { + XMotionEvent* e2 = &e->xmotion; + QMouseEvent ev(QEvent::MouseMove, QPoint(e2->x, e2->y), QPoint(e2->x_root, e2->y_root), + Qt::NoButton, x11ToQtMouseButtons(e2->state), x11ToQtKeyboardModifiers(e2->state)); + effect->windowInputMouseEvent(&ev); + break; // ---> + } } } - return false; + return true; // eat event } void EffectsHandlerImpl::checkInputWindowStacking() { - if (input_windows.count() == 0) + if (m_grabbedMouseEffects.isEmpty()) { return; - xcb_window_t* wins = new xcb_window_t[input_windows.count()]; - QVector attributes(input_windows.count()); - int pos = 0; - foreach (const InputWindowPair &it, input_windows) { - attributes[pos] = Xcb::WindowAttributes(it.second); - pos++; } - pos = 0; - for (QVector::iterator it = attributes.begin(); it != attributes.end(); ++it) { - if (*it && (*it)->map_state != XCB_MAP_STATE_UNMAPPED) { - wins[pos++] = (*it).window(); - } - } - if (pos) { - const uint32_t values[] = { XCB_STACK_MODE_ABOVE }; - xcb_configure_window(connection(), wins[0], XCB_CONFIG_WINDOW_STACK_MODE, values); - for (int i=1; iensureOnTop(); + ScreenEdges::self()->ensureOnTop(); #endif } @@ -1521,6 +1472,7 @@ void EffectsHandlerImpl::unloadEffect(const QString& name) if (activeFullScreenEffect() == it.value().second) { setActiveFullScreenEffect(0); } + stopMouseInterception(it.value().second); // remove support properties for the effect const QList properties = m_propertiesForEffects.keys(); foreach (const QByteArray &property, properties) { diff --git a/effects.h b/effects.h index a4c33ddf98..4115433ee5 100644 --- a/effects.h +++ b/effects.h @@ -25,6 +25,7 @@ along with this program. If not, see . #include "kwineffects.h" #include "scene.h" +#include "xcbutils.h" #include #include @@ -38,7 +39,6 @@ class OrgFreedesktopScreenSaverInterface; namespace KWin { -typedef QPair< Effect*, xcb_window_t > InputWindowPair; class AbstractThumbnailItem; class DesktopThumbnailItem; @@ -110,6 +110,9 @@ public: virtual QPoint cursorPos() const; virtual bool grabKeyboard(Effect* effect); virtual void ungrabKeyboard(); + // not performing XGrabPointer + virtual void startMouseInterception(Effect *effect, Qt::CursorShape shape); + virtual void stopMouseInterception(Effect *effect); virtual void* getProxy(QString name); virtual void startMousePolling(); virtual void stopMousePolling(); @@ -143,10 +146,7 @@ public: virtual double animationTimeFactor() const; virtual WindowQuadType newWindowQuadType(); - virtual xcb_window_t createInputWindow(Effect* e, int x, int y, int w, int h, const QCursor& cursor); - using EffectsHandler::createInputWindow; - virtual void destroyInputWindow(xcb_window_t w); - virtual void defineCursor(xcb_window_t w, Qt::CursorShape shape); + virtual void defineCursor(Qt::CursorShape shape); virtual bool checkInputWindowEvent(XEvent* e); virtual void checkInputWindowStacking(); @@ -262,10 +262,11 @@ private: QHash m_managedProperties; Compositor *m_compositor; Scene *m_scene; - QList< InputWindowPair > input_windows; ScreenLockerWatcher *m_screenLockerWatcher; bool m_desktopRendering; int m_currentRenderedDesktop; + Xcb::Window m_mouseInterceptionWindow; + QList m_grabbedMouseEffects; }; class EffectWindowImpl : public EffectWindow diff --git a/effects/coverswitch/coverswitch.cpp b/effects/coverswitch/coverswitch.cpp index 626c05470e..dc44973216 100644 --- a/effects/coverswitch/coverswitch.cpp +++ b/effects/coverswitch/coverswitch.cpp @@ -527,7 +527,7 @@ void CoverSwitchEffect::slotTabBoxAdded(int mode) (mode == TabBoxCurrentAppWindowsMode && primaryTabBox) || (mode == TabBoxCurrentAppWindowsAlternativeMode && secondaryTabBox)) && effects->currentTabBoxWindowList().count() > 0) { - input = effects->createFullScreenInputWindow(this, Qt::ArrowCursor); + effects->startMouseInterception(this, Qt::ArrowCursor); activeScreen = effects->activeScreen(); if (!stop && !stopRequested) { effects->refTabBox(); @@ -598,7 +598,7 @@ void CoverSwitchEffect::slotTabBoxClosed() effects->setActiveFullScreenEffect(0); mActivated = false; effects->unrefTabBox(); - effects->destroyInputWindow(input); + effects->stopMouseInterception(this); effects->addRepaintFull(); } } @@ -891,10 +891,8 @@ void CoverSwitchEffect::paintWindows(const EffectWindowList& windows, bool left, } } -void CoverSwitchEffect::windowInputMouseEvent(Window w, QEvent* e) +void CoverSwitchEffect::windowInputMouseEvent(QEvent* e) { - assert(w == input); - Q_UNUSED(w); if (e->type() != QEvent::MouseButtonPress) return; // we don't want click events during animations @@ -965,7 +963,7 @@ void CoverSwitchEffect::abort() // in this case the cleanup is already done (see bug 207554) if (mActivated) { effects->unrefTabBox(); - effects->destroyInputWindow(input); + effects->stopMouseInterception(this); } effects->setActiveFullScreenEffect(0); mActivated = false; diff --git a/effects/coverswitch/coverswitch.h b/effects/coverswitch/coverswitch.h index 73ede747d9..75ebdfb58a 100644 --- a/effects/coverswitch/coverswitch.h +++ b/effects/coverswitch/coverswitch.h @@ -57,7 +57,7 @@ public: virtual void paintScreen(int mask, QRegion region, ScreenPaintData& data); virtual void postPaintScreen(); virtual void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data); - virtual void windowInputMouseEvent(Window w, QEvent* e); + virtual void windowInputMouseEvent(QEvent* e); virtual bool isActive() const; static bool supported(); @@ -131,7 +131,6 @@ private: bool startRequested; QTimeLine timeLine; QRect area; - Window input; float zPosition; float scaleFactor; enum Direction { diff --git a/effects/cube/cube.cpp b/effects/cube/cube.cpp index 636f929726..02fb4a4f5e 100644 --- a/effects/cube/cube.cpp +++ b/effects/cube/cube.cpp @@ -1136,7 +1136,7 @@ void CubeEffect::postPaintScreen() if (keyboard_grab) effects->ungrabKeyboard(); keyboard_grab = false; - effects->destroyInputWindow(input); + effects->stopMouseInterception(this); effects->setActiveFullScreenEffect(0); @@ -1896,8 +1896,7 @@ void CubeEffect::setActive(bool active) activated = true; activeScreen = effects->activeScreen(); keyboard_grab = effects->grabKeyboard(this); - input = effects->createInputWindow(this, 0, 0, displayWidth(), displayHeight(), - Qt::OpenHandCursor); + effects->startMouseInterception(this, Qt::OpenHandCursor); frontDesktop = effects->currentDesktop(); zoom = 0.0; zOrderingFactor = zPosition / (effects->stackingOrder().count() - 1); @@ -1983,10 +1982,10 @@ void CubeEffect::slotMouseChanged(const QPoint& pos, const QPoint& oldpos, Qt::M } } if (!oldbuttons.testFlag(Qt::LeftButton) && buttons.testFlag(Qt::LeftButton)) { - effects->defineCursor(input, Qt::ClosedHandCursor); + effects->defineCursor(Qt::ClosedHandCursor); } if (oldbuttons.testFlag(Qt::LeftButton) && !buttons.testFlag(Qt::LeftButton)) { - effects->defineCursor(input, Qt::OpenHandCursor); + effects->defineCursor(Qt::OpenHandCursor); if (closeOnMouseRelease) setActive(false); } @@ -1996,10 +1995,8 @@ void CubeEffect::slotMouseChanged(const QPoint& pos, const QPoint& oldpos, Qt::M } } -void CubeEffect::windowInputMouseEvent(Window w, QEvent* e) +void CubeEffect::windowInputMouseEvent(QEvent* e) { - assert(w == input); - Q_UNUSED(w); QMouseEvent *mouse = dynamic_cast< QMouseEvent* >(e); if (mouse && mouse->type() == QEvent::MouseButtonRelease) { if (mouse->button() == Qt::XButton1) { diff --git a/effects/cube/cube.h b/effects/cube/cube.h index d35da677a8..c707a18a7a 100644 --- a/effects/cube/cube.h +++ b/effects/cube/cube.h @@ -66,7 +66,7 @@ public: virtual void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data); virtual bool borderActivated(ElectricBorder border); virtual void grabbedKeyboardEvent(QKeyEvent* e); - virtual void windowInputMouseEvent(Window w, QEvent* e); + virtual void windowInputMouseEvent(QEvent* e); virtual bool isActive() const; // proxy functions @@ -179,7 +179,6 @@ private: QList borderActivateCylinder; QList borderActivateSphere; int painting_desktop; - Window input; int frontDesktop; float cubeOpacity; bool opacityDesktopOnly; diff --git a/effects/desktopgrid/desktopgrid.cpp b/effects/desktopgrid/desktopgrid.cpp index 95fe1394ee..dc3d82b187 100644 --- a/effects/desktopgrid/desktopgrid.cpp +++ b/effects/desktopgrid/desktopgrid.cpp @@ -462,7 +462,7 @@ void DesktopGridEffect::slotWindowGeometryShapeChanged(EffectWindow* w, const QR } } -void DesktopGridEffect::windowInputMouseEvent(Window, QEvent* e) +void DesktopGridEffect::windowInputMouseEvent(QEvent* e) { if ((e->type() != QEvent::MouseMove && e->type() != QEvent::MouseButtonPress @@ -521,7 +521,7 @@ void DesktopGridEffect::windowInputMouseEvent(Window, QEvent* e) } m_proxy->calculateWindowTransformations(manager.managedWindows(), windowMove->screen(), manager); } - effects->defineCursor(input, Qt::ClosedHandCursor); + effects->defineCursor(Qt::ClosedHandCursor); } wasWindowMove = true; if (windowMove->isMovable() && !isUsingPresentWindows()) { @@ -539,7 +539,7 @@ void DesktopGridEffect::windowInputMouseEvent(Window, QEvent* e) } else if ((me->buttons() & Qt::LeftButton) && !wasDesktopMove && (me->pos() - dragStartPos).manhattanLength() > KGlobalSettings::dndEventDelay()) { wasDesktopMove = true; - effects->defineCursor(input, Qt::ClosedHandCursor); + effects->defineCursor(Qt::ClosedHandCursor); } if (d != highlightedDesktop) { // Highlight desktop if ((me->buttons() & Qt::LeftButton) && isValidMove && !wasWindowMove && d <= effects->numberOfDesktops()) { @@ -673,9 +673,9 @@ void DesktopGridEffect::windowInputMouseEvent(Window, QEvent* e) } effects->setElevatedWindow(windowMove, false); windowMove = NULL; - effects->defineCursor(input, Qt::PointingHandCursor); + effects->defineCursor(Qt::PointingHandCursor); } else if (wasDesktopMove) - effects->defineCursor(input, Qt::PointingHandCursor); + effects->defineCursor(Qt::PointingHandCursor); wasWindowMove = false; wasDesktopMove = false; } @@ -1061,8 +1061,7 @@ void DesktopGridEffect::setActive(bool active) void DesktopGridEffect::setup() { keyboardGrab = effects->grabKeyboard(this); - input = effects->createInputWindow(this, 0, 0, displayWidth(), displayHeight(), - Qt::PointingHandCursor); + effects->startMouseInterception(this, Qt::PointingHandCursor); effects->setActiveFullScreenEffect(this); setHighlightedDesktop(effects->currentDesktop()); @@ -1193,7 +1192,7 @@ void DesktopGridEffect::finish() if (keyboardGrab) effects->ungrabKeyboard(); keyboardGrab = false; - effects->destroyInputWindow(input); + effects->stopMouseInterception(this); effects->setActiveFullScreenEffect(0); if (isUsingPresentWindows()) { while (!m_managers.isEmpty()) { diff --git a/effects/desktopgrid/desktopgrid.h b/effects/desktopgrid/desktopgrid.h index b78404f8bc..226591a276 100644 --- a/effects/desktopgrid/desktopgrid.h +++ b/effects/desktopgrid/desktopgrid.h @@ -66,7 +66,7 @@ public: virtual void postPaintScreen(); virtual void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time); virtual void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data); - virtual void windowInputMouseEvent(Window w, QEvent* e); + virtual void windowInputMouseEvent(QEvent* e); virtual void grabbedKeyboardEvent(QKeyEvent* e); virtual bool borderActivated(ElectricBorder border); virtual bool isActive() const; @@ -139,7 +139,6 @@ private: int paintingDesktop; int highlightedDesktop; int m_originalMovingDesktop; - Window input; bool keyboardGrab; bool wasWindowMove, wasDesktopMove, isValidMove; EffectWindow* windowMove; diff --git a/effects/flipswitch/flipswitch.cpp b/effects/flipswitch/flipswitch.cpp index 6291e12b43..97e0455beb 100644 --- a/effects/flipswitch/flipswitch.cpp +++ b/effects/flipswitch/flipswitch.cpp @@ -614,16 +614,16 @@ void FlipSwitchEffect::setActive(bool activate, FlipSwitchMode mode) switch(m_mode) { case TabboxMode: m_selectedWindow = effects->currentTabBoxWindow(); - m_input = effects->createFullScreenInputWindow(this, Qt::ArrowCursor); + effects->startMouseInterception(this, Qt::ArrowCursor); break; case CurrentDesktopMode: m_selectedWindow = effects->activeWindow(); - m_input = effects->createFullScreenInputWindow(this, Qt::BlankCursor); + effects->startMouseInterception(this, Qt::BlankCursor); m_hasKeyboardGrab = effects->grabKeyboard(this); break; case AllDesktopsMode: m_selectedWindow = effects->activeWindow(); - m_input = effects->createFullScreenInputWindow(this, Qt::BlankCursor); + effects->startMouseInterception(this, Qt::BlankCursor); m_hasKeyboardGrab = effects->grabKeyboard(this); break; } @@ -661,7 +661,7 @@ void FlipSwitchEffect::setActive(bool activate, FlipSwitchMode mode) } } else m_startStopTimeLine.setCurveShape(QTimeLine::EaseInOutCurve); - effects->destroyInputWindow(m_input); + effects->stopMouseInterception(this); if (m_hasKeyboardGrab) { effects->ungrabKeyboard(); m_hasKeyboardGrab = false; @@ -962,10 +962,8 @@ void FlipSwitchEffect::updateCaption() // Mouse handling //************************************************************* -void FlipSwitchEffect::windowInputMouseEvent(Window w, QEvent* e) +void FlipSwitchEffect::windowInputMouseEvent(QEvent* e) { - assert(w == m_input); - Q_UNUSED(w); if (e->type() != QEvent::MouseButtonPress) return; // we don't want click events during animations diff --git a/effects/flipswitch/flipswitch.h b/effects/flipswitch/flipswitch.h index 35b67dc45e..c238a93b14 100644 --- a/effects/flipswitch/flipswitch.h +++ b/effects/flipswitch/flipswitch.h @@ -53,7 +53,7 @@ public: virtual void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time); virtual void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data); virtual void grabbedKeyboardEvent(QKeyEvent* e); - virtual void windowInputMouseEvent(Window w, QEvent* e); + virtual void windowInputMouseEvent(QEvent* e); virtual bool isActive() const; static bool supported(); @@ -128,7 +128,6 @@ private: bool m_stop; bool m_animation; bool m_hasKeyboardGrab; - Window m_input; FlipSwitchMode m_mode; EffectFrame* m_captionFrame; QFont m_captionFont; diff --git a/effects/presentwindows/presentwindows.cpp b/effects/presentwindows/presentwindows.cpp index 61a94478c7..116e7eb5e0 100755 --- a/effects/presentwindows/presentwindows.cpp +++ b/effects/presentwindows/presentwindows.cpp @@ -514,11 +514,8 @@ bool PresentWindowsEffect::borderActivated(ElectricBorder border) return true; } -void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e) +void PresentWindowsEffect::windowInputMouseEvent(QEvent *e) { - assert(w == m_input); - Q_UNUSED(w); - QMouseEvent* me = static_cast< QMouseEvent* >(e); if (m_closeView && m_closeView->geometry().contains(me->pos())) { if (!m_closeView->isVisible()) { @@ -574,7 +571,7 @@ void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e) m_highlightedDropTarget = NULL; } effects->addRepaintFull(); - effects->defineCursor(m_input, Qt::PointingHandCursor); + effects->defineCursor(Qt::PointingHandCursor); return; } if (hovering) { @@ -613,7 +610,7 @@ void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e) m_highlightedDropTarget->setIcon(icon.pixmap(QSize(128, 128), QIcon::Normal)); m_highlightedDropTarget = NULL; } - effects->defineCursor(m_input, Qt::PointingHandCursor); + effects->defineCursor(Qt::PointingHandCursor); } else if (e->type() == QEvent::MouseButtonPress && me->button() == Qt::LeftButton && hovering && m_dragToClose) { m_dragStart = me->pos(); m_dragWindow = m_highlightedWindow; @@ -625,7 +622,7 @@ void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e) if (e->type() == QEvent::MouseMove && m_dragWindow) { if ((me->pos() - m_dragStart).manhattanLength() > KGlobalSettings::dndEventDelay() && !m_dragInProgress) { m_dragInProgress = true; - effects->defineCursor(m_input, Qt::ForbiddenCursor); + effects->defineCursor(Qt::ForbiddenCursor); } if (!m_dragInProgress) { return; @@ -643,13 +640,13 @@ void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e) KIcon icon("user-trash"); effects->addRepaint(m_highlightedDropTarget->geometry()); m_highlightedDropTarget->setIcon(icon.pixmap(QSize(128, 128), QIcon::Active)); - effects->defineCursor(m_input, Qt::DragMoveCursor); + effects->defineCursor(Qt::DragMoveCursor); } else if (!target && m_highlightedDropTarget) { KIcon icon("user-trash"); effects->addRepaint(m_highlightedDropTarget->geometry()); m_highlightedDropTarget->setIcon(icon.pixmap(QSize(128, 128), QIcon::Normal)); m_highlightedDropTarget = NULL; - effects->defineCursor(m_input, Qt::ForbiddenCursor); + effects->defineCursor(Qt::ForbiddenCursor); } } } @@ -1533,7 +1530,7 @@ void PresentWindowsEffect::setActive(bool active) } // Create temporary input window to catch mouse events - m_input = effects->createFullScreenInputWindow(this, Qt::PointingHandCursor); + effects->startMouseInterception(this, Qt::PointingHandCursor); m_hasKeyboardGrab = effects->grabKeyboard(this); effects->setActiveFullScreenEffect(this); @@ -1576,7 +1573,7 @@ void PresentWindowsEffect::setActive(bool active) m_windowFilter.clear(); m_selectedWindows.clear(); - effects->destroyInputWindow(m_input); + effects->stopMouseInterception(this); if (m_hasKeyboardGrab) effects->ungrabKeyboard(); m_hasKeyboardGrab = false; diff --git a/effects/presentwindows/presentwindows.h b/effects/presentwindows/presentwindows.h index ed2807eb9c..89ccca796a 100644 --- a/effects/presentwindows/presentwindows.h +++ b/effects/presentwindows/presentwindows.h @@ -109,7 +109,7 @@ public: // User interaction virtual bool borderActivated(ElectricBorder border); - virtual void windowInputMouseEvent(Window w, QEvent *e); + virtual void windowInputMouseEvent(QEvent *e); virtual void grabbedKeyboardEvent(QKeyEvent *e); virtual bool isActive() const; @@ -275,7 +275,6 @@ private: bool m_activated; bool m_ignoreMinimized; double m_decalOpacity; - Window m_input; bool m_hasKeyboardGrab; PresentWindowsMode m_mode; int m_desktop; diff --git a/libkwineffects/kwineffects.cpp b/libkwineffects/kwineffects.cpp index 0cc83c3abe..8f165b0344 100644 --- a/libkwineffects/kwineffects.cpp +++ b/libkwineffects/kwineffects.cpp @@ -469,7 +469,7 @@ void* Effect::proxy() return NULL; } -void Effect::windowInputMouseEvent(Window, QEvent*) +void Effect::windowInputMouseEvent(QEvent*) { } @@ -603,16 +603,6 @@ EffectsHandler::~EffectsHandler() assert(loaded_effects.count() == 0); } -xcb_window_t EffectsHandler::createInputWindow(Effect* e, const QRect& r, const QCursor& cursor) -{ - return createInputWindow(e, r.x(), r.y(), r.width(), r.height(), cursor); -} - -xcb_window_t EffectsHandler::createFullScreenInputWindow(Effect* e, const QCursor& cursor) -{ - return createInputWindow(e, 0, 0, displayWidth(), displayHeight(), cursor); -} - CompositingType EffectsHandler::compositingType() const { return compositing_type; diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h index a08a99b2ea..5daba46fe7 100644 --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -170,7 +170,7 @@ X-KDE-Library=kwin4_effect_cooleffect #define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor )) #define KWIN_EFFECT_API_VERSION_MAJOR 0 -#define KWIN_EFFECT_API_VERSION_MINOR 222 +#define KWIN_EFFECT_API_VERSION_MINOR 223 #define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \ KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR ) @@ -434,7 +434,7 @@ public: **/ virtual void buildQuads(EffectWindow* w, WindowQuadList& quadList); - virtual void windowInputMouseEvent(Window w, QEvent* e); + virtual void windowInputMouseEvent(QEvent* e); virtual void grabbedKeyboardEvent(QKeyEvent* e); /** @@ -644,17 +644,35 @@ public: virtual void drawWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) = 0; virtual void buildQuads(EffectWindow* w, WindowQuadList& quadList) = 0; virtual QVariant kwinOption(KWinOption kwopt) = 0; - // Functions for handling input - e.g. when an Expose-like effect is shown, an input window - // covering the whole screen is created and all mouse events will be intercepted by it. - // The effect's windowInputMouseEvent() will get called with such events. - virtual xcb_window_t createInputWindow(Effect* e, int x, int y, int w, int h, const QCursor& cursor) = 0; - xcb_window_t createInputWindow(Effect* e, const QRect& r, const QCursor& cursor); - virtual xcb_window_t createFullScreenInputWindow(Effect* e, const QCursor& cursor); - virtual void destroyInputWindow(xcb_window_t w) = 0; - virtual void defineCursor(xcb_window_t w, Qt::CursorShape shape) = 0; + /** + * Sets the cursor while the mouse is intercepted. + * @see startMouseInterception + * @since 4.11 + **/ + virtual void defineCursor(Qt::CursorShape shape) = 0; virtual QPoint cursorPos() const = 0; virtual bool grabKeyboard(Effect* effect) = 0; virtual void ungrabKeyboard() = 0; + /** + * Ensures that all mouse events are sent to the @p effect. + * No window will get the mouse events. Only fullscreen effects providing a custom user interface should + * be using this method. The input events are delivered to Effect::windowInputMouseEvent. + * + * NOTE: this method does not perform an X11 mouse grab. On X11 a fullscreen input window is raised above + * all other windows, but no grab is performed. + * + * @param shape Sets the cursor to be used while the mouse is intercepted + * @see stopMouseInterception + * @see Effect::windowInputMouseEvent + * @since 4.11 + **/ + virtual void startMouseInterception(Effect *effect, Qt::CursorShape shape) = 0; + /** + * Releases the hold mouse interception for @p effect + * @see startMouseInterception + * @since 4.11 + **/ + virtual void stopMouseInterception(Effect *effect) = 0; /** * Retrieve the proxy class for an effect if it has one. Will return NULL if diff --git a/xcbutils.h b/xcbutils.h index 51b8f5d421..762e0ed08e 100644 --- a/xcbutils.h +++ b/xcbutils.h @@ -348,6 +348,7 @@ public: void move(uint32_t x, uint32_t y); void resize(const QSize &size); void resize(uint32_t width, uint32_t height); + void raise(); void map(); void unmap(); /** @@ -492,6 +493,13 @@ void Window::resize(uint32_t width, uint32_t height) xcb_configure_window(connection(), m_window, mask, values); } +inline +void Window::raise() +{ + const uint32_t values[] = { XCB_STACK_MODE_ABOVE }; + xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_STACK_MODE, values); +} + inline void Window::map() {