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() {