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
This commit is contained in:
Martin Gräßlin 2013-04-24 16:51:04 +02:00
parent 0811d17329
commit 49e734f743
15 changed files with 166 additions and 213 deletions

View file

@ -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<InputWindowPair>::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<Xcb::WindowAttributes> attributes(input_windows.count());
int pos = 0;
foreach (const InputWindowPair &it, input_windows) {
attributes[pos] = Xcb::WindowAttributes(it.second);
pos++;
}
pos = 0;
for (QVector<Xcb::WindowAttributes>::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; i<pos; ++i) {
const uint16_t mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE;
const uint32_t stackingValues[] = {
wins[i-1],
XCB_STACK_MODE_BELOW
};
xcb_configure_window(connection(), wins[i], mask, stackingValues);
}
}
delete[] wins;
m_mouseInterceptionWindow.raise();
// Raise electric border windows above the input windows
// so they can still be triggered. TODO: Do both at once.
#ifdef KWIN_BUILD_SCREENEDGES
if (pos)
ScreenEdges::self()->ensureOnTop();
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<QByteArray> properties = m_propertiesForEffects.keys();
foreach (const QByteArray &property, properties) {

View file

@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "kwineffects.h"
#include "scene.h"
#include "xcbutils.h"
#include <QStack>
#include <QHash>
@ -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<QByteArray, qulonglong> 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<Effect*> m_grabbedMouseEffects;
};
class EffectWindowImpl : public EffectWindow

View file

@ -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;

View file

@ -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 {

View file

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

View file

@ -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<ElectricBorder> borderActivateCylinder;
QList<ElectricBorder> borderActivateSphere;
int painting_desktop;
Window input;
int frontDesktop;
float cubeOpacity;
bool opacityDesktopOnly;

View file

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

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

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