Support for "input windows" that let effects intercept mouse events
when they e.g. want to let the user select from window thumbnails. svn path=/branches/work/kwin_composite/; revision=620305
This commit is contained in:
parent
2e84c74fc8
commit
1765551277
8 changed files with 233 additions and 1 deletions
|
@ -60,6 +60,7 @@ set(kwin_KDEINIT_SRCS
|
||||||
effects/dialogparent.cpp
|
effects/dialogparent.cpp
|
||||||
effects/showfps.cpp
|
effects/showfps.cpp
|
||||||
effects/zoom.cpp
|
effects/zoom.cpp
|
||||||
|
effects/test_input.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml workspace.h KWinInternal::Workspace )
|
qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml workspace.h KWinInternal::Workspace )
|
||||||
|
|
|
@ -117,7 +117,7 @@ void Workspace::setupCompositing()
|
||||||
kDebug( 1212 ) << "XRender compositing" << endl;
|
kDebug( 1212 ) << "XRender compositing" << endl;
|
||||||
else if( dynamic_cast< SceneBasic* >( scene ))
|
else if( dynamic_cast< SceneBasic* >( scene ))
|
||||||
kDebug( 1212 ) << "X compositing" << endl;
|
kDebug( 1212 ) << "X compositing" << endl;
|
||||||
effects = new EffectsHandler( this );
|
new EffectsHandler( this ); // sets also the 'effects' pointer
|
||||||
addDamageFull();
|
addDamageFull();
|
||||||
foreach( Client* c, clients )
|
foreach( Client* c, clients )
|
||||||
c->setupCompositing();
|
c->setupCompositing();
|
||||||
|
|
98
effects.cpp
98
effects.cpp
|
@ -24,6 +24,8 @@ License. See the file "COPYING" for the exact licensing terms.
|
||||||
#include "effects/showfps.h"
|
#include "effects/showfps.h"
|
||||||
#include "effects/zoom.h"
|
#include "effects/zoom.h"
|
||||||
|
|
||||||
|
#include "effects/test_input.h"
|
||||||
|
|
||||||
namespace KWinInternal
|
namespace KWinInternal
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -51,6 +53,10 @@ void Effect::windowActivated( Toplevel* )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Effect::windowInputMouseEvent( Window, QEvent* )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void Effect::prePaintScreen( int* mask, QRegion* region, int time )
|
void Effect::prePaintScreen( int* mask, QRegion* region, int time )
|
||||||
{
|
{
|
||||||
effects->prePaintScreen( mask, region, time );
|
effects->prePaintScreen( mask, region, time );
|
||||||
|
@ -91,6 +97,7 @@ EffectsHandler::EffectsHandler( Workspace* ws )
|
||||||
{
|
{
|
||||||
if( !compositing())
|
if( !compositing())
|
||||||
return;
|
return;
|
||||||
|
KWinInternal::effects = this;
|
||||||
effects.append( new ShowFpsEffect( ws ));
|
effects.append( new ShowFpsEffect( ws ));
|
||||||
// effects.append( new ZoomEffect( ws ));
|
// effects.append( new ZoomEffect( ws ));
|
||||||
// effects.append( new HowtoEffect );
|
// effects.append( new HowtoEffect );
|
||||||
|
@ -100,12 +107,16 @@ EffectsHandler::EffectsHandler( Workspace* ws )
|
||||||
// effects.append( new FadeInEffect );
|
// effects.append( new FadeInEffect );
|
||||||
// effects.append( new ScaleInEffect );
|
// effects.append( new ScaleInEffect );
|
||||||
// effects.append( new DialogParentEffect );
|
// effects.append( new DialogParentEffect );
|
||||||
|
|
||||||
|
// effects.append( new TestInputEffect );
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectsHandler::~EffectsHandler()
|
EffectsHandler::~EffectsHandler()
|
||||||
{
|
{
|
||||||
foreach( Effect* e, effects )
|
foreach( Effect* e, effects )
|
||||||
delete e;
|
delete e;
|
||||||
|
foreach( InputWindowPair pos, input_windows )
|
||||||
|
XDestroyWindow( display(), pos.second );
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectsHandler::windowUserMovedResized( Toplevel* c, bool first, bool last )
|
void EffectsHandler::windowUserMovedResized( Toplevel* c, bool first, bool last )
|
||||||
|
@ -202,6 +213,93 @@ void EffectsHandler::postPaintWindow( Scene::Window* w )
|
||||||
// no special final code
|
// no special final code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Window EffectsHandler::createInputWindow( Effect* e, int x, int y, int w, int h, const QCursor& cursor )
|
||||||
|
{
|
||||||
|
XSetWindowAttributes attrs;
|
||||||
|
attrs.override_redirect = True;
|
||||||
|
Window win = XCreateWindow( display(), rootWindow(), x, y, w, h, 0, 0, InputOnly, CopyFromParent,
|
||||||
|
CWOverrideRedirect, &attrs );
|
||||||
|
// TODO keeping on top?
|
||||||
|
// TODO enter/leave notify?
|
||||||
|
XSelectInput( display(), win, ButtonPressMask | ButtonReleaseMask | PointerMotionMask );
|
||||||
|
XDefineCursor( display(), win, cursor.handle());
|
||||||
|
XMapWindow( display(), win );
|
||||||
|
input_windows.append( qMakePair( e, win ));
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window EffectsHandler::createInputWindow( Effect* e, const QRect& r, const QCursor& cursor )
|
||||||
|
{
|
||||||
|
return createInputWindow( e, r.x(), r.y(), r.width(), r.height(), cursor );
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectsHandler::destroyInputWindow( Window w )
|
||||||
|
{
|
||||||
|
foreach( InputWindowPair pos, input_windows )
|
||||||
|
{
|
||||||
|
if( pos.second == w )
|
||||||
|
{
|
||||||
|
input_windows.removeAll( pos );
|
||||||
|
XDestroyWindow( display(), w );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EffectsHandler::checkInputWindowEvent( XEvent* e )
|
||||||
|
{
|
||||||
|
if( e->type != ButtonPress && e->type != ButtonRelease && e->type != MotionNotify )
|
||||||
|
return false;
|
||||||
|
foreach( InputWindowPair pos, input_windows )
|
||||||
|
{
|
||||||
|
if( pos.second == e->xany.window )
|
||||||
|
{
|
||||||
|
switch( e->type )
|
||||||
|
{
|
||||||
|
case ButtonPress:
|
||||||
|
case ButtonRelease:
|
||||||
|
{
|
||||||
|
XButtonEvent* e2 = &e->xbutton;
|
||||||
|
QMouseEvent ev( e->type == ButtonPress ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease,
|
||||||
|
QPoint( e2->x, e2->y ), QPoint( e2->x_root, e2->y_root ), x11ToQtMouseButton( e2->button ),
|
||||||
|
x11ToQtMouseButtons( e2->state ), 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectsHandler::checkInputWindowStacking()
|
||||||
|
{
|
||||||
|
if( input_windows.count() == 0 )
|
||||||
|
return;
|
||||||
|
Window* wins = new Window[ input_windows.count() ];
|
||||||
|
int pos = 0;
|
||||||
|
foreach( InputWindowPair it, input_windows )
|
||||||
|
wins[ pos++ ] = it.second;
|
||||||
|
XRaiseWindow( display(), wins[ 0 ] );
|
||||||
|
XRestackWindows( display(), wins, pos );
|
||||||
|
delete[] wins;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectsHandler::activateWindow( Client* c )
|
||||||
|
{
|
||||||
|
Workspace::self()->activateClient( c, true );
|
||||||
|
}
|
||||||
|
|
||||||
EffectsHandler* effects;
|
EffectsHandler* effects;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
15
effects.h
15
effects.h
|
@ -15,6 +15,8 @@ License. See the file "COPYING" for the exact licensing terms.
|
||||||
|
|
||||||
#include "scene.h"
|
#include "scene.h"
|
||||||
|
|
||||||
|
#include <qpair.h>
|
||||||
|
|
||||||
namespace KWinInternal
|
namespace KWinInternal
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -73,6 +75,7 @@ class Effect
|
||||||
virtual void windowAdded( Toplevel* c );
|
virtual void windowAdded( Toplevel* c );
|
||||||
virtual void windowDeleted( Toplevel* c );
|
virtual void windowDeleted( Toplevel* c );
|
||||||
virtual void windowActivated( Toplevel* c );
|
virtual void windowActivated( Toplevel* c );
|
||||||
|
virtual void windowInputMouseEvent( Window w, QEvent* e );
|
||||||
};
|
};
|
||||||
|
|
||||||
class EffectsHandler
|
class EffectsHandler
|
||||||
|
@ -87,14 +90,26 @@ class EffectsHandler
|
||||||
void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time );
|
void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time );
|
||||||
void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data );
|
void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data );
|
||||||
void postPaintWindow( Scene::Window* w );
|
void postPaintWindow( Scene::Window* w );
|
||||||
|
// 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.
|
||||||
|
Window createInputWindow( Effect* e, int x, int y, int w, int h, const QCursor& cursor );
|
||||||
|
Window createInputWindow( Effect* e, const QRect& r, const QCursor& cursor );
|
||||||
|
void destroyInputWindow( Window w );
|
||||||
|
// functions that allow controlling windows/desktop
|
||||||
|
void activateWindow( Client* c );
|
||||||
// internal (used by kwin core or compositing code)
|
// internal (used by kwin core or compositing code)
|
||||||
void startPaint();
|
void startPaint();
|
||||||
void windowUserMovedResized( Toplevel* c, bool first, bool last );
|
void windowUserMovedResized( Toplevel* c, bool first, bool last );
|
||||||
void windowAdded( Toplevel* c );
|
void windowAdded( Toplevel* c );
|
||||||
void windowDeleted( Toplevel* c );
|
void windowDeleted( Toplevel* c );
|
||||||
void windowActivated( Toplevel* c );
|
void windowActivated( Toplevel* c );
|
||||||
|
bool checkInputWindowEvent( XEvent* e );
|
||||||
|
void checkInputWindowStacking();
|
||||||
private:
|
private:
|
||||||
QVector< Effect* > effects;
|
QVector< Effect* > effects;
|
||||||
|
typedef QPair< Effect*, Window > InputWindowPair;
|
||||||
|
QList< InputWindowPair > input_windows;
|
||||||
int current_paint_window;
|
int current_paint_window;
|
||||||
int current_paint_screen;
|
int current_paint_screen;
|
||||||
};
|
};
|
||||||
|
|
70
effects/test_input.cpp
Normal file
70
effects/test_input.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*****************************************************************
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
|
||||||
|
|
||||||
|
You can Freely distribute this program under the GNU General Public
|
||||||
|
License. See the file "COPYING" for the exact licensing terms.
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Testing of handling input in effects. This testing effect moves all windows
|
||||||
|
by 100 pixels down, creates an input window that'll intercept all mouse events
|
||||||
|
and activates the window that's been clicked (click position needs to be
|
||||||
|
transformed). This is useful for effects that present something on the screen
|
||||||
|
and let the user interact with it (e.g. a list of window thumbnails and the
|
||||||
|
user can activate the window by clicking its thumbnail).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test_input.h"
|
||||||
|
|
||||||
|
#include <workspace.h>
|
||||||
|
#include <client.h>
|
||||||
|
|
||||||
|
namespace KWinInternal
|
||||||
|
{
|
||||||
|
|
||||||
|
TestInputEffect::TestInputEffect()
|
||||||
|
{
|
||||||
|
input = effects->createInputWindow( this, 0, 0, displayWidth(), displayHeight(), Qt::CrossCursor );
|
||||||
|
}
|
||||||
|
|
||||||
|
TestInputEffect::~TestInputEffect()
|
||||||
|
{
|
||||||
|
effects->destroyInputWindow( input );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestInputEffect::prePaintScreen( int* mask, QRegion* region, int time )
|
||||||
|
{
|
||||||
|
*mask |= Scene::PAINT_SCREEN_TRANSFORMED;
|
||||||
|
effects->prePaintScreen( mask, region, time );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestInputEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
|
||||||
|
{
|
||||||
|
data.yTranslate += 100;
|
||||||
|
effects->paintScreen( mask, region, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestInputEffect::windowInputMouseEvent( Window w, QEvent* e )
|
||||||
|
{
|
||||||
|
assert( w == input );
|
||||||
|
if( e->type() != QEvent::MouseButtonPress )
|
||||||
|
return;
|
||||||
|
QPoint pos = static_cast< QMouseEvent* >( e )->pos();
|
||||||
|
pos -= QPoint( 0, 100 ); // adjust for transformation
|
||||||
|
foreach( Client* c, Workspace::self()->stackingOrder())
|
||||||
|
{
|
||||||
|
if( c->isShown( true ) && c->isOnCurrentDesktop()
|
||||||
|
&& c->geometry().contains( pos ))
|
||||||
|
{
|
||||||
|
effects->activateWindow( c );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
40
effects/test_input.h
Normal file
40
effects/test_input.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*****************************************************************
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
|
||||||
|
|
||||||
|
You can Freely distribute this program under the GNU General Public
|
||||||
|
License. See the file "COPYING" for the exact licensing terms.
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Testing of handling input in effects.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KWIN_TEST_INPUT_H
|
||||||
|
#define KWIN_TEST_INPUT_H
|
||||||
|
|
||||||
|
#include <effects.h>
|
||||||
|
|
||||||
|
namespace KWinInternal
|
||||||
|
{
|
||||||
|
|
||||||
|
class TestInputEffect
|
||||||
|
: public Effect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestInputEffect();
|
||||||
|
virtual ~TestInputEffect();
|
||||||
|
virtual void prePaintScreen( int* mask, QRegion* region, int time );
|
||||||
|
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
|
||||||
|
virtual void windowInputMouseEvent( Window w, QEvent* e );
|
||||||
|
private:
|
||||||
|
Window input;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,6 +23,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
||||||
#include "rules.h"
|
#include "rules.h"
|
||||||
#include "unmanaged.h"
|
#include "unmanaged.h"
|
||||||
#include "scene.h"
|
#include "scene.h"
|
||||||
|
#include "effects.h"
|
||||||
|
|
||||||
#include <QWhatsThis>
|
#include <QWhatsThis>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
@ -220,6 +221,8 @@ bool Workspace::workspaceEvent( XEvent * e )
|
||||||
tab_box->handleMouseEvent( e );
|
tab_box->handleMouseEvent( e );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if( effects && effects->checkInputWindowEvent( e ))
|
||||||
|
return true;
|
||||||
break;
|
break;
|
||||||
case KeyPress:
|
case KeyPress:
|
||||||
{
|
{
|
||||||
|
@ -1634,6 +1637,8 @@ void Unmanaged::unmapNotifyEvent( XUnmapEvent* )
|
||||||
|
|
||||||
void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
|
void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
|
||||||
{
|
{
|
||||||
|
if( effects )
|
||||||
|
effects->checkInputWindowStacking(); // keep them on top
|
||||||
QRect newgeom( e->x, e->y, e->width, e->height );
|
QRect newgeom( e->x, e->y, e->width, e->height );
|
||||||
if( newgeom == geom )
|
if( newgeom == geom )
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -11,6 +11,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
||||||
#include "unmanaged.h"
|
#include "unmanaged.h"
|
||||||
|
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
|
#include "effects.h"
|
||||||
|
|
||||||
#include <X11/extensions/shape.h>
|
#include <X11/extensions/shape.h>
|
||||||
|
|
||||||
|
@ -62,6 +63,8 @@ bool Unmanaged::track( Window w )
|
||||||
detectShape( w );
|
detectShape( w );
|
||||||
setupCompositing();
|
setupCompositing();
|
||||||
ungrabXServer();
|
ungrabXServer();
|
||||||
|
if( effects )
|
||||||
|
effects->checkInputWindowStacking();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue