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/showfps.cpp
|
||||
effects/zoom.cpp
|
||||
effects/test_input.cpp
|
||||
)
|
||||
|
||||
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;
|
||||
else if( dynamic_cast< SceneBasic* >( scene ))
|
||||
kDebug( 1212 ) << "X compositing" << endl;
|
||||
effects = new EffectsHandler( this );
|
||||
new EffectsHandler( this ); // sets also the 'effects' pointer
|
||||
addDamageFull();
|
||||
foreach( Client* c, clients )
|
||||
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/zoom.h"
|
||||
|
||||
#include "effects/test_input.h"
|
||||
|
||||
namespace KWinInternal
|
||||
{
|
||||
|
||||
|
@ -51,6 +53,10 @@ void Effect::windowActivated( Toplevel* )
|
|||
{
|
||||
}
|
||||
|
||||
void Effect::windowInputMouseEvent( Window, QEvent* )
|
||||
{
|
||||
}
|
||||
|
||||
void Effect::prePaintScreen( int* mask, QRegion* region, int time )
|
||||
{
|
||||
effects->prePaintScreen( mask, region, time );
|
||||
|
@ -91,6 +97,7 @@ EffectsHandler::EffectsHandler( Workspace* ws )
|
|||
{
|
||||
if( !compositing())
|
||||
return;
|
||||
KWinInternal::effects = this;
|
||||
effects.append( new ShowFpsEffect( ws ));
|
||||
// effects.append( new ZoomEffect( ws ));
|
||||
// effects.append( new HowtoEffect );
|
||||
|
@ -100,12 +107,16 @@ EffectsHandler::EffectsHandler( Workspace* ws )
|
|||
// effects.append( new FadeInEffect );
|
||||
// effects.append( new ScaleInEffect );
|
||||
// effects.append( new DialogParentEffect );
|
||||
|
||||
// effects.append( new TestInputEffect );
|
||||
}
|
||||
|
||||
EffectsHandler::~EffectsHandler()
|
||||
{
|
||||
foreach( Effect* e, effects )
|
||||
delete e;
|
||||
foreach( InputWindowPair pos, input_windows )
|
||||
XDestroyWindow( display(), pos.second );
|
||||
}
|
||||
|
||||
void EffectsHandler::windowUserMovedResized( Toplevel* c, bool first, bool last )
|
||||
|
@ -202,6 +213,93 @@ void EffectsHandler::postPaintWindow( Scene::Window* w )
|
|||
// 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;
|
||||
|
||||
} // 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 <qpair.h>
|
||||
|
||||
namespace KWinInternal
|
||||
{
|
||||
|
||||
|
@ -73,6 +75,7 @@ class Effect
|
|||
virtual void windowAdded( Toplevel* c );
|
||||
virtual void windowDeleted( Toplevel* c );
|
||||
virtual void windowActivated( Toplevel* c );
|
||||
virtual void windowInputMouseEvent( Window w, QEvent* e );
|
||||
};
|
||||
|
||||
class EffectsHandler
|
||||
|
@ -87,14 +90,26 @@ class EffectsHandler
|
|||
void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time );
|
||||
void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data );
|
||||
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)
|
||||
void startPaint();
|
||||
void windowUserMovedResized( Toplevel* c, bool first, bool last );
|
||||
void windowAdded( Toplevel* c );
|
||||
void windowDeleted( Toplevel* c );
|
||||
void windowActivated( Toplevel* c );
|
||||
bool checkInputWindowEvent( XEvent* e );
|
||||
void checkInputWindowStacking();
|
||||
private:
|
||||
QVector< Effect* > effects;
|
||||
typedef QPair< Effect*, Window > InputWindowPair;
|
||||
QList< InputWindowPair > input_windows;
|
||||
int current_paint_window;
|
||||
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 "unmanaged.h"
|
||||
#include "scene.h"
|
||||
#include "effects.h"
|
||||
|
||||
#include <QWhatsThis>
|
||||
#include <QApplication>
|
||||
|
@ -220,6 +221,8 @@ bool Workspace::workspaceEvent( XEvent * e )
|
|||
tab_box->handleMouseEvent( e );
|
||||
return true;
|
||||
}
|
||||
if( effects && effects->checkInputWindowEvent( e ))
|
||||
return true;
|
||||
break;
|
||||
case KeyPress:
|
||||
{
|
||||
|
@ -1634,6 +1637,8 @@ void Unmanaged::unmapNotifyEvent( XUnmapEvent* )
|
|||
|
||||
void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
|
||||
{
|
||||
if( effects )
|
||||
effects->checkInputWindowStacking(); // keep them on top
|
||||
QRect newgeom( e->x, e->y, e->width, e->height );
|
||||
if( newgeom == geom )
|
||||
return;
|
||||
|
|
|
@ -11,6 +11,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include "unmanaged.h"
|
||||
|
||||
#include "workspace.h"
|
||||
#include "effects.h"
|
||||
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
|
@ -62,6 +63,8 @@ bool Unmanaged::track( Window w )
|
|||
detectShape( w );
|
||||
setupCompositing();
|
||||
ungrabXServer();
|
||||
if( effects )
|
||||
effects->checkInputWindowStacking();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue