Move most (all?) internal methods from EffectsHandler to EffectsHandlerImpl.

The ugly side effect of this is that there are tons of static_casts in the code now... maybe it
  would be better to add effectImpl() convenience method and use that?

svn path=/branches/work/kwin_composite/; revision=652348
This commit is contained in:
Rivo Laks 2007-04-10 18:47:13 +00:00
parent f8004bf458
commit 02032f8587
15 changed files with 1072 additions and 1131 deletions

View file

@ -29,6 +29,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "atoms.h" #include "atoms.h"
#include "group.h" #include "group.h"
#include "rules.h" #include "rules.h"
#include "effects.h"
#include <QX11Info> #include <QX11Info>
namespace KWin namespace KWin
@ -221,8 +222,8 @@ void Workspace::setActiveClient( Client* c, allowed_t )
++set_active_client_recursion; ++set_active_client_recursion;
if( active_client != NULL ) if( active_client != NULL )
{ // note that this may call setActiveClient( NULL ), therefore the recursion counter { // note that this may call setActiveClient( NULL ), therefore the recursion counter
active_client->setActive( false ); active_client->setActive( false );
} }
active_client = c; active_client = c;
Q_ASSERT( c == NULL || c->isActive()); Q_ASSERT( c == NULL || c->isActive());
if( active_client != NULL ) if( active_client != NULL )
@ -245,6 +246,8 @@ void Workspace::setActiveClient( Client* c, allowed_t )
rootInfo->setActiveWindow( active_client? active_client->window() : 0 ); rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
updateColormap(); updateColormap();
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->windowActivated( active_client ? active_client->effectWindow() : NULL );
--set_active_client_recursion; --set_active_client_recursion;
} }
@ -263,7 +266,6 @@ void Workspace::activateClient( Client* c, bool force )
{ {
if( c == NULL ) if( c == NULL )
{ {
focusToNull();
setActiveClient( NULL, Allowed ); setActiveClient( NULL, Allowed );
return; return;
} }
@ -698,7 +700,7 @@ void Client::demandAttentionKNotify()
} }
// TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it // TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it
KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*, KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, Client, const Client*,
// ignore already existing splashes, toolbars, utilities, menus and topmenus, // ignore already existing splashes, toolbars, utilities, menus and topmenus,
// as the app may show those before the main window // as the app may show those before the main window
!cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu() !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()

View file

@ -28,6 +28,9 @@ License. See the file "COPYING" for the exact licensing terms.
#include "atoms.h" #include "atoms.h"
#include "notifications.h" #include "notifications.h"
#include "rules.h" #include "rules.h"
#include "scene.h"
#include "effects.h"
#include "deleted.h"
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
#include <QX11Info> #include <QX11Info>
@ -63,12 +66,10 @@ namespace KWin
is done in manage(). is done in manage().
*/ */
Client::Client( Workspace *ws ) Client::Client( Workspace *ws )
: QObject( NULL ), : Toplevel( ws ),
client( None ), client( None ),
wrapper( None ), wrapper( None ),
frame( None ),
decoration( NULL ), decoration( NULL ),
wspace( ws ),
bridge( new Bridge( this )), bridge( new Bridge( this )),
move_faked_activity( false ), move_faked_activity( false ),
move_resize_grab_window( None ), move_resize_grab_window( None ),
@ -82,7 +83,7 @@ Client::Client( Workspace *ws )
process_killer( NULL ), process_killer( NULL ),
user_time( CurrentTime ), // not known yet user_time( CurrentTime ), // not known yet
allowed_actions( 0 ), allowed_actions( 0 ),
postpone_geometry_updates( 0 ), block_geometry_updates( 0 ),
pending_geometry_update( false ), pending_geometry_update( false ),
shade_geometry_change( false ), shade_geometry_change( false ),
border_left( 0 ), border_left( 0 ),
@ -111,7 +112,6 @@ Client::Client( Workspace *ws )
deleting = false; deleting = false;
keep_above = false; keep_above = false;
keep_below = false; keep_below = false;
is_shape = false;
motif_noborder = false; motif_noborder = false;
motif_may_move = true; motif_may_move = true;
motif_may_resize = true; motif_may_resize = true;
@ -124,6 +124,7 @@ Client::Client( Workspace *ws )
modal = false; modal = false;
noborder = false; noborder = false;
user_noborder = false; user_noborder = false;
not_obscured = false;
urgency = false; urgency = false;
ignore_focus_stealing = false; ignore_focus_stealing = false;
demands_attention = false; demands_attention = false;
@ -142,7 +143,7 @@ Client::Client( Workspace *ws )
cmap = None; cmap = None;
frame_geometry = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0) geom = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
client_size = QSize( 100, 100 ); client_size = QSize( 100, 100 );
// SELI initialize xsizehints?? // SELI initialize xsizehints??
@ -155,11 +156,11 @@ Client::~Client()
{ {
assert(!moveResizeMode); assert(!moveResizeMode);
assert( client == None ); assert( client == None );
assert( frame == None && wrapper == None ); assert( wrapper == None );
// assert( frameId() == None );
assert( decoration == NULL ); assert( decoration == NULL );
assert( postpone_geometry_updates == 0 ); assert( block_geometry_updates == 0 );
assert( !check_active_modal ); assert( !check_active_modal );
delete info;
delete bridge; delete bridge;
} }
@ -176,15 +177,21 @@ void Client::releaseWindow( bool on_shutdown )
{ {
assert( !deleting ); assert( !deleting );
deleting = true; deleting = true;
Deleted* del = Deleted::create( this );
if( effects )
{
static_cast<EffectsHandlerImpl*>(effects)->windowClosed( effectWindow());
scene->windowClosed( this, del );
}
finishCompositing();
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
StackingUpdatesBlocker blocker( workspace()); StackingUpdatesBlocker blocker( workspace());
if (moveResizeMode) if (moveResizeMode)
leaveMoveResize(); leaveMoveResize();
finishWindowRules(); finishWindowRules();
++postpone_geometry_updates; ++block_geometry_updates;
// grab X during the release to make removing of properties, setting to withdrawn state if( isOnCurrentDesktop() && isShown( true ))
// and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2) addWorkspaceRepaint( geometry());
grabXServer();
setMappingState( WithdrawnState ); setMappingState( WithdrawnState );
setModal( false ); // otherwise its mainwindow wouldn't get focus setModal( false ); // otherwise its mainwindow wouldn't get focus
hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags) hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
@ -222,12 +229,12 @@ void Client::releaseWindow( bool on_shutdown )
client = None; client = None;
XDestroyWindow( display(), wrapper ); XDestroyWindow( display(), wrapper );
wrapper = None; wrapper = None;
XDestroyWindow( display(), frame ); XDestroyWindow( display(), frameId());
frame = None; // frame = None;
--postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry --block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
checkNonExistentClients(); disownDataPassedToDeleted();
del->unrefWindow();
deleteClient( this, Allowed ); deleteClient( this, Allowed );
ungrabXServer();
} }
// like releaseWindow(), but this one is called when the window has been already destroyed // like releaseWindow(), but this one is called when the window has been already destroyed
@ -236,12 +243,21 @@ void Client::destroyClient()
{ {
assert( !deleting ); assert( !deleting );
deleting = true; deleting = true;
Deleted* del = Deleted::create( this );
if( effects )
{
static_cast<EffectsHandlerImpl*>(effects)->windowClosed( effectWindow());
scene->windowClosed( this, del );
}
finishCompositing();
workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
StackingUpdatesBlocker blocker( workspace()); StackingUpdatesBlocker blocker( workspace());
if (moveResizeMode) if (moveResizeMode)
leaveMoveResize(); leaveMoveResize();
finishWindowRules(); finishWindowRules();
++postpone_geometry_updates; ++block_geometry_updates;
if( isOnCurrentDesktop() && isShown( true ))
addWorkspaceRepaint( geometry());
setModal( false ); setModal( false );
hidden = true; // so that it's not considered visible anymore hidden = true; // so that it's not considered visible anymore
workspace()->clientHidden( this ); workspace()->clientHidden( this );
@ -251,10 +267,11 @@ void Client::destroyClient()
client = None; // invalidate client = None; // invalidate
XDestroyWindow( display(), wrapper ); XDestroyWindow( display(), wrapper );
wrapper = None; wrapper = None;
XDestroyWindow( display(), frame ); XDestroyWindow( display(), frameId());
frame = None; // frame = None;
--postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry --block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
checkNonExistentClients(); disownDataPassedToDeleted();
del->unrefWindow();
deleteClient( this, Allowed ); deleteClient( this, Allowed );
} }
@ -264,12 +281,12 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
|| ( decoration != NULL && !noBorder()))) || ( decoration != NULL && !noBorder())))
return; return;
bool do_show = false; bool do_show = false;
postponeGeometryUpdates( true ); QRect oldgeom = geometry();
blockGeometryUpdates( true );
if( force ) if( force )
destroyDecoration(); destroyDecoration();
if( !noBorder()) if( !noBorder())
{ {
setMask( QRegion()); // reset shape mask
decoration = workspace()->createDecoration( bridge ); decoration = workspace()->createDecoration( bridge );
// TODO check decoration's minimum size? // TODO check decoration's minimum size?
decoration->init(); decoration->init();
@ -284,12 +301,18 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
workarea_diff_x = save_workarea_diff_x; workarea_diff_x = save_workarea_diff_x;
workarea_diff_y = save_workarea_diff_y; workarea_diff_y = save_workarea_diff_y;
do_show = true; do_show = true;
if( compositing() )
discardWindowPixmap();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
if( effects != NULL )
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), oldgeom );
} }
else else
destroyDecoration(); destroyDecoration();
if( check_workspace_pos ) if( check_workspace_pos )
checkWorkspacePosition(); checkWorkspacePosition();
postponeGeometryUpdates( false ); blockGeometryUpdates( false );
if( do_show ) if( do_show )
decoration->widget()->show(); decoration->widget()->show();
updateFrameExtents(); updateFrameExtents();
@ -297,6 +320,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
void Client::destroyDecoration() void Client::destroyDecoration()
{ {
QRect oldgeom = geometry();
if( decoration != NULL ) if( decoration != NULL )
{ {
delete decoration; delete decoration;
@ -310,6 +334,12 @@ void Client::destroyDecoration()
move( grav ); move( grav );
workarea_diff_x = save_workarea_diff_x; workarea_diff_x = save_workarea_diff_x;
workarea_diff_y = save_workarea_diff_y; workarea_diff_y = save_workarea_diff_y;
if( compositing() )
discardWindowPixmap();
if( scene != NULL && !deleting )
scene->windowGeometryShapeChanged( this );
if( effects != NULL && !deleting )
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), oldgeom );
} }
} }
@ -322,7 +352,7 @@ void Client::checkBorderSizes()
if( new_left == border_left && new_right == border_right if( new_left == border_left && new_right == border_right
&& new_top == border_top && new_bottom == border_bottom ) && new_top == border_top && new_bottom == border_bottom )
return; return;
GeometryUpdatesPostponer blocker( this ); GeometryUpdatesBlocker blocker( this );
move( calculateGravitation( true )); move( calculateGravitation( true ));
border_left = new_left; border_left = new_left;
border_right = new_right; border_right = new_right;
@ -339,7 +369,7 @@ void Client::checkBorderSizes()
void Client::detectNoBorder() void Client::detectNoBorder()
{ {
if( Shape::hasShape( window())) if( shape())
{ {
noborder = true; noborder = true;
return; return;
@ -427,47 +457,25 @@ void Client::setUserNoBorder( bool set )
void Client::updateShape() void Client::updateShape()
{ {
if ( shape() )
XShapeCombineShape(display(), frameId(), ShapeBounding,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSet);
else
XShapeCombineMask( display(), frameId(), ShapeBounding, 0, 0,
None, ShapeSet);
if( compositing())
addDamageFull();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
if( effects != NULL )
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
// workaround for #19644 - shaped windows shouldn't have decoration // workaround for #19644 - shaped windows shouldn't have decoration
if( shape() && !noBorder()) if( shape() && !noBorder())
{ {
noborder = true; noborder = true;
updateDecoration( true ); updateDecoration( true );
} }
if( shape())
{
XShapeCombineShape(display(), frameId(), ShapeBounding,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSet);
}
// !shape() mask setting is done in setMask() when the decoration
// calls it or when the decoration is created/destroyed
if( Shape::version() >= 0x11 ) // 1.1, has input shape support
{ // There appears to be no way to find out if a window has input
// shape set or not, so always propagate the input shape
// (it's the same like the bounding shape by default).
// Also, build the shape using a helper window, not directly
// in the frame window, because the sequence set-shape-to-frame,
// remove-shape-of-client, add-input-shape-of-client has the problem
// that after the second step there's a hole in the input shape
// until the real shape of the client is added and that can make
// the window lose focus (which is a problem with mouse focus policies)
static Window helper_window = None;
if( helper_window == None )
helper_window = XCreateSimpleWindow( display(), rootWindow(),
0, 0, 1, 1, 0, 0, 0 );
XResizeWindow( display(), helper_window, width(), height());
XShapeCombineShape( display(), helper_window, ShapeInput, 0, 0,
frameId(), ShapeBounding, ShapeSet );
XShapeCombineShape( display(), helper_window, ShapeInput,
clientPos().x(), clientPos().y(),
window(), ShapeBounding, ShapeSubtract );
XShapeCombineShape( display(), helper_window, ShapeInput,
clientPos().x(), clientPos().y(),
window(), ShapeInput, ShapeUnion );
XShapeCombineShape( display(), frameId(), ShapeInput, 0, 0,
helper_window, ShapeInput, ShapeSet );
}
} }
void Client::setMask( const QRegion& reg, int mode ) void Client::setMask( const QRegion& reg, int mode )
@ -496,7 +504,12 @@ void Client::setMask( const QRegion& reg, int mode )
xrects, rects.count(), ShapeSet, mode ); xrects, rects.count(), ShapeSet, mode );
delete[] xrects; delete[] xrects;
} }
updateShape(); if( compositing())
addDamageFull();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
if( effects != NULL )
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
} }
QRegion Client::mask() const QRegion Client::mask() const
@ -555,10 +568,6 @@ void Client::minimize( bool avoid_animation )
Notify::raise( Notify::Minimize ); Notify::raise( Notify::Minimize );
// SELI mainClients().isEmpty() ??? - and in unminimize() too
if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
animateMinimizeOrUnminimize( true ); // was visible or shaded
minimized = true; minimized = true;
updateVisibility(); updateVisibility();
@ -566,6 +575,8 @@ void Client::minimize( bool avoid_animation )
workspace()->updateMinimizedOfTransients( this ); workspace()->updateMinimizedOfTransients( this );
updateWindowRules(); updateWindowRules();
workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast ); workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
if( effects && !avoid_animation ) // TODO shouldn't it tell effects at least about the change?
static_cast<EffectsHandlerImpl*>(effects)->windowMinimized( effectWindow());
} }
void Client::unminimize( bool avoid_animation ) void Client::unminimize( bool avoid_animation )
@ -575,142 +586,34 @@ void Client::unminimize( bool avoid_animation )
Notify::raise( Notify::UnMinimize ); Notify::raise( Notify::UnMinimize );
minimized = false; minimized = false;
if( isOnCurrentDesktop() && isShown( true ))
{
if( mainClients().isEmpty() && !avoid_animation )
animateMinimizeOrUnminimize( false );
}
updateVisibility(); updateVisibility();
updateAllowedActions(); updateAllowedActions();
workspace()->updateMinimizedOfTransients( this ); workspace()->updateMinimizedOfTransients( this );
updateWindowRules(); updateWindowRules();
if( effects && !avoid_animation )
static_cast<EffectsHandlerImpl*>(effects)->windowUnminimized( effectWindow());
} }
extern bool blockAnimation; QRect Client::iconGeometry() const
void Client::animateMinimizeOrUnminimize( bool minimize )
{ {
#ifdef __GNUC__
#warning implement kwin animation
#endif
if ( 1 || blockAnimation )
return;
if ( !options->animateMinimize )
return;
if( decoration != NULL && decoration->animateMinimize( minimize ))
return; // decoration did it
// the function is a bit tricky since it will ensure that an
// animation action needs always the same time regardless of the
// performance of the machine or the X-Server.
float lf,rf,tf,bf,step;
int speed = options->animateMinimizeSpeed;
if ( speed > 10 )
speed = 10;
if ( speed < 0 )
speed = 0;
step = 40. * (11 - speed );
NETRect r = info->iconGeometry(); NETRect r = info->iconGeometry();
QRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height ); QRect geom( r.pos.x, r.pos.y, r.size.width, r.size.height );
if ( !icongeom.isValid() ) if( geom.isValid() )
return; return geom;
else
QPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
QRect before, after;
if ( minimize )
{
before = QRect( x(), y(), width(), pm.height() );
after = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
}
else
{
before = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
after = QRect( x(), y(), width(), pm.height() );
}
lf = (after.left() - before.left())/step;
rf = (after.right() - before.right())/step;
tf = (after.top() - before.top())/step;
bf = (after.bottom() - before.bottom())/step;
grabXServer();
QRect area = before;
QRect area2;
QPixmap pm2;
QTime t;
t.start();
float diff;
QPainter p ( workspace()->desktopWidget() );
bool need_to_clear = false;
QPixmap pm3;
do
{
if (area2 != area)
{
pm = animationPixmap( area.width() );
pm2 = QPixmap::grabWindow( rootWindow(), area.x(), area.y(), area.width(), area.height() );
p.drawPixmap( area.x(), area.y(), pm );
if ( need_to_clear )
{
p.drawPixmap( area2.x(), area2.y(), pm3 );
need_to_clear = false;
}
area2 = area;
}
XFlush(display());
XSync( display(), false );
diff = t.elapsed();
if (diff > step)
diff = step;
area.setLeft(before.left() + int(diff*lf));
area.setRight(before.right() + int(diff*rf));
area.setTop(before.top() + int(diff*tf));
area.setBottom(before.bottom() + int(diff*bf));
if (area2 != area )
{
if ( area2.intersects( area ) )
p.drawPixmap( area2.x(), area2.y(), pm2 );
else
{ // no overlap, we can clear later to avoid flicker
pm3 = pm2;
need_to_clear = true;
}
}
} while ( t.elapsed() < step);
if (area2 == area || need_to_clear )
p.drawPixmap( area2.x(), area2.y(), pm2 );
p.end();
ungrabXServer();
}
/*!
The pixmap shown during (un)minimalization animation
*/
QPixmap Client::animationPixmap( int w )
{ {
QFont font = options->font(isActive()); // Check all mainwindows of this window (recursively)
QFontMetrics fm( font ); foreach( Client* mainwin, mainClients() )
QPixmap pm( w, fm.lineSpacing() ); {
pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) ); geom = mainwin->iconGeometry();
QPainter p( &pm ); if( geom.isValid() )
p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() )); return geom;
p.setFont(options->font(isActive())); }
p.drawText( pm.rect(), Qt::AlignLeft|Qt::AlignVCenter|Qt::TextSingleLine, caption() ); // No mainwindow (or their parents) with icon geometry was found
return pm; return QRect();
}
} }
bool Client::isShadeable() const bool Client::isShadeable() const
{ {
return !isSpecialWindow() && !noBorder(); return !isSpecialWindow() && !noBorder();
@ -745,19 +648,15 @@ void Client::setShade( ShadeMode mode )
} }
assert( decoration != NULL ); // noborder windows can't be shaded assert( decoration != NULL ); // noborder windows can't be shaded
GeometryUpdatesPostponer blocker( this ); GeometryUpdatesBlocker blocker( this );
// decorations may turn off some borders when shaded // decorations may turn off some borders when shaded
decoration->borders( border_left, border_right, border_top, border_bottom ); decoration->borders( border_left, border_right, border_top, border_bottom );
int as = options->animateShade? 10 : 1;
// TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere // TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
if ( isShade()) if ( isShade())
{ // shade_mode == ShadeNormal { // shade_mode == ShadeNormal
// we're about to shade, texx xcompmgr to prepare addWorkspaceRepaint( geometry());
long _shade = 1;
XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
// shade // shade
int h = height();
shade_geometry_change = true; shade_geometry_change = true;
QSize s( sizeForClientSize( QSize( clientSize()))); QSize s( sizeForClientSize( QSize( clientSize())));
s.setHeight( border_top + border_bottom ); s.setHeight( border_top + border_bottom );
@ -765,21 +664,6 @@ void Client::setShade( ShadeMode mode )
XUnmapWindow( display(), wrapper ); XUnmapWindow( display(), wrapper );
XUnmapWindow( display(), client ); XUnmapWindow( display(), client );
XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask ); XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
//as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it
//done xcompmgr workaround
// FRAME repaint( false );
// bool wasStaticContents = testWFlags( WStaticContents );
// setWFlags( WStaticContents );
int step = qMax( 4, QABS( h - s.height() ) / as )+1;
do
{
h -= step;
XResizeWindow( display(), frameId(), s.width(), h );
resizeDecoration( QSize( s.width(), h ));
QApplication::syncX();
} while ( h > s.height() + step );
// if ( !wasStaticContents )
// clearWFlags( WStaticContents );
plainResize( s ); plainResize( s );
shade_geometry_change = false; shade_geometry_change = false;
if( isActive()) if( isActive())
@ -789,43 +673,24 @@ void Client::setShade( ShadeMode mode )
else else
workspace()->focusToNull(); workspace()->focusToNull();
} }
// tell xcompmgr shade's done
_shade = 2;
XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
} }
else else
{ {
int h = height();
shade_geometry_change = true; shade_geometry_change = true;
QSize s( sizeForClientSize( clientSize())); QSize s( sizeForClientSize( clientSize()));
// FRAME bool wasStaticContents = testWFlags( WStaticContents );
// setWFlags( WStaticContents );
int step = qMax( 4, QABS( h - s.height() ) / as )+1;
do
{
h += step;
XResizeWindow( display(), frameId(), s.width(), h );
resizeDecoration( QSize( s.width(), h ));
// assume a border
// we do not have time to wait for X to send us paint events
// FRAME repaint( 0, h - step-5, width(), step+5, true);
QApplication::syncX();
} while ( h < s.height() - step );
// if ( !wasStaticContents )
// clearWFlags( WStaticContents );
shade_geometry_change = false; shade_geometry_change = false;
plainResize( s ); plainResize( s );
if( shade_mode == ShadeHover || shade_mode == ShadeActivated ) if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
setActive( true ); setActive( true );
XMapWindow( display(), wrapperId()); XMapWindow( display(), wrapperId());
XMapWindow( display(), window()); XMapWindow( display(), window());
XDeleteProperty (display(), client, atoms->net_wm_window_shade);
if ( isActive() ) if ( isActive() )
workspace()->requestFocus( this ); workspace()->requestFocus( this );
} }
checkMaximizeGeometry(); checkMaximizeGeometry();
info->setState( isShade() ? NET::Shaded : 0, NET::Shaded ); info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden ); info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
discardWindowPixmap();
updateVisibility(); updateVisibility();
updateAllowedActions(); updateAllowedActions();
workspace()->updateMinimizedOfTransients( this ); workspace()->updateMinimizedOfTransients( this );
@ -929,8 +794,8 @@ void Client::setMappingState(int s)
XChangeProperty(display(), window(), atoms->wm_state, atoms->wm_state, 32, XChangeProperty(display(), window(), atoms->wm_state, atoms->wm_state, 32,
PropModeReplace, (unsigned char *)data, 2); PropModeReplace, (unsigned char *)data, 2);
if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry if( was_unmanaged ) // manage() did block_geometry_updates = 1, now it's ok to finally set the geometry
postponeGeometryUpdates( false ); blockGeometryUpdates( false );
} }
/*! /*!
@ -941,12 +806,17 @@ void Client::rawShow()
{ {
if( decoration != NULL ) if( decoration != NULL )
decoration->widget()->show(); // not really necessary, but let it know the state decoration->widget()->show(); // not really necessary, but let it know the state
XMapWindow( display(), frame ); XMapWindow( display(), frameId());
if( !isShade()) if( !isShade())
{ {
XMapWindow( display(), wrapper ); XMapWindow( display(), wrapper );
XMapWindow( display(), client ); XMapWindow( display(), client );
} }
// XComposite invalidates backing pixmaps on unmap (minimize, different
// virtual desktop, etc.). We kept the last known good pixmap around
// for use in effects, but now we want to have access to the new pixmap
if( compositing() )
discardWindowPixmap();
} }
/*! /*!
@ -956,6 +826,7 @@ void Client::rawShow()
*/ */
void Client::rawHide() void Client::rawHide()
{ {
addWorkspaceRepaint( geometry());
// Here it may look like a race condition, as some other client might try to unmap // Here it may look like a race condition, as some other client might try to unmap
// the window between these two XSelectInput() calls. However, they're supposed to // the window between these two XSelectInput() calls. However, they're supposed to
// use XWithdrawWindow(), which also sends a synthetic event to the root window, // use XWithdrawWindow(), which also sends a synthetic event to the root window,
@ -963,7 +834,7 @@ void Client::rawHide()
// will be missed is also very minimal, so I don't think it's needed to grab the server // will be missed is also very minimal, so I don't think it's needed to grab the server
// here. // here.
XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
XUnmapWindow( display(), frame ); XUnmapWindow( display(), frameId());
XUnmapWindow( display(), wrapper ); XUnmapWindow( display(), wrapper );
XUnmapWindow( display(), client ); XUnmapWindow( display(), client );
XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask ); XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
@ -1197,6 +1068,17 @@ void Client::setDesktop( int desktop )
updateWindowRules(); updateWindowRules();
} }
/*!
Returns the virtual desktop within the workspace() the client window
is located in, 0 if it isn't located on any special desktop (not mapped yet),
or NET::OnAllDesktops. Do not use desktop() directly, use
isOnDesktop() instead.
*/
int Client::desktop() const
{
return desk;
}
void Client::setOnAllDesktops( bool b ) void Client::setOnAllDesktops( bool b )
{ {
if(( b && isOnAllDesktops()) if(( b && isOnAllDesktops())
@ -1208,11 +1090,6 @@ void Client::setOnAllDesktops( bool b )
setDesktop( workspace()->currentDesktop()); setDesktop( workspace()->currentDesktop());
} }
bool Client::isOnCurrentDesktop() const
{
return isOnDesktop( workspace()->currentDesktop());
}
// performs activation and/or raising of the window // performs activation and/or raising of the window
void Client::takeActivity( int flags, bool handled, allowed_t ) void Client::takeActivity( int flags, bool handled, allowed_t )
{ {
@ -1308,7 +1185,7 @@ QString Client::readName() const
return KWM::readNameProperty( window(), XA_WM_NAME ); return KWM::readNameProperty( window(), XA_WM_NAME );
} }
KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption()); KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, Client, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
void Client::setCaption( const QString& _s, bool force ) void Client::setCaption( const QString& _s, bool force )
{ {
@ -1495,125 +1372,6 @@ void Client::getWindowProtocols()
} }
} }
static int nullErrorHandler(Display *, XErrorEvent *)
{
return 0;
}
/*!
Returns WM_WINDOW_ROLE property for a given window.
*/
QByteArray Client::staticWindowRole(WId w)
{
return getStringProperty(w, atoms->wm_window_role).toLower();
}
/*!
Returns SM_CLIENT_ID property for a given window.
*/
QByteArray Client::staticSessionId(WId w)
{
return getStringProperty(w, atoms->sm_client_id);
}
/*!
Returns WM_COMMAND property for a given window.
*/
QByteArray Client::staticWmCommand(WId w)
{
return getStringProperty(w, XA_WM_COMMAND, ' ');
}
/*!
Returns WM_CLIENT_LEADER property for a given window.
*/
Window Client::staticWmClientLeader(WId w)
{
Atom type;
int format, status;
unsigned long nitems = 0;
unsigned long extra = 0;
unsigned char *data = 0;
Window result = w;
XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
status = XGetWindowProperty( display(), w, atoms->wm_client_leader, 0, 10000,
false, XA_WINDOW, &type, &format,
&nitems, &extra, &data );
XSetErrorHandler(oldHandler);
if (status == Success )
{
if (data && nitems > 0)
result = *((Window*) data);
XFree(data);
}
return result;
}
void Client::getWmClientLeader()
{
wmClientLeaderWin = staticWmClientLeader(window());
}
/*!
Returns sessionId for this client,
taken either from its window or from the leader window.
*/
QByteArray Client::sessionId()
{
QByteArray result = staticSessionId(window());
if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
result = staticSessionId(wmClientLeaderWin);
return result;
}
/*!
Returns command property for this client,
taken either from its window or from the leader window.
*/
QByteArray Client::wmCommand()
{
QByteArray result = staticWmCommand(window());
if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
result = staticWmCommand(wmClientLeaderWin);
return result;
}
void Client::getWmClientMachine()
{
client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
if( client_machine.isEmpty())
client_machine = "localhost";
}
/*!
Returns client machine for this client,
taken either from its window or from the leader window.
*/
QByteArray Client::wmClientMachine( bool use_localhost ) const
{
QByteArray result = client_machine;
if( use_localhost )
{ // special name for the local machine (localhost)
if( result != "localhost" && isLocalMachine( result ))
result = "localhost";
}
return result;
}
/*!
Returns client leader window for this client.
Returns the client window itself if no leader window is defined.
*/
Window Client::wmClientLeader() const
{
if (wmClientLeaderWin)
return wmClientLeaderWin;
return window();
}
bool Client::wantsTabFocus() const bool Client::wantsTabFocus() const
{ {
return ( isNormalWindow() || isDialog()) && wantsInput(); return ( isNormalWindow() || isDialog()) && wantsInput();
@ -1625,89 +1383,12 @@ bool Client::wantsInput() const
return rules()->checkAcceptFocus( input || Ptakefocus ); return rules()->checkAcceptFocus( input || Ptakefocus );
} }
bool Client::isDesktop() const
{
return windowType() == NET::Desktop;
}
bool Client::isDock() const
{
return windowType() == NET::Dock;
}
bool Client::isTopMenu() const
{
return windowType() == NET::TopMenu;
}
bool Client::isMenu() const
{
return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
}
bool Client::isToolbar() const
{
return windowType() == NET::Toolbar;
}
bool Client::isSplash() const
{
return windowType() == NET::Splash;
}
bool Client::isUtility() const
{
return windowType() == NET::Utility;
}
bool Client::isDialog() const
{
return windowType() == NET::Dialog;
}
bool Client::isNormalWindow() const
{
return windowType() == NET::Normal;
}
bool Client::isSpecialWindow() const bool Client::isSpecialWindow() const
{ {
return isDesktop() || isDock() || isSplash() || isTopMenu() return isDesktop() || isDock() || isSplash() || isTopMenu()
|| isToolbar(); // TODO || isToolbar(); // TODO
} }
NET::WindowType Client::windowType( bool direct, int supported_types ) const
{
NET::WindowType wt = info->windowType( supported_types );
if( direct )
return wt;
NET::WindowType wt2 = rules()->checkType( wt );
if( wt != wt2 )
{
wt = wt2;
info->setWindowType( wt ); // force hint change
}
// hacks here
if( wt == NET::Menu )
{
// ugly hack to support the times when NET::Menu meant NET::TopMenu
// if it's as wide as the screen, not very high and has its upper-left
// corner a bit above the screen's upper-left cornet, it's a topmenu
if( x() == 0 && y() < 0 && y() > -10 && height() < 100
&& abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
wt = NET::TopMenu;
}
// TODO change this to rule
const char* const oo_prefix = "openoffice.org"; // QByteArray has no startsWith()
// oo_prefix is lowercase, because resourceClass() is forced to be lowercase
if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
wt = NET::Normal; // see bug #66065
if( wt == NET::Unknown ) // this is more or less suggested in NETWM spec
wt = isTransient() ? NET::Dialog : NET::Normal;
return wt;
}
/*! /*!
Sets an appropriate cursor shape for the logical mouse position \a m Sets an appropriate cursor shape for the logical mouse position \a m
@ -1804,46 +1485,10 @@ void Client::cancelAutoRaise()
autoRaiseTimer = 0; autoRaiseTimer = 0;
} }
#ifndef NDEBUG void Client::debug( kdbgstream& stream ) const
kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
{ {
if( cl == NULL ) stream << "\'ID:" << window() << ";WMCLASS:" << resourceClass() << ":" << resourceName() << ";Caption:" << caption() << "\'";
return stream << "\'NULL_CLIENT\'";
return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
} }
kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
{
stream << "LIST:(";
bool first = true;
for( ClientList::ConstIterator it = list.begin();
it != list.end();
++it )
{
if( !first )
stream << ":";
first = false;
stream << *it;
}
stream << ")";
return stream;
}
kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
{
stream << "LIST:(";
bool first = true;
for( ConstClientList::ConstIterator it = list.begin();
it != list.end();
++it )
{
if( !first )
stream << ":";
first = false;
stream << *it;
}
stream << ")";
return stream;
}
#endif
QPixmap * kwin_get_menu_pix_hack() QPixmap * kwin_get_menu_pix_hack()
{ {

View file

@ -431,7 +431,7 @@ void Toplevel::addDamage( int x, int y, int w, int h )
r &= rect(); r &= rect();
damage_region += r; damage_region += r;
repaints_region += r; repaints_region += r;
effects->windowDamaged( effectWindow(), r ); static_cast<EffectsHandlerImpl*>(effects)->windowDamaged( effectWindow(), r );
} }
void Toplevel::addDamageFull() void Toplevel::addDamageFull()
@ -440,7 +440,7 @@ void Toplevel::addDamageFull()
return; return;
damage_region = rect(); damage_region = rect();
repaints_region = rect(); repaints_region = rect();
effects->windowDamaged( effectWindow(), rect()); static_cast<EffectsHandlerImpl*>(effects)->windowDamaged( effectWindow(), rect());
} }
void Toplevel::resetDamage( const QRect& r ) void Toplevel::resetDamage( const QRect& r )

View file

@ -16,7 +16,13 @@ License. See the file "COPYING" for the exact licensing terms.
#include "scene_xrender.h" #include "scene_xrender.h"
#include "workspace.h" #include "workspace.h"
#include <QFile>
#include "kdebug.h" #include "kdebug.h"
#include "klibloader.h"
#include "kdesktopfile.h"
#include "kconfiggroup.h"
#include "kstandarddirs.h"
#include <assert.h> #include <assert.h>
@ -116,11 +122,112 @@ void EffectsHandlerImpl::drawWindow( EffectWindow* w, int mask, QRegion region,
scene->finalDrawWindow( static_cast<EffectWindowImpl*>( w ), mask, region, data ); scene->finalDrawWindow( static_cast<EffectWindowImpl*>( w ), mask, region, data );
} }
// start another painting pass
void EffectsHandlerImpl::startPaint()
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_transform == 0 );
}
void EffectsHandlerImpl::windowUserMovedResized( EffectWindow* c, bool first, bool last )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowUserMovedResized( c, first, last );
}
void EffectsHandlerImpl::windowOpacityChanged( EffectWindow* c, double old_opacity ) void EffectsHandlerImpl::windowOpacityChanged( EffectWindow* c, double old_opacity )
{ {
if( static_cast<EffectWindowImpl*>(c)->window()->opacity() == old_opacity ) if( static_cast<EffectWindowImpl*>(c)->window()->opacity() == old_opacity )
return; return;
EffectsHandler::windowOpacityChanged( c, old_opacity ); foreach( EffectPair ep, loaded_effects )
ep.second->windowOpacityChanged( c, old_opacity );
}
void EffectsHandlerImpl::windowAdded( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowAdded( c );
}
void EffectsHandlerImpl::windowDeleted( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowDeleted( c );
}
void EffectsHandlerImpl::windowClosed( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowClosed( c );
}
void EffectsHandlerImpl::windowActivated( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowActivated( c );
}
void EffectsHandlerImpl::windowMinimized( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowMinimized( c );
}
void EffectsHandlerImpl::windowUnminimized( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowUnminimized( c );
}
void EffectsHandlerImpl::desktopChanged( int old )
{
foreach( EffectPair ep, loaded_effects )
ep.second->desktopChanged( old );
}
void EffectsHandlerImpl::windowDamaged( EffectWindow* w, const QRect& r )
{
if( w == NULL )
return;
foreach( EffectPair ep, loaded_effects )
ep.second->windowDamaged( w, r );
}
void EffectsHandlerImpl::windowGeometryShapeChanged( EffectWindow* w, const QRect& old )
{
if( w == NULL ) // during late cleanup effectWindow() may be already NULL
return; // in some functions that may still call this
foreach( EffectPair ep, loaded_effects )
ep.second->windowGeometryShapeChanged( w, old );
}
void EffectsHandlerImpl::tabBoxAdded( int mode )
{
foreach( EffectPair ep, loaded_effects )
ep.second->tabBoxAdded( mode );
}
void EffectsHandlerImpl::tabBoxClosed()
{
foreach( EffectPair ep, loaded_effects )
ep.second->tabBoxClosed();
}
void EffectsHandlerImpl::tabBoxUpdated()
{
foreach( EffectPair ep, loaded_effects )
ep.second->tabBoxUpdated();
}
bool EffectsHandlerImpl::borderActivated( ElectricBorder border )
{
bool ret = false;
foreach( EffectPair ep, loaded_effects )
if( ep.second->borderActivated( border ))
ret = true; // bail out or tell all?
return ret;
} }
void EffectsHandlerImpl::activateWindow( EffectWindow* c ) void EffectsHandlerImpl::activateWindow( EffectWindow* c )
@ -283,6 +390,108 @@ unsigned long EffectsHandlerImpl::xrenderBufferPicture()
return None; return None;
} }
KLibrary* EffectsHandlerImpl::findEffectLibrary( const QString& effectname )
{
QString libname = "kwin4_effect_" + effectname.toLower();
QString desktopfile = KStandardDirs::locate("appdata",
"effects/" + effectname.toLower() + ".desktop");
if( !desktopfile.isEmpty() )
{
KDesktopFile desktopconf( desktopfile );
KConfigGroup conf = desktopconf.desktopGroup();
libname = conf.readEntry( "X-KDE-Library", libname );
}
KLibrary* library = KLibLoader::self()->library(QFile::encodeName(libname));
if( !library )
{
kError( 1212 ) << k_funcinfo << "couldn't open library for effect '" <<
effectname << "'" << endl;
return 0;
}
return library;
}
void EffectsHandlerImpl::loadEffect( const QString& name )
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_transform == 0 );
// Make sure a single effect won't be loaded multiple times
for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); it++)
{
if( (*it).first == name )
{
kDebug( 1212 ) << "EffectsHandler::loadEffect : Effect already loaded : " << name << endl;
return;
}
}
kDebug( 1212 ) << k_funcinfo << "Trying to load " << name << endl;
KLibrary* library = findEffectLibrary( name );
if( !library )
{
return;
}
QString supported_symbol = "effect_supported_" + name;
KLibrary::void_function_ptr supported_func = library->resolveFunction(supported_symbol.toAscii().data());
QString create_symbol = "effect_create_" + name;
KLibrary::void_function_ptr create_func = library->resolveFunction(create_symbol.toAscii().data());
if( supported_func )
{
typedef bool (*t_supportedfunc)();
t_supportedfunc supported = reinterpret_cast<t_supportedfunc>(supported_func);
if(!supported())
{
kWarning( 1212 ) << "EffectsHandler::loadEffect : Effect " << name << " is not supported" << endl;
library->unload();
return;
}
}
if(!create_func)
{
kError( 1212 ) << "EffectsHandler::loadEffect : effect_create function not found" << endl;
library->unload();
return;
}
typedef Effect* (*t_createfunc)();
t_createfunc create = reinterpret_cast<t_createfunc>(create_func);
Effect* e = create();
loaded_effects.append( EffectPair( name, e ) );
effect_libraries[ name ] = library;
}
void EffectsHandlerImpl::unloadEffect( const QString& name )
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_transform == 0 );
for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); it++)
{
if ( (*it).first == name )
{
kDebug( 1212 ) << "EffectsHandler::unloadEffect : Unloading Effect : " << name << endl;
delete (*it).second;
loaded_effects.erase(it);
effect_libraries[ name ]->unload();
return;
}
}
kDebug( 1212 ) << "EffectsHandler::unloadEffect : Effect not loaded : " << name << endl;
}
//**************************************** //****************************************
// EffectWindowImpl // EffectWindowImpl
//**************************************** //****************************************

View file

@ -34,7 +34,6 @@ class EffectsHandlerImpl : public EffectsHandler
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void windowOpacityChanged( EffectWindow* c, double old_opacity );
virtual void activateWindow( EffectWindow* c ); virtual void activateWindow( EffectWindow* c );
virtual int currentDesktop() const; virtual int currentDesktop() const;
@ -58,6 +57,30 @@ class EffectsHandlerImpl : public EffectsHandler
virtual void reserveElectricBorderSwitching( bool reserve ); virtual void reserveElectricBorderSwitching( bool reserve );
virtual unsigned long xrenderBufferPicture(); virtual unsigned long xrenderBufferPicture();
// internal (used by kwin core or compositing code)
virtual void startPaint();
virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last );
virtual void windowOpacityChanged( EffectWindow* c, double old_opacity );
virtual void windowAdded( EffectWindow* c );
virtual void windowClosed( EffectWindow* c );
virtual void windowDeleted( EffectWindow* c );
virtual void windowActivated( EffectWindow* c );
virtual void windowMinimized( EffectWindow* c );
virtual void windowUnminimized( EffectWindow* c );
virtual void desktopChanged( int old );
virtual void windowDamaged( EffectWindow* w, const QRect& r );
virtual void windowGeometryShapeChanged( EffectWindow* w, const QRect& old );
virtual void tabBoxAdded( int mode );
virtual void tabBoxClosed();
virtual void tabBoxUpdated();
virtual bool borderActivated( ElectricBorder border );
void loadEffect( const QString& name );
void unloadEffect( const QString& name );
protected:
KLibrary* findEffectLibrary( const QString& effectname );
}; };
class EffectWindowImpl : public EffectWindow class EffectWindowImpl : public EffectWindow

View file

@ -21,6 +21,9 @@ License. See the file "COPYING" for the exact licensing terms.
#include "tabbox.h" #include "tabbox.h"
#include "group.h" #include "group.h"
#include "rules.h" #include "rules.h"
#include "unmanaged.h"
#include "scene.h"
#include "effects.h"
#include <QWhatsThis> #include <QWhatsThis>
#include <QApplication> #include <QApplication>
@ -83,6 +86,10 @@ void WinInfo::changeState( unsigned long state, unsigned long mask )
m_client->setFullScreen( true, false ); m_client->setFullScreen( true, false );
} }
void WinInfo::disable()
{
m_client = NULL; // only used when the object is passed to Deleted
}
// **************************************** // ****************************************
// RootInfo // RootInfo
@ -199,15 +206,10 @@ bool Workspace::workspaceEvent( XEvent * e )
XUngrabKeyboard( display(), xTime() ); XUngrabKeyboard( display(), xTime() );
} }
if( e->type == PropertyNotify || e->type == ClientMessage ) if ( e->type == PropertyNotify || e->type == ClientMessage )
{ {
unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ]; if ( netCheck( e ) )
rootInfo->event( e, dirty, NETRootInfo::PROPERTIES_SIZE ); return true;
if( dirty[ NETRootInfo::PROTOCOLS ] & NET::DesktopNames )
saveDesktopSettings();
if( dirty[ NETRootInfo::PROTOCOLS2 ] & NET::WM2DesktopLayout )
setDesktopLayout( rootInfo->desktopLayoutOrientation(), rootInfo->desktopLayoutColumnsRows().width(),
rootInfo->desktopLayoutColumnsRows().height(), rootInfo->desktopLayoutCorner());
} }
// events that should be handled before Clients can get them // events that should be handled before Clients can get them
@ -223,6 +225,8 @@ bool Workspace::workspaceEvent( XEvent * e )
tab_box->handleMouseEvent( e ); tab_box->handleMouseEvent( e );
return true; return true;
} }
if( effects && static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowEvent( e ))
return true;
break; break;
case KeyPress: case KeyPress:
{ {
@ -267,6 +271,11 @@ bool Workspace::workspaceEvent( XEvent * e )
if( c->windowEvent( e )) if( c->windowEvent( e ))
return true; return true;
} }
else if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xany.window )))
{
if( c->windowEvent( e ))
return true;
}
else else
{ {
Window special = findSpecialEventWindow( e ); Window special = findSpecialEventWindow( e );
@ -324,13 +333,8 @@ bool Workspace::workspaceEvent( XEvent * e )
} }
return true; return true;
} }
return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt
} }
case MapNotify:
return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt
case ReparentNotify: case ReparentNotify:
{ {
//do not confuse Qt with these events. After all, _we_ are the //do not confuse Qt with these events. After all, _we_ are the
@ -380,6 +384,19 @@ bool Workspace::workspaceEvent( XEvent * e )
} }
break; break;
} }
case MapNotify:
{
if( e->xmap.override_redirect )
{
Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xmap.window ));
if( c == NULL )
c = createUnmanaged( e->xmap.window );
if( c )
return c->windowEvent( e );
}
return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt
}
case EnterNotify: case EnterNotify:
{ {
if ( QWhatsThis::inWhatsThisMode() ) if ( QWhatsThis::inWhatsThisMode() )
@ -388,7 +405,7 @@ bool Workspace::workspaceEvent( XEvent * e )
if ( w ) if ( w )
QWhatsThis::leaveWhatsThisMode(); QWhatsThis::leaveWhatsThisMode();
} }
if( electricBorder(e)) if( electricBorderEvent(e))
return true; return true;
break; break;
} }
@ -453,10 +470,32 @@ bool Workspace::workspaceEvent( XEvent * e )
case FocusOut: case FocusOut:
return true; // always eat these, they would tell Qt that KWin is the active app return true; // always eat these, they would tell Qt that KWin is the active app
case ClientMessage: case ClientMessage:
if( electricBorder( e )) if( electricBorderEvent( e ))
return true; return true;
break; break;
case MappingNotify:
XRefreshKeyboardMapping( &e->xmapping );
tab_box->updateKeyMapping();
break;
case Expose:
if( e->xexpose.window == rootWindow() && compositing()) // root window needs repainting
addRepaint( e->xexpose.x, e->xexpose.y, e->xexpose.width, e->xexpose.height );
break;
default: default:
if( e->type == Extensions::randrNotifyEvent() && Extensions::randrAvailable() )
{
#ifdef HAVE_XRANDR
XRRUpdateConfiguration( e );
#endif
if( compositing() )
{
// desktopResized() should take care of when the size or
// shape of the desktop has changed, but we also want to
// catch refresh rate changes
finishCompositing();
QTimer::singleShot( 0, this, SLOT( setupCompositing() ) );
}
}
break; break;
} }
return false; return false;
@ -496,6 +535,20 @@ Window Workspace::findSpecialEventWindow( XEvent* e )
}; };
} }
/*!
Handles client messages sent to the workspace
*/
bool Workspace::netCheck( XEvent* e )
{
unsigned int dirty = rootInfo->event( e );
if ( dirty & NET::DesktopNames )
saveDesktopSettings();
return dirty != 0;
}
// **************************************** // ****************************************
// Client // Client
// **************************************** // ****************************************
@ -508,6 +561,7 @@ bool Client::windowEvent( XEvent* e )
if( e->xany.window == window()) // avoid doing stuff on frame or wrapper if( e->xany.window == window()) // avoid doing stuff on frame or wrapper
{ {
unsigned long dirty[ 2 ]; unsigned long dirty[ 2 ];
double old_opacity = opacity();
info->event( e, dirty, 2 ); // pass through the NET stuff info->event( e, dirty, 2 ); // pass through the NET stuff
if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 ) if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 )
@ -538,6 +592,21 @@ bool Client::windowEvent( XEvent* e )
if( demandAttentionKNotifyTimer != NULL ) if( demandAttentionKNotifyTimer != NULL )
demandAttentionKNotify(); demandAttentionKNotify();
} }
if( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2Opacity )
{
if( compositing())
{
addRepaintFull();
scene->windowOpacityChanged( this );
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->windowOpacityChanged( effectWindow(), old_opacity );
}
else
{ // forward to the frame if there's possibly another compositing manager running
NETWinInfo i( display(), frameId(), rootWindow(), 0 );
i.setOpacity( info->opacity());
}
}
} }
// TODO move all focus handling stuff to separate file? // TODO move all focus handling stuff to separate file?
@ -618,15 +687,25 @@ bool Client::windowEvent( XEvent* e )
workspace()->updateColormap(); workspace()->updateColormap();
} }
break; break;
case VisibilityNotify:
visibilityNotifyEvent( &e->xvisibility );
break;
default: default:
if( e->xany.window == window()) if( e->xany.window == window())
{
if( e->type == Shape::shapeEvent() )
{ {
is_shape = Shape::hasShape( window()); // workaround for #19644 if( e->type == Extensions::shapeNotifyEvent() )
updateShape(); {
detectShape( window()); // workaround for #19644
updateShape();
}
}
if( e->xany.window == frameId())
{
#ifdef HAVE_XDAMAGE
if( e->type == Extensions::damageNotifyEvent())
damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e ));
#endif
} }
}
break; break;
} }
return true; // eat all events return true; // eat all events
@ -728,8 +807,6 @@ void Client::destroyNotifyEvent( XDestroyWindowEvent* e )
} }
bool blockAnimation = false;
/*! /*!
Handles client messages for the client window Handles client messages for the client window
*/ */
@ -742,14 +819,13 @@ void Client::clientMessageEvent( XClientMessageEvent* e )
{ {
if( isTopMenu() && workspace()->managingTopMenus()) if( isTopMenu() && workspace()->managingTopMenus())
return; // kwin controls these return; // kwin controls these
if( e->data.l[ 1 ] ) bool avoid_animation = ( e->data.l[ 1 ] );
blockAnimation = true;
if( e->data.l[ 0 ] == IconicState ) if( e->data.l[ 0 ] == IconicState )
minimize(); minimize();
else if( e->data.l[ 0 ] == NormalState ) else if( e->data.l[ 0 ] == NormalState )
{ // copied from mapRequest() { // copied from mapRequest()
if( isMinimized()) if( isMinimized())
unminimize(); unminimize( avoid_animation );
if( isShade()) if( isShade())
setShade( ShadeNone ); setShade( ShadeNone );
if( !isOnCurrentDesktop()) if( !isOnCurrentDesktop())
@ -760,7 +836,6 @@ void Client::clientMessageEvent( XClientMessageEvent* e )
demandAttention(); demandAttention();
} }
} }
blockAnimation = false;
} }
else if ( e->message_type == atoms->wm_change_state) else if ( e->message_type == atoms->wm_change_state)
{ {
@ -829,6 +904,7 @@ void Client::configureRequestEvent( XConfigureRequestEvent* e )
*/ */
void Client::propertyNotifyEvent( XPropertyEvent* e ) void Client::propertyNotifyEvent( XPropertyEvent* e )
{ {
Toplevel::propertyNotifyEvent( e );
if( e->window != window()) if( e->window != window())
return; // ignore frame/wrapper return; // ignore frame/wrapper
switch ( e->atom ) switch ( e->atom )
@ -852,10 +928,6 @@ void Client::propertyNotifyEvent( XPropertyEvent* e )
default: default:
if ( e->atom == atoms->wm_protocols ) if ( e->atom == atoms->wm_protocols )
getWindowProtocols(); getWindowProtocols();
else if (e->atom == atoms->wm_client_leader )
getWmClientLeader();
else if( e->atom == atoms->wm_window_role )
window_role = staticWindowRole( window());
else if( e->atom == atoms->motif_wm_hints ) else if( e->atom == atoms->motif_wm_hints )
getMotifHints(); getMotifHints();
break; break;
@ -995,13 +1067,18 @@ void Client::ungrabButton( int modifier )
*/ */
void Client::updateMouseGrab() void Client::updateMouseGrab()
{ {
if( workspace()->globalShortcutsDisabled())
{
XUngrabButton( display(), AnyButton, AnyModifier, wrapperId());
// keep grab for the simple click without modifiers if needed
if( !( !options->clickRaise || not_obscured ))
grabButton( None );
return;
}
if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab() if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
{ {
// remove the grab for no modifiers only if the window // remove the grab for no modifiers only if the window
// is unobscured or if the user doesn't want click raise // is unobscured or if the user doesn't want click raise
// (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
// the most recently raised window)
bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
if( !options->clickRaise || not_obscured ) if( !options->clickRaise || not_obscured )
ungrabButton( None ); ungrabButton( None );
else else
@ -1021,37 +1098,6 @@ void Client::updateMouseGrab()
} }
} }
int qtToX11Button( Qt::ButtonState button )
{
if( button == Qt::LeftButton )
return Button1;
else if( button == Qt::MidButton )
return Button2;
else if( button == Qt::RightButton )
return Button3;
return AnyButton;
}
int qtToX11State( Qt::ButtonState buttons, Qt::KeyboardModifiers modifiers )
{
int ret = 0;
if( buttons & Qt::LeftButton )
ret |= Button1Mask;
if( buttons & Qt::MidButton )
ret |= Button2Mask;
if( buttons & Qt::RightButton )
ret |= Button3Mask;
if( modifiers & Qt::ShiftModifier )
ret |= ShiftMask;
if( modifiers & Qt::ControlModifier )
ret |= ControlMask;
if( modifiers & Qt::AltModifier )
ret |= KKeyServer::modXAlt();
if( modifiers & Qt::MetaModifier )
ret |= KKeyServer::modXMeta();
return ret;
}
// Qt propagates mouse events up the widget hierachy, which means events // Qt propagates mouse events up the widget hierachy, which means events
// for the decoration window cannot be (easily) intercepted as X11 events // for the decoration window cannot be (easily) intercepted as X11 events
bool Client::eventFilter( QObject* o, QEvent* e ) bool Client::eventFilter( QObject* o, QEvent* e )
@ -1095,6 +1141,15 @@ bool Client::eventFilter( QObject* o, QEvent* e )
// on the decoration widget. // on the decoration widget.
if( ev->size() != size()) if( ev->size() != size())
return true; return true;
// HACK: Avoid decoration redraw delays. On resize Qt sets WA_WStateConfigPending
// which delays all painting until a matching ConfigureNotify event comes.
// But this process itself is the window manager, so it's not needed
// to wait for that event, the geometry is known.
// Note that if Qt in the future changes how this flag is handled and what it
// triggers then this may potentionally break things. See mainly QETWidget::translateConfigEvent().
decoration->widget()->setAttribute( Qt::WA_WState_ConfigPending, false );
decoration->widget()->update();
return false;
} }
return false; return false;
} }
@ -1436,6 +1491,17 @@ void Client::focusOutEvent( XFocusOutEvent* e )
setActive( false ); setActive( false );
} }
void Client::visibilityNotifyEvent( XVisibilityEvent * e)
{
if( e->window != frameId())
return; // care only about the whole frame
bool new_not_obscured = e->state == VisibilityUnobscured;
if( not_obscured == new_not_obscured )
return;
not_obscured = new_not_obscured;
updateMouseGrab();
}
// performs _NET_WM_MOVERESIZE // performs _NET_WM_MOVERESIZE
void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction ) void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
{ {
@ -1497,7 +1563,7 @@ void Client::keyPressEvent( uint key_code )
bool is_alt = key_code & Qt::ALT; bool is_alt = key_code & Qt::ALT;
key_code = key_code & 0xffff; key_code = key_code & 0xffff;
int delta = is_control?1:is_alt?32:8; int delta = is_control?1:is_alt?32:8;
QPoint pos = QCursor::pos(); QPoint pos = cursorPos();
switch ( key_code ) switch ( key_code )
{ {
case Qt::Key_Left: case Qt::Key_Left:
@ -1530,6 +1596,104 @@ void Client::keyPressEvent( uint key_code )
QCursor::setPos( pos ); QCursor::setPos( pos );
} }
// ****************************************
// Unmanaged
// ****************************************
bool Unmanaged::windowEvent( XEvent* e )
{
double old_opacity = opacity();
unsigned long dirty[ 2 ];
info->event( e, dirty, 2 ); // pass through the NET stuff
if( dirty[ NETWinInfo::PROTOCOLS2 ] & NET::WM2Opacity )
{
if( compositing())
{
addRepaintFull();
scene->windowOpacityChanged( this );
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->windowOpacityChanged( effectWindow(), old_opacity );
}
}
switch (e->type)
{
case UnmapNotify:
unmapNotifyEvent( &e->xunmap );
break;
case MapNotify:
mapNotifyEvent( &e->xmap );
break;
case ConfigureNotify:
configureNotifyEvent( &e->xconfigure );
break;
case PropertyNotify:
propertyNotifyEvent( &e->xproperty );
default:
{
if( e->type == Extensions::shapeNotifyEvent() )
{
detectShape( window());
addDamageFull();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
if( effects != NULL )
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
}
#ifdef HAVE_XDAMAGE
if( e->type == Extensions::damageNotifyEvent())
damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e ));
#endif
break;
}
}
return false; // don't eat events, even our own unmanaged widgets are tracked
}
void Unmanaged::mapNotifyEvent( XMapEvent* )
{
}
void Unmanaged::unmapNotifyEvent( XUnmapEvent* )
{
release();
}
void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
{
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowStacking(); // keep them on top
QRect newgeom( e->x, e->y, e->width, e->height );
if( newgeom == geom )
return;
addWorkspaceRepaint( geometry()); // damage old area
QRect old = geom;
geom = newgeom;
discardWindowPixmap();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
if( effects != NULL )
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), old );
}
// ****************************************
// Toplevel
// ****************************************
void Toplevel::propertyNotifyEvent( XPropertyEvent* e )
{
if( e->window != window())
return; // ignore frame/wrapper
switch ( e->atom )
{
default:
if (e->atom == atoms->wm_client_leader )
getWmClientLeader();
else if( e->atom == atoms->wm_window_role )
getWindowRole();
break;
}
}
// **************************************** // ****************************************
// Group // Group
// **************************************** // ****************************************

View file

@ -28,6 +28,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "notifications.h" #include "notifications.h"
#include "geometrytip.h" #include "geometrytip.h"
#include "rules.h" #include "rules.h"
#include "effects.h"
#include <QX11Info> #include <QX11Info>
#include <QDesktopWidget> #include <QDesktopWidget>
@ -48,8 +49,15 @@ void Workspace::desktopResized()
desktop_geometry.width = geom.width(); desktop_geometry.width = geom.width();
desktop_geometry.height = geom.height(); desktop_geometry.height = geom.height();
rootInfo->setDesktopGeometry( -1, desktop_geometry ); rootInfo->setDesktopGeometry( -1, desktop_geometry );
updateClientArea(); updateClientArea();
checkElectricBorders( true ); destroyElectricBorders();
updateElectricBorders();
if( compositing() )
{
finishCompositing();
QTimer::singleShot( 0, this, SLOT( setupCompositing() ) );
}
} }
/*! /*!
@ -215,7 +223,7 @@ QRect Workspace::clientArea( clientAreaOption opt, const QPoint& p, int desktop
if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 ) if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 )
desktop = currentDesktop(); desktop = currentDesktop();
QDesktopWidget *desktopwidget = KApplication::desktop(); QDesktopWidget *desktopwidget = KApplication::desktop();
int screen = desktopwidget->isVirtualDesktop() ? desktopwidget->screenNumber( p ) : desktopwidget->primaryScreen(); int screen = desktopwidget->screenNumber( p );
if( screen < 0 ) if( screen < 0 )
screen = desktopwidget->primaryScreen(); screen = desktopwidget->primaryScreen();
QRect sarea = screenarea // may be NULL during KWin initialization QRect sarea = screenarea // may be NULL during KWin initialization
@ -1409,7 +1417,7 @@ void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, i
|| ns != size()) || ns != size())
{ {
QRect orig_geometry = geometry(); QRect orig_geometry = geometry();
GeometryUpdatesPostponer blocker( this ); GeometryUpdatesBlocker blocker( this );
move( new_pos ); move( new_pos );
plainResize( ns ); plainResize( ns );
setGeometry( QRect( calculateGravitation( false, gravity ), size())); setGeometry( QRect( calculateGravitation( false, gravity ), size()));
@ -1442,7 +1450,7 @@ void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, i
if( ns != size()) // don't restore if some app sets its own size again if( ns != size()) // don't restore if some app sets its own size again
{ {
QRect orig_geometry = geometry(); QRect orig_geometry = geometry();
GeometryUpdatesPostponer blocker( this ); GeometryUpdatesBlocker blocker( this );
int save_gravity = xSizeHint.win_gravity; int save_gravity = xSizeHint.win_gravity;
xSizeHint.win_gravity = gravity; xSizeHint.win_gravity = gravity;
resizeWithChecks( ns ); resizeWithChecks( ns );
@ -1662,31 +1670,46 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
{ {
client_size = QSize( w - border_left - border_right, h - border_top - border_bottom ); client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
} }
if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h )) if( force == NormalGeometrySet && geom == QRect( x, y, w, h ))
return; return;
frame_geometry = QRect( x, y, w, h ); geom = QRect( x, y, w, h );
updateWorkareaDiffs(); updateWorkareaDiffs();
if( postpone_geometry_updates != 0 ) if( block_geometry_updates != 0 )
{ {
pending_geometry_update = true; pending_geometry_update = true;
return; return;
} }
resizeDecoration( QSize( w, h )); if( geom_before_block.size() != geom.size())
XMoveResizeWindow( display(), frameId(), x, y, w, h );
// resizeDecoration( QSize( w, h ));
if( !isShade())
{ {
QSize cs = clientSize(); resizeDecoration( QSize( w, h ));
XMoveResizeWindow( display(), wrapperId(), clientPos().x(), clientPos().y(), XMoveResizeWindow( display(), frameId(), x, y, w, h );
cs.width(), cs.height()); if( !isShade())
XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height()); {
QSize cs = clientSize();
XMoveResizeWindow( display(), wrapperId(), clientPos().x(), clientPos().y(),
cs.width(), cs.height());
XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height());
}
if( shape())
updateShape();
} }
updateShape(); else
XMoveWindow( display(), frameId(), x, y );
// SELI TODO won't this be too expensive? // SELI TODO won't this be too expensive?
updateWorkareaDiffs(); updateWorkareaDiffs();
sendSyntheticConfigureNotify(); sendSyntheticConfigureNotify();
updateWindowRules(); updateWindowRules();
checkMaximizeGeometry(); checkMaximizeGeometry();
if( geom_before_block.size() != geom.size())
{
discardWindowPixmap();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
if( effects != NULL )
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geom_before_block );
}
addWorkspaceRepaint( geom_before_block );
geom_before_block = geom;
} }
void Client::plainResize( int w, int h, ForceGeometry_t force ) void Client::plainResize( int w, int h, ForceGeometry_t force )
@ -1716,11 +1739,11 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
kDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl; kDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl;
kDebug() << kBacktrace() << endl; kDebug() << kBacktrace() << endl;
} }
if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h )) if( force == NormalGeometrySet && geom.size() == QSize( w, h ))
return; return;
frame_geometry.setSize( QSize( w, h )); geom.setSize( QSize( w, h ));
updateWorkareaDiffs(); updateWorkareaDiffs();
if( postpone_geometry_updates != 0 ) if( block_geometry_updates != 0 )
{ {
pending_geometry_update = true; pending_geometry_update = true;
return; return;
@ -1735,11 +1758,19 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
cs.width(), cs.height()); cs.width(), cs.height());
XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height()); XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height());
} }
updateShape(); if( shape())
updateShape();
updateWorkareaDiffs(); updateWorkareaDiffs();
sendSyntheticConfigureNotify(); sendSyntheticConfigureNotify();
updateWindowRules(); updateWindowRules();
checkMaximizeGeometry(); checkMaximizeGeometry();
discardWindowPixmap();
if( scene != NULL )
scene->windowGeometryShapeChanged( this );
if( effects != NULL )
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geom_before_block );
addWorkspaceRepaint( geom_before_block );
geom_before_block = geom;
} }
/*! /*!
@ -1747,11 +1778,11 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
*/ */
void Client::move( int x, int y, ForceGeometry_t force ) void Client::move( int x, int y, ForceGeometry_t force )
{ {
if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y )) if( force == NormalGeometrySet && geom.topLeft() == QPoint( x, y ))
return; return;
frame_geometry.moveTopLeft( QPoint( x, y )); geom.moveTopLeft( QPoint( x, y ));
updateWorkareaDiffs(); updateWorkareaDiffs();
if( postpone_geometry_updates != 0 ) if( block_geometry_updates != 0 )
{ {
pending_geometry_update = true; pending_geometry_update = true;
return; return;
@ -1760,20 +1791,23 @@ void Client::move( int x, int y, ForceGeometry_t force )
sendSyntheticConfigureNotify(); sendSyntheticConfigureNotify();
updateWindowRules(); updateWindowRules();
checkMaximizeGeometry(); checkMaximizeGeometry();
// client itself is not damaged
addWorkspaceRepaint( geom_before_block );
addWorkspaceRepaint( geom ); // trigger repaint of window's new location
geom_before_block = geom;
} }
void Client::blockGeometryUpdates( bool block )
void Client::postponeGeometryUpdates( bool postpone )
{ {
if( postpone ) if( block )
{ {
if( postpone_geometry_updates == 0 ) if( block_geometry_updates == 0 )
pending_geometry_update = false; pending_geometry_update = false;
++postpone_geometry_updates; ++block_geometry_updates;
} }
else else
{ {
if( --postpone_geometry_updates == 0 ) if( --block_geometry_updates == 0 )
{ {
if( pending_geometry_update ) if( pending_geometry_update )
{ {
@ -1822,7 +1856,7 @@ void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
if( !adjust && max_mode == old_mode ) if( !adjust && max_mode == old_mode )
return; return;
GeometryUpdatesPostponer blocker( this ); GeometryUpdatesBlocker blocker( this );
// maximing one way and unmaximizing the other way shouldn't happen // maximing one way and unmaximizing the other way shouldn't happen
Q_ASSERT( !( vertical && horizontal ) Q_ASSERT( !( vertical && horizontal )
@ -2074,7 +2108,7 @@ void Client::setFullScreen( bool set, bool user )
if( was_fs == isFullScreen()) if( was_fs == isFullScreen())
return; return;
StackingUpdatesBlocker blocker1( workspace()); StackingUpdatesBlocker blocker1( workspace());
GeometryUpdatesPostponer blocker2( this ); GeometryUpdatesBlocker blocker2( this );
workspace()->updateClientLayer( this ); // active fullscreens get different layer workspace()->updateClientLayer( this ); // active fullscreens get different layer
info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen ); info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen );
updateDecoration( false, false ); updateDecoration( false, false );
@ -2230,7 +2264,7 @@ bool Client::startMoveResize()
XMapRaised( display(), move_resize_grab_window ); XMapRaised( display(), move_resize_grab_window );
if( XGrabPointer( display(), move_resize_grab_window, False, if( XGrabPointer( display(), move_resize_grab_window, False,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
GrabModeAsync, GrabModeAsync, move_resize_grab_window, cursor.handle(), xTime() ) == Success ) GrabModeAsync, GrabModeAsync, None, cursor.handle(), xTime() ) == Success )
has_grab = true; has_grab = true;
if( XGrabKeyboard( display(), frameId(), False, GrabModeAsync, GrabModeAsync, xTime() ) == Success ) if( XGrabKeyboard( display(), frameId(), False, GrabModeAsync, GrabModeAsync, xTime() ) == Success )
has_grab = true; has_grab = true;
@ -2260,6 +2294,10 @@ bool Client::startMoveResize()
// not needed anymore? kapp->installEventFilter( eater ); // not needed anymore? kapp->installEventFilter( eater );
} }
Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart ); Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->windowUserMovedResized( effectWindow(), true, false );
if( options->electricBorders() == Options::ElectricMoveOnly )
workspace()->reserveElectricBorderSwitching( true );
return true; return true;
} }
@ -2273,6 +2311,8 @@ void Client::finishMoveResize( bool cancel )
checkMaximizeGeometry(); checkMaximizeGeometry();
// FRAME update(); // FRAME update();
Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd ); Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->windowUserMovedResized( effectWindow(), false, true );
} }
void Client::leaveMoveResize() void Client::leaveMoveResize()
@ -2298,6 +2338,8 @@ void Client::leaveMoveResize()
moveResizeMode = false; moveResizeMode = false;
delete eater; delete eater;
eater = 0; eater = 0;
if( options->electricBorders() == Options::ElectricMoveOnly )
workspace()->reserveElectricBorderSwitching( false );
} }
// This function checks if it actually makes sense to perform a restricted move/resize. // This function checks if it actually makes sense to perform a restricted move/resize.
@ -2535,8 +2577,9 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
} // so the geometry tip will be painted above the outline } // so the geometry tip will be painted above the outline
} }
if ( isMove() ) if ( isMove() )
workspace()->clientMoved(globalPos, xTime()); workspace()->checkElectricBorder(globalPos, xTime());
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->windowUserMovedResized( effectWindow(), false, false );
} }
} // namespace } // namespace

View file

@ -11,13 +11,8 @@ License. See the file "COPYING" for the exact licensing terms.
#include "kwineffects.h" #include "kwineffects.h"
#include <QStringList> #include <QStringList>
#include <QFile>
#include "kdebug.h" #include "kdebug.h"
#include "klibloader.h"
#include "kdesktopfile.h"
#include "kconfiggroup.h"
#include "kstandarddirs.h"
#include <assert.h> #include <assert.h>
@ -212,113 +207,6 @@ EffectsHandler::~EffectsHandler()
assert( loaded_effects.count() == 0 ); assert( loaded_effects.count() == 0 );
} }
void EffectsHandler::windowUserMovedResized( EffectWindow* c, bool first, bool last )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowUserMovedResized( c, first, last );
}
void EffectsHandler::windowOpacityChanged( EffectWindow* c, double old_opacity )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowOpacityChanged( c, old_opacity );
}
void EffectsHandler::windowAdded( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowAdded( c );
}
void EffectsHandler::windowDeleted( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowDeleted( c );
}
void EffectsHandler::windowClosed( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowClosed( c );
}
void EffectsHandler::windowActivated( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowActivated( c );
}
void EffectsHandler::windowMinimized( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowMinimized( c );
}
void EffectsHandler::windowUnminimized( EffectWindow* c )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowUnminimized( c );
}
void EffectsHandler::desktopChanged( int old )
{
foreach( EffectPair ep, loaded_effects )
ep.second->desktopChanged( old );
}
void EffectsHandler::windowDamaged( EffectWindow* w, const QRect& r )
{
if( w == NULL )
return;
foreach( EffectPair ep, loaded_effects )
ep.second->windowDamaged( w, r );
}
void EffectsHandler::windowGeometryShapeChanged( EffectWindow* w, const QRect& old )
{
if( w == NULL ) // during late cleanup effectWindow() may be already NULL
return; // in some functions that may still call this
foreach( EffectPair ep, loaded_effects )
ep.second->windowGeometryShapeChanged( w, old );
}
void EffectsHandler::tabBoxAdded( int mode )
{
foreach( EffectPair ep, loaded_effects )
ep.second->tabBoxAdded( mode );
}
void EffectsHandler::tabBoxClosed()
{
foreach( EffectPair ep, loaded_effects )
ep.second->tabBoxClosed();
}
void EffectsHandler::tabBoxUpdated()
{
foreach( EffectPair ep, loaded_effects )
ep.second->tabBoxUpdated();
}
bool EffectsHandler::borderActivated( ElectricBorder border )
{
bool ret = false;
foreach( EffectPair ep, loaded_effects )
if( ep.second->borderActivated( border ))
ret = true; // bail out or tell all?
return ret;
}
// start another painting pass
void EffectsHandler::startPaint()
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_transform == 0 );
}
QRect EffectsHandler::transformWindowDamage( EffectWindow* w, const QRect& r ) QRect EffectsHandler::transformWindowDamage( EffectWindow* w, const QRect& r )
{ {
if( current_transform < loaded_effects.size()) if( current_transform < loaded_effects.size())
@ -341,106 +229,6 @@ Window EffectsHandler::createFullScreenInputWindow( Effect* e, const QCursor& cu
return createInputWindow( e, 0, 0, displayWidth(), displayHeight(), cursor ); return createInputWindow( e, 0, 0, displayWidth(), displayHeight(), cursor );
} }
KLibrary* EffectsHandler::findEffectLibrary( const QString& effectname )
{
QString libname = "kwin4_effect_" + effectname.toLower();
QString desktopfile = KStandardDirs::locate("appdata",
"effects/" + effectname.toLower() + ".desktop");
if( !desktopfile.isEmpty() )
{
KDesktopFile desktopconf( desktopfile );
KConfigGroup conf = desktopconf.desktopGroup();
libname = conf.readEntry( "X-KDE-Library", libname );
}
KLibrary* library = KLibLoader::self()->library(QFile::encodeName(libname));
if( !library )
{
kError( 1212 ) << k_funcinfo << "couldn't open library for effect '" <<
effectname << "'" << endl;
return 0;
}
return library;
}
void EffectsHandler::loadEffect( const QString& name )
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_transform == 0 );
// Make sure a single effect won't be loaded multiple times
for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); it++)
{
if( (*it).first == name )
{
kDebug( 1212 ) << "EffectsHandler::loadEffect : Effect already loaded : " << name << endl;
return;
}
}
kDebug( 1212 ) << k_funcinfo << "Trying to load " << name << endl;
KLibrary* library = findEffectLibrary( name );
if( !library )
{
return;
}
QString supported_symbol = "effect_supported_" + name;
KLibrary::void_function_ptr supported_func = library->resolveFunction(supported_symbol.toAscii().data());
QString create_symbol = "effect_create_" + name;
KLibrary::void_function_ptr create_func = library->resolveFunction(create_symbol.toAscii().data());
if( supported_func )
{
typedef bool (*t_supportedfunc)();
t_supportedfunc supported = reinterpret_cast<t_supportedfunc>(supported_func);
if(!supported())
{
kWarning( 1212 ) << "EffectsHandler::loadEffect : Effect " << name << " is not supported" << endl;
library->unload();
return;
}
}
if(!create_func)
{
kError( 1212 ) << "EffectsHandler::loadEffect : effect_create function not found" << endl;
library->unload();
return;
}
typedef Effect* (*t_createfunc)();
t_createfunc create = reinterpret_cast<t_createfunc>(create_func);
Effect* e = create();
loaded_effects.append( EffectPair( name, e ) );
effect_libraries[ name ] = library;
}
void EffectsHandler::unloadEffect( const QString& name )
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
assert( current_transform == 0 );
for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); it++)
{
if ( (*it).first == name )
{
kDebug( 1212 ) << "EffectsHandler::unloadEffect : Unloading Effect : " << name << endl;
delete (*it).second;
loaded_effects.erase(it);
effect_libraries[ name ]->unload();
return;
}
}
kDebug( 1212 ) << "EffectsHandler::unloadEffect : Effect not loaded : " << name << endl;
}
EffectsHandler* effects = 0; EffectsHandler* effects = 0;

View file

@ -188,35 +188,9 @@ class KWIN_EXPORT EffectsHandler
virtual void addRepaint( const QRect& r ) = 0; virtual void addRepaint( const QRect& r ) = 0;
virtual void addRepaint( int x, int y, int w, int h ) = 0; virtual void addRepaint( int x, int y, int w, int h ) = 0;
// internal (used by kwin core or compositing code)
virtual void startPaint();
virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last );
virtual void windowOpacityChanged( EffectWindow* c, double old_opacity );
virtual void windowAdded( EffectWindow* c );
virtual void windowClosed( EffectWindow* c );
virtual void windowDeleted( EffectWindow* c );
virtual void windowActivated( EffectWindow* c );
virtual void windowMinimized( EffectWindow* c );
virtual void windowUnminimized( EffectWindow* c );
virtual bool checkInputWindowEvent( XEvent* e ) = 0;
virtual void checkInputWindowStacking() = 0;
virtual void desktopChanged( int old );
virtual void windowDamaged( EffectWindow* w, const QRect& r );
virtual void windowGeometryShapeChanged( EffectWindow* w, const QRect& old );
virtual void tabBoxAdded( int mode );
virtual void tabBoxClosed();
virtual void tabBoxUpdated();
virtual bool borderActivated( ElectricBorder border );
CompositingType compositingType() const { return compositing_type; } CompositingType compositingType() const { return compositing_type; }
virtual unsigned long xrenderBufferPicture() = 0; virtual unsigned long xrenderBufferPicture() = 0;
//void registerEffect( const QString& name, EffectFactory* factory );
void loadEffect( const QString& name );
void unloadEffect( const QString& name );
protected:
KLibrary* findEffectLibrary( const QString& effectname );
protected: protected:
QVector< EffectPair > loaded_effects; QVector< EffectPair > loaded_effects;

View file

@ -93,7 +93,7 @@ void Scene::paintScreen( int* mask, QRegion* region )
? 0 : PAINT_SCREEN_REGION; ? 0 : PAINT_SCREEN_REGION;
updateTimeDiff(); updateTimeDiff();
// preparation step // preparation step
effects->startPaint(); static_cast<EffectsHandlerImpl*>(effects)->startPaint();
effects->prePaintScreen( mask, region, time_diff ); effects->prePaintScreen( mask, region, time_diff );
if( *mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS )) if( *mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS ))
{ // Region painting is not possible with transformations, { // Region painting is not possible with transformations,

View file

@ -12,6 +12,7 @@ License. See the file "COPYING" for the exact licensing terms.
//#define QT_CLEAN_NAMESPACE //#define QT_CLEAN_NAMESPACE
#include "tabbox.h" #include "tabbox.h"
#include "workspace.h" #include "workspace.h"
#include "effects.h"
#include "client.h" #include "client.h"
#include <QPainter> #include <QPainter>
#include <QLabel> #include <QLabel>
@ -24,7 +25,6 @@ License. See the file "COPYING" for the exact licensing terms.
#include <QApplication> #include <QApplication>
#include <qdesktopwidget.h> #include <qdesktopwidget.h>
#include <QCursor> #include <QCursor>
#include <kstringhandler.h>
#include <stdarg.h> #include <stdarg.h>
#include <kdebug.h> #include <kdebug.h>
#include <kglobalsettings.h> #include <kglobalsettings.h>
@ -43,39 +43,30 @@ namespace KWin
extern QPixmap* kwin_get_menu_pix_hack(); extern QPixmap* kwin_get_menu_pix_hack();
TabBox::TabBox( Workspace *ws, const char *name ) TabBox::TabBox( Workspace *ws )
: Q3Frame( 0, name, Qt::WNoAutoErase ), current_client( NULL ), wspace(ws) : QFrame( 0, Qt::X11BypassWindowManagerHint )
, wspace(ws)
, client(0)
, display_refcount( 0 )
{ {
setFrameStyle(QFrame::StyledPanel | QFrame::Plain); setFrameStyle(QFrame::StyledPanel);
setFrameShadow(QFrame::Plain);
setBackgroundRole(QPalette::Base);
setLineWidth(2); setLineWidth(2);
setMargin(2); setContentsMargins( 2, 2, 2, 2 );
showMiniIcon = false; showMiniIcon = false;
no_tasks = i18n("*** No Windows ***"); no_tasks = i18n("*** No Windows ***");
m = DesktopMode; // init variables m = DesktopMode; // init variables
updateKeyMapping();
reconfigure(); reconfigure();
reset(); reset();
connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show())); connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show()));
XSetWindowAttributes attr;
attr.override_redirect = 1;
outline_left = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
outline_right = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
outline_top = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
outline_bottom = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
} }
TabBox::~TabBox() TabBox::~TabBox()
{ {
XDestroyWindow( display(), outline_left );
XDestroyWindow( display(), outline_right );
XDestroyWindow( display(), outline_top );
XDestroyWindow( display(), outline_bottom );
} }
@ -102,7 +93,7 @@ void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client
Client* start = c; Client* start = c;
if ( chain ) if ( chain )
c = workspace()->nextFocusChainClient(c); c = workspace()->nextClientFocusChain(c);
else else
c = workspace()->stackingOrder().first(); c = workspace()->stackingOrder().first();
@ -125,15 +116,11 @@ void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client
list += c; list += c;
else if( !list.contains( modal )) else if( !list.contains( modal ))
list += modal; list += modal;
else
{
// nothing
}
} }
} }
if ( chain ) if ( chain )
c = workspace()->nextFocusChainClient( c ); c = workspace()->nextClientFocusChain( c );
else else
{ {
if ( idx >= (workspace()->stackingOrder().size()-1) ) if ( idx >= (workspace()->stackingOrder().size()-1) )
@ -148,15 +135,39 @@ void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client
} }
/*!
Create list of desktops, starting with desktop start
*/
void TabBox::createDesktopList(QList< int > &list, int start, SortOrder order)
{
list.clear();
int iDesktop = start;
for( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
{
list.append( iDesktop );
if ( order == StaticOrder )
{
iDesktop = workspace()->nextDesktopStatic( iDesktop );
}
else
{ // MostRecentlyUsedOrder
iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
}
}
}
/*! /*!
Resets the tab box to display the active client in WindowsMode, or the Resets the tab box to display the active client in WindowsMode, or the
current desktop in DesktopListMode current desktop in DesktopListMode
*/ */
void TabBox::reset() void TabBox::reset( bool partial_reset )
{ {
int w, h, cw = 0, wmax = 0; int w, h, cw = 0, wmax = 0;
QRect r = KGlobalSettings::desktopGeometry(QCursor::pos()); QRect r = KGlobalSettings::desktopGeometry(cursorPos());
// calculate height of 1 line // calculate height of 1 line
// fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below
@ -164,10 +175,14 @@ void TabBox::reset()
if ( mode() == WindowsMode ) if ( mode() == WindowsMode )
{ {
setCurrentClient( workspace()->activeClient()); Client* starting_client = 0;
if( partial_reset && clients.count() != 0 )
starting_client = clients.first();
else
client = starting_client = workspace()->activeClient();
// get all clients to show // get all clients to show
createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), current_client, true); createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), starting_client, true);
// calculate maximum caption width // calculate maximum caption width
cw = fontMetrics().width(no_tasks)+20; cw = fontMetrics().width(no_tasks)+20;
@ -212,18 +227,32 @@ void TabBox::reset()
} }
} }
else else
{ // DesktopListMode {
showMiniIcon = false; int starting_desktop;
desk = workspace()->currentDesktop(); if( mode() == DesktopListMode )
{
starting_desktop = 1;
createDesktopList(desktops, starting_desktop, StaticOrder );
}
else
{ // DesktopMode
starting_desktop = workspace()->currentDesktop();
createDesktopList(desktops, starting_desktop, MostRecentlyUsedOrder );
}
for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ ) if( !partial_reset )
desk = workspace()->currentDesktop();
showMiniIcon = false;
foreach (int it, desktops)
{ {
cw = fontMetrics().width( workspace()->desktopName(i) ); cw = fontMetrics().width( workspace()->desktopName(it) );
if ( cw > wmax ) wmax = cw; if ( cw > wmax ) wmax = cw;
} }
// calculate height for the popup (max. 16 desktops always fit in a 800x600 screen) // calculate height for the popup (max. 16 desktops always fit in a 800x600 screen)
h = workspace()->numberOfDesktops() * lineHeight; h = desktops.count() * lineHeight;
} }
// height, width for the popup // height, width for the popup
@ -234,6 +263,9 @@ void TabBox::reset()
setGeometry( (r.width()-w)/2 + r.x(), setGeometry( (r.width()-w)/2 + r.x(),
(r.height()-h)/2+ r.y(), (r.height()-h)/2+ r.y(),
w, h ); w, h );
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
} }
@ -244,52 +276,42 @@ void TabBox::nextPrev( bool next)
{ {
if ( mode() == WindowsMode ) if ( mode() == WindowsMode )
{ {
Client* firstClient = NULL; Client* firstClient = 0;
Client* client = current_client; Client* newClient = client;
do do
{ {
if ( next ) if ( next )
client = workspace()->nextFocusChainClient(client); newClient = workspace()->nextClientFocusChain(newClient);
else else
client = workspace()->previousFocusChainClient(client); newClient = workspace()->previousClientFocusChain(newClient);
if (!firstClient) if (!firstClient)
{ {
// When we see our first client for the second time, // When we see our first client for the second time,
// it's time to stop. // it's time to stop.
firstClient = client; firstClient = newClient;
} }
else if (client == firstClient) else if (newClient == firstClient)
{ {
// No candidates found. // No candidates found.
client = 0; newClient = 0;
break; break;
} }
} while ( client && !clients.contains( client )); } while ( newClient && !clients.contains( newClient ));
setCurrentClient( client ); setCurrentClient( newClient );
} }
else if( mode() == DesktopMode ) else if( mode() == DesktopMode )
{ {
if ( next ) setCurrentDesktop ( next ? workspace()->nextDesktopFocusChain( desk )
desk = workspace()->nextDesktopFocusChain( desk ); : workspace()->previousDesktopFocusChain( desk ) );
else
desk = workspace()->previousDesktopFocusChain( desk );
} }
else else
{ // DesktopListMode { // DesktopListMode
if ( next ) setCurrentDesktop ( next ? workspace()->nextDesktopStatic( desk )
{ : workspace()->previousDesktopStatic( desk )) ;
desk++;
if ( desk > workspace()->numberOfDesktops() )
desk = 1;
}
else
{
desk--;
if ( desk < 1 )
desk = workspace()->numberOfDesktops();
}
} }
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
update(); update();
} }
@ -303,20 +325,24 @@ Client* TabBox::currentClient()
{ {
if ( mode() != WindowsMode ) if ( mode() != WindowsMode )
return 0; return 0;
if (!workspace()->hasClient( current_client )) if (!workspace()->hasClient( client ))
return 0; return 0;
return current_client; return client;
} }
void TabBox::setCurrentClient( Client* c ) /*!
Returns the list of clients potentially displayed ( only works in
WindowsMode ).
Returns an empty list if no clients are available.
*/
ClientList TabBox::currentClientList()
{ {
if( current_client != c ) if( mode() != WindowsMode )
{ return ClientList();
current_client = c; return clients;
updateOutline();
}
} }
/*! /*!
Returns the currently displayed virtual desktop ( only works in Returns the currently displayed virtual desktop ( only works in
DesktopListMode ) DesktopListMode )
@ -326,21 +352,52 @@ int TabBox::currentDesktop()
{ {
if ( mode() == DesktopListMode || mode() == DesktopMode ) if ( mode() == DesktopListMode || mode() == DesktopMode )
return desk; return desk;
else return -1;
return -1;
} }
/*!
Returns the list of desktops potentially displayed ( only works in
DesktopListMode )
Returns an empty list if no desktops are available.
*/
QList< int > TabBox::currentDesktopList()
{
if ( mode() == DesktopListMode || mode() == DesktopMode )
return desktops;
return QList< int >();
}
/*!
Change the currently selected client, and notify the effects.
\sa setCurrentDesktop()
*/
void TabBox::setCurrentClient( Client* newClient )
{
client = newClient;
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
}
/*!
Change the currently selected desktop, and notify the effects.
\sa setCurrentClient()
*/
void TabBox::setCurrentDesktop( int newDesktop )
{
desk = newDesktop;
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
}
/*! /*!
Reimplemented to raise the tab box as well Reimplemented to raise the tab box as well
*/ */
void TabBox::showEvent( QShowEvent* ) void TabBox::showEvent( QShowEvent* )
{ {
updateOutline();
XRaiseWindow( display(), outline_left );
XRaiseWindow( display(), outline_right );
XRaiseWindow( display(), outline_top );
XRaiseWindow( display(), outline_bottom );
raise(); raise();
} }
@ -350,29 +407,23 @@ void TabBox::showEvent( QShowEvent* )
*/ */
void TabBox::hideEvent( QHideEvent* ) void TabBox::hideEvent( QHideEvent* )
{ {
XUnmapWindow( display(), outline_left );
XUnmapWindow( display(), outline_right );
XUnmapWindow( display(), outline_top );
XUnmapWindow( display(), outline_bottom );
} }
/*! /*!
Paints the tab box Paints the tab box
*/ */
void TabBox::drawContents( QPainter * ) void TabBox::paintEvent( QPaintEvent* e )
{ {
QRect r(contentsRect()); QFrame::paintEvent( e );
QPixmap pix(r.size()); // do double buffering to avoid flickers
pix.fill(this, 0, 0);
QPainter p; QPainter p( this );
p.begin(&pix); QRect r( contentsRect());
QPixmap* menu_pix = kwin_get_menu_pix_hack(); QPixmap* menu_pix = kwin_get_menu_pix_hack();
int iconWidth = showMiniIcon ? 16 : 32; int iconWidth = showMiniIcon ? 16 : 32;
int x = 0; int x = r.x();
int y = 0; int y = r.y();
if ( mode () == WindowsMode ) if ( mode () == WindowsMode )
{ {
@ -392,7 +443,7 @@ void TabBox::drawContents( QPainter * )
if ( workspace()->hasClient( *it ) ) // safety if ( workspace()->hasClient( *it ) ) // safety
{ {
// draw highlight background // draw highlight background
if ( (*it) == current_client ) if ( (*it) == currentClient() )
p.fillRect(x, y, r.width(), lineHeight, palette().brush( QPalette::Highlight )); p.fillRect(x, y, r.width(), lineHeight, palette().brush( QPalette::Highlight ));
// draw icon // draw icon
@ -426,10 +477,10 @@ void TabBox::drawContents( QPainter * )
else else
s += (*it)->caption(); s += (*it)->caption();
s = fontMetrics().elidedText(s, Qt::ElideMiddle, r.width() - 5 - iconWidth - 8); s = fontMetrics().elidedText( s, Qt::ElideMiddle, r.width() - 5 - iconWidth - 8 );
// draw text // draw text
if ( (*it) == current_client ) if ( (*it) == currentClient() )
p.setPen(palette().color( QPalette::HighlightedText )); p.setPen(palette().color( QPalette::HighlightedText ));
else if( (*it)->isMinimized()) else if( (*it)->isMinimized())
{ {
@ -471,22 +522,19 @@ void TabBox::drawContents( QPainter * )
QFontMetrics fm(f); QFontMetrics fm(f);
int wmax = 0; int wmax = 0;
for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ ) foreach (int it, desktops)
{ {
wmax = qMax(wmax, fontMetrics().width(workspace()->desktopName(i))); wmax = qMax(wmax, fontMetrics().width(workspace()->desktopName(it)));
// calculate max width of desktop-number text // calculate max width of desktop-number text
QString num = QString::number(i); QString num = QString::number(it);
iconWidth = qMax(iconWidth - 4, fm.boundingRect(num).width()) + 4; iconWidth = qMax(iconWidth - 4, fm.boundingRect(num).width()) + 4;
} }
// In DesktopMode, start at the current desktop foreach (int it, desktops)
// In DesktopListMode, start at desktop #1
int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
{ {
// draw highlight background // draw highlight background
if ( iDesktop == desk ) // current desktop if ( it == desk ) // current desktop
p.fillRect(x, y, r.width(), lineHeight, palette().brush( QPalette::Highlight )); p.fillRect(x, y, r.width(), lineHeight, palette().brush( QPalette::Highlight ));
p.save(); p.save();
@ -498,28 +546,28 @@ void TabBox::drawContents( QPainter * )
// draw desktop-number // draw desktop-number
p.setFont(f); p.setFont(f);
QString num = QString::number(iDesktop); QString num = QString::number(it);
p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num); p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num);
p.restore(); p.restore();
// draw desktop name text // draw desktop name text
if ( iDesktop == desk ) if ( it == desk )
p.setPen(palette().color( QPalette::HighlightedText )); p.setPen(palette().color( QPalette::HighlightedText ));
else else
p.setPen(palette().color( QPalette::Text )); p.setPen(palette().color( QPalette::Text ));
p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight, p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
workspace()->desktopName(iDesktop)); workspace()->desktopName(it));
// show mini icons from that desktop aligned to each other // show mini icons from that desktop aligned to each other
int x1 = x + 5 + iconWidth + 8 + wmax + 5; int x1 = x + 5 + iconWidth + 8 + wmax + 5;
ClientList list; ClientList list;
createClientList(list, iDesktop, 0, false); createClientList(list, it, 0, false);
// clients are in reversed stacking order // clients are in reversed stacking order
for ( int i = list.size() - 1; i>=0; i-- ) for ( int i = list.size() - 1; i>=0; i-- )
{ {
if ( !list.at( i )->miniIcon().isNull() ) if ( !list.at( i )->miniIcon().isNull() )
{ {
@ -534,107 +582,38 @@ void TabBox::drawContents( QPainter * )
// next desktop // next desktop
y += lineHeight; y += lineHeight;
if ( y >= r.height() ) break; if ( y >= r.height() ) break;
if( mode() == DesktopMode )
iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
else
iDesktop++;
} }
} }
p.end();
QPainter localPainter( this );
localPainter.drawImage( QPoint( r.x(), r.y() ), pix.toImage() );
} }
void TabBox::updateOutline()
/*!
Notify effects that the tab box is being shown, and only display the
default tab box QFrame if no effect has referenced the tab box.
*/
void TabBox::show()
{ {
Client* c = currentClient(); if( effects )
if( c == NULL || this->isHidden() || !c->isShown( true ) || !c->isOnCurrentDesktop()) static_cast<EffectsHandlerImpl*>(effects)->tabBoxAdded( mode());
{ if( isDisplayed())
XUnmapWindow( display(), outline_left );
XUnmapWindow( display(), outline_right );
XUnmapWindow( display(), outline_top );
XUnmapWindow( display(), outline_bottom );
return; return;
} refDisplay();
// left/right parts are between top/bottom, they don't reach as far as the corners QWidget::show();
XMoveResizeWindow( display(), outline_left, c->x(), c->y() + 5, 5, c->height() - 10 );
XMoveResizeWindow( display(), outline_right, c->x() + c->width() - 5, c->y() + 5, 5, c->height() - 10 );
XMoveResizeWindow( display(), outline_top, c->x(), c->y(), c->width(), 5 );
XMoveResizeWindow( display(), outline_bottom, c->x(), c->y() + c->height() - 5, c->width(), 5 );
{
QPixmap pix( 5, c->height() - 10 );
QPainter p( &pix );
p.setPen( Qt::white );
p.drawLine( 0, 0, 0, pix.height() - 1 );
p.drawLine( 4, 0, 4, pix.height() - 1 );
p.setPen( Qt::gray );
p.drawLine( 1, 0, 1, pix.height() - 1 );
p.drawLine( 3, 0, 3, pix.height() - 1 );
p.setPen( Qt::black );
p.drawLine( 2, 0, 2, pix.height() - 1 );
p.end();
XSetWindowBackgroundPixmap( display(), outline_left, pix.handle());
XSetWindowBackgroundPixmap( display(), outline_right, pix.handle());
}
{
QPixmap pix( c->width(), 5 );
QPainter p( &pix );
p.setPen( Qt::white );
p.drawLine( 0, 0, pix.width() - 1 - 0, 0 );
p.drawLine( 4, 4, pix.width() - 1 - 4, 4 );
p.drawLine( 0, 0, 0, 4 );
p.drawLine( pix.width() - 1 - 0, 0, pix.width() - 1 - 0, 4 );
p.setPen( Qt::gray );
p.drawLine( 1, 1, pix.width() - 1 - 1, 1 );
p.drawLine( 3, 3, pix.width() - 1 - 3, 3 );
p.drawLine( 1, 1, 1, 4 );
p.drawLine( 3, 3, 3, 4 );
p.drawLine( pix.width() - 1 - 1, 1, pix.width() - 1 - 1, 4 );
p.drawLine( pix.width() - 1 - 3, 3, pix.width() - 1 - 3, 4 );
p.setPen( Qt::black );
p.drawLine( 2, 2, pix.width() - 1 - 2, 2 );
p.drawLine( 2, 2, 2, 4 );
p.drawLine( pix.width() - 1 - 2, 2, pix.width() - 1 - 2, 4 );
p.end();
XSetWindowBackgroundPixmap( display(), outline_top, pix.handle());
}
{
QPixmap pix( c->width(), 5 );
QPainter p( &pix );
p.setPen( Qt::white );
p.drawLine( 4, 0, pix.width() - 1 - 4, 0 );
p.drawLine( 0, 4, pix.width() - 1 - 0, 4 );
p.drawLine( 0, 4, 0, 0 );
p.drawLine( pix.width() - 1 - 0, 4, pix.width() - 1 - 0, 0 );
p.setPen( Qt::gray );
p.drawLine( 3, 1, pix.width() - 1 - 3, 1 );
p.drawLine( 1, 3, pix.width() - 1 - 1, 3 );
p.drawLine( 3, 1, 3, 0 );
p.drawLine( 1, 3, 1, 0 );
p.drawLine( pix.width() - 1 - 3, 1, pix.width() - 1 - 3, 0 );
p.drawLine( pix.width() - 1 - 1, 3, pix.width() - 1 - 1, 0 );
p.setPen( Qt::black );
p.drawLine( 2, 2, pix.width() - 1 - 2, 2 );
p.drawLine( 2, 0, 2, 2 );
p.drawLine( pix.width() - 1 - 2, 0, pix.width() - 1 - 2 , 2 );
p.end();
XSetWindowBackgroundPixmap( display(), outline_bottom, pix.handle());
}
XClearWindow( display(), outline_left );
XClearWindow( display(), outline_right );
XClearWindow( display(), outline_top );
XClearWindow( display(), outline_bottom );
XMapWindow( display(), outline_left );
XMapWindow( display(), outline_right );
XMapWindow( display(), outline_top );
XMapWindow( display(), outline_bottom );
} }
/*!
Notify effects that the tab box is being hidden.
*/
void TabBox::hide() void TabBox::hide()
{ {
delayedShowTimer.stop(); delayedShowTimer.stop();
if( isVisible())
unrefDisplay();
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->tabBoxClosed();
if( isDisplayed())
kDebug( 1212 ) << "Tab box was not properly closed by an effect" << endl;
QWidget::hide(); QWidget::hide();
QApplication::syncX(); QApplication::syncX();
XEvent otherEvent; XEvent otherEvent;
@ -643,6 +622,15 @@ void TabBox::hide()
} }
/*!
Decrease the reference count. Only when the reference count is 0 will
the default tab box be shown.
*/
void TabBox::unrefDisplay()
{
--display_refcount;
}
void TabBox::reconfigure() void TabBox::reconfigure()
{ {
KSharedConfigPtr c(KGlobal::config()); KSharedConfigPtr c(KGlobal::config());
@ -688,17 +676,24 @@ void TabBox::delayedShow()
void TabBox::handleMouseEvent( XEvent* e ) void TabBox::handleMouseEvent( XEvent* e )
{ {
XAllowEvents( display(), AsyncPointer, xTime() ); XAllowEvents( display(), AsyncPointer, xTime() );
if( !isVisible() && isDisplayed())
{ // tabbox has been replaced, check effects
if( effects && static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowEvent( e ))
return;
}
if( e->type != ButtonPress ) if( e->type != ButtonPress )
return; return;
QPoint pos( e->xbutton.x_root, e->xbutton.y_root ); QPoint pos( e->xbutton.x_root, e->xbutton.y_root );
if( !geometry().contains( pos )) QPoint widgetPos = mapFromGlobal( pos ); // inside tabbox
if(( !isVisible() && isDisplayed())
|| !geometry().contains( pos ))
{ {
workspace()->closeTabBox(); // click outside closes tab workspace()->closeTabBox(); // click outside closes tab
return; return;
} }
pos.rx() -= x(); // pos is now inside tabbox
pos.ry() -= y(); int num = (widgetPos.y()-frameWidth()) / lineHeight;
int num = (pos.y()-frameWidth()) / lineHeight;
if( mode() == WindowsMode ) if( mode() == WindowsMode )
{ {
@ -716,21 +711,14 @@ void TabBox::handleMouseEvent( XEvent* e )
} }
else else
{ {
int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1; foreach( int it, desktops )
for( int i = 1;
i <= workspace()->numberOfDesktops();
++i )
{ {
if( num == 0 ) if( num == 0 )
{ {
desk = iDesktop; setCurrentDesktop( it );
break; break;
} }
num--; num--;
if( mode() == DesktopMode )
iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
else
iDesktop++;
} }
} }
update(); update();
@ -788,12 +776,16 @@ bool areKeySymXsDepressed( bool bAll, const uint keySyms[], int nKeySyms )
return bAll; return bAll;
} }
static const int MAX_KEYSYMS = 4;
static uint alt_keysyms[ MAX_KEYSYMS ];
static uint win_keysyms[ MAX_KEYSYMS ];
static bool areModKeysDepressed( const QKeySequence& seq ) static bool areModKeysDepressed( const QKeySequence& seq )
{ {
uint rgKeySyms[10]; uint rgKeySyms[10];
int nKeySyms = 0; int nKeySyms = 0;
if( seq.isEmpty()) if( seq.isEmpty())
return false; return false;
int mod = seq[seq.count()-1] & Qt::KeyboardModifierMask; int mod = seq[seq.count()-1] & Qt::KeyboardModifierMask;
if ( mod & Qt::SHIFT ) if ( mod & Qt::SHIFT )
@ -808,18 +800,17 @@ static bool areModKeysDepressed( const QKeySequence& seq )
} }
if( mod & Qt::ALT ) if( mod & Qt::ALT )
{ {
rgKeySyms[nKeySyms++] = XK_Alt_L; for( int i = 0;
rgKeySyms[nKeySyms++] = XK_Alt_R; i < MAX_KEYSYMS && alt_keysyms[ i ] != NoSymbol;
++i )
rgKeySyms[nKeySyms++] = alt_keysyms[ i ];
} }
if( mod & Qt::META ) if( mod & Qt::META )
{ {
// It would take some code to determine whether the Win key for( int i = 0;
// is associated with Super or Meta, so check for both. i < MAX_KEYSYMS && win_keysyms[ i ] != NoSymbol;
// See bug #140023 for details. ++i )
rgKeySyms[nKeySyms++] = XK_Super_L; rgKeySyms[nKeySyms++] = win_keysyms[ i ];
rgKeySyms[nKeySyms++] = XK_Super_R;
rgKeySyms[nKeySyms++] = XK_Meta_L;
rgKeySyms[nKeySyms++] = XK_Meta_R;
} }
return areKeySymXsDepressed( false, rgKeySyms, nKeySyms ); return areKeySymXsDepressed( false, rgKeySyms, nKeySyms );
@ -833,6 +824,44 @@ static bool areModKeysDepressed( const KShortcut& cut )
return false; return false;
} }
void TabBox::updateKeyMapping()
{
const int size = 6;
uint keysyms[ size ] = { XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R, XK_Meta_L, XK_Meta_R };
XModifierKeymap* map = XGetModifierMapping( display() );
int altpos = 0;
int winpos = 0;
int winmodpos = -1;
int winmod = KKeyServer::modXMeta();
while( winmod > 0 ) // get position of the set bit in winmod
{
winmod >>= 1;
++winmodpos;
}
for( int i = 0;
i < MAX_KEYSYMS;
++i )
alt_keysyms[ i ] = win_keysyms[ i ] = NoSymbol;
for( int i = 0;
i < size;
++i )
{
KeyCode keycode = XKeysymToKeycode( display(), keysyms[ i ] );
for( int j = 0;
j < map->max_keypermod;
++j )
{
if( map->modifiermap[ 3 * map->max_keypermod + j ] == keycode ) // Alt
if( altpos < MAX_KEYSYMS )
alt_keysyms[ altpos++ ] = keysyms[ i ];
if( winmodpos >= 0 && map->modifiermap[ winmodpos * map->max_keypermod + j ] == keycode )
if( winpos < MAX_KEYSYMS )
win_keysyms[ winpos++ ] = keysyms[ i ];
}
}
XFreeModifiermap( map );
}
void Workspace::slotWalkThroughWindows() void Workspace::slotWalkThroughWindows()
{ {
if ( root != rootWindow() ) if ( root != rootWindow() )
@ -956,7 +985,7 @@ bool Workspace::startKDEWalkThroughWindows()
{ {
if( !establishTabBoxGrab()) if( !establishTabBoxGrab())
return false; return false;
tab_grab = true; tab_grab = true;
keys->setEnabled( false ); keys->setEnabled( false );
disable_shortcuts_keys->setEnabled( false ); disable_shortcuts_keys->setEnabled( false );
client_keys->setEnabled( false ); client_keys->setEnabled( false );
@ -1030,7 +1059,7 @@ void Workspace::CDEWalkThroughWindows( bool forward )
Client* firstClient = 0; Client* firstClient = 0;
do do
{ {
nc = forward ? nextStaticClient(nc) : previousStaticClient(nc); nc = forward ? nextClientStatic(nc) : previousClientStatic(nc);
if (!firstClient) if (!firstClient)
{ {
// When we see our first client for the second time, // When we see our first client for the second time,
@ -1136,6 +1165,18 @@ void Workspace::tabBoxKeyPress( int keyQt )
} }
} }
void Workspace::refTabBox()
{
if( tab_box )
tab_box->refDisplay();
}
void Workspace::unrefTabBox()
{
if( tab_box )
tab_box->unrefDisplay();
}
void Workspace::closeTabBox() void Workspace::closeTabBox()
{ {
removeTabBoxGrab(); removeTabBoxGrab();
@ -1187,12 +1228,9 @@ void Workspace::tabBoxKeyRelease( const XKeyEvent& ev )
return; return;
if (tab_grab) if (tab_grab)
{ {
removeTabBoxGrab(); bool old_control_grab = control_grab;
tab_box->hide(); closeTabBox();
keys->setEnabled( true ); control_grab = old_control_grab;
disable_shortcuts_keys->setEnabled( true );
client_keys->setEnabled( true );
tab_grab = false;
if( Client* c = tab_box->currentClient()) if( Client* c = tab_box->currentClient())
{ {
activateClient( c ); activateClient( c );
@ -1202,12 +1240,9 @@ void Workspace::tabBoxKeyRelease( const XKeyEvent& ev )
} }
if (control_grab) if (control_grab)
{ {
removeTabBoxGrab(); bool old_tab_grab = tab_grab;
tab_box->hide(); closeTabBox();
keys->setEnabled( true ); tab_grab = old_tab_grab;
disable_shortcuts_keys->setEnabled( true );
client_keys->setEnabled( true );
control_grab = False;
if ( tab_box->currentDesktop() != -1 ) if ( tab_box->currentDesktop() != -1 )
{ {
setCurrentDesktop( tab_box->currentDesktop() ); setCurrentDesktop( tab_box->currentDesktop() );
@ -1238,11 +1273,27 @@ int Workspace::previousDesktopFocusChain( int iDesktop ) const
return numberOfDesktops(); return numberOfDesktops();
} }
int Workspace::nextDesktopStatic( int iDesktop ) const
{
int i = ++iDesktop;
if( i > numberOfDesktops())
i = 1;
return i;
}
int Workspace::previousDesktopStatic( int iDesktop ) const
{
int i = --iDesktop;
if( i < 1 )
i = numberOfDesktops();
return i;
}
/*! /*!
auxiliary functions to travers all clients according the focus auxiliary functions to travers all clients according the focus
order. Useful for kwms Alt-tab feature. order. Useful for kwms Alt-tab feature.
*/ */
Client* Workspace::nextFocusChainClient( Client* c ) const Client* Workspace::nextClientFocusChain( Client* c ) const
{ {
if ( global_focus_chain.isEmpty() ) if ( global_focus_chain.isEmpty() )
return 0; return 0;
@ -1259,7 +1310,7 @@ Client* Workspace::nextFocusChainClient( Client* c ) const
auxiliary functions to travers all clients according the focus auxiliary functions to travers all clients according the focus
order. Useful for kwms Alt-tab feature. order. Useful for kwms Alt-tab feature.
*/ */
Client* Workspace::previousFocusChainClient( Client* c ) const Client* Workspace::previousClientFocusChain( Client* c ) const
{ {
if ( global_focus_chain.isEmpty() ) if ( global_focus_chain.isEmpty() )
return 0; return 0;
@ -1276,7 +1327,7 @@ Client* Workspace::previousFocusChainClient( Client* c ) const
auxiliary functions to travers all clients according the static auxiliary functions to travers all clients according the static
order. Useful for the CDE-style Alt-tab feature. order. Useful for the CDE-style Alt-tab feature.
*/ */
Client* Workspace::nextStaticClient( Client* c ) const Client* Workspace::nextClientStatic( Client* c ) const
{ {
if ( !c || clients.isEmpty() ) if ( !c || clients.isEmpty() )
return 0; return 0;
@ -1292,7 +1343,7 @@ Client* Workspace::nextStaticClient( Client* c ) const
auxiliary functions to travers all clients according the static auxiliary functions to travers all clients according the static
order. Useful for the CDE-style Alt-tab feature. order. Useful for the CDE-style Alt-tab feature.
*/ */
Client* Workspace::previousStaticClient( Client* c ) const Client* Workspace::previousClientStatic( Client* c ) const
{ {
if ( !c || clients.isEmpty() ) if ( !c || clients.isEmpty() )
return 0; return 0;
@ -1305,6 +1356,46 @@ Client* Workspace::previousStaticClient( Client* c ) const
return clients[ pos ]; return clients[ pos ];
} }
Client* Workspace::currentTabBoxClient() const
{
if( !tab_box )
return 0;
return tab_box->currentClient();
}
ClientList Workspace::currentTabBoxClientList() const
{
if( !tab_box )
return ClientList();
return tab_box->currentClientList();
}
int Workspace::currentTabBoxDesktop() const
{
if( !tab_box )
return -1;
return tab_box->currentDesktop();
}
QList< int > Workspace::currentTabBoxDesktopList() const
{
if( !tab_box )
return QList< int >();
return tab_box->currentDesktopList();
}
void Workspace::setTabBoxClient( Client* c )
{
if( tab_box )
tab_box->setCurrentClient( c );
}
void Workspace::setTabBoxDesktop( int iDesktop )
{
if( tab_box )
tab_box->setCurrentDesktop( iDesktop );
}
bool Workspace::establishTabBoxGrab() bool Workspace::establishTabBoxGrab()
{ {
if( XGrabKeyboard( display(), root, false, if( XGrabKeyboard( display(), root, false,

View file

@ -304,7 +304,7 @@ void Toplevel::setOpacity( double new_opacity )
addRepaintFull(); addRepaintFull();
scene->windowOpacityChanged( this ); scene->windowOpacityChanged( this );
if( effects ) if( effects )
effects->windowOpacityChanged( effectWindow(), old_opacity ); static_cast<EffectsHandlerImpl*>(effects)->windowOpacityChanged( effectWindow(), old_opacity );
} }
} }

View file

@ -63,7 +63,7 @@ bool Unmanaged::track( Window w )
setupCompositing(); setupCompositing();
ungrabXServer(); ungrabXServer();
if( effects ) if( effects )
effects->checkInputWindowStacking(); static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowStacking();
return true; return true;
} }
@ -72,7 +72,7 @@ void Unmanaged::release()
Deleted* del = Deleted::create( this ); Deleted* del = Deleted::create( this );
if( effects ) if( effects )
{ {
effects->windowClosed( effectWindow()); static_cast<EffectsHandlerImpl*>(effects)->windowClosed( effectWindow());
scene->windowClosed( this, del ); scene->windowClosed( this, del );
} }
finishCompositing(); finishCompositing();

View file

@ -19,6 +19,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "client.h" #include "client.h"
#include "workspace.h" #include "workspace.h"
#include "effects.h"
#include <fixx11h.h> #include <fixx11h.h>
#include <QPushButton> #include <QPushButton>
@ -60,7 +61,7 @@ QMenu* Workspace::clientPopup()
advanced_popup->setFont(KGlobalSettings::menuFont()); advanced_popup->setFont(KGlobalSettings::menuFont());
mKeepAboveOpAction = advanced_popup->addAction( i18n("Keep &Above Others") ); mKeepAboveOpAction = advanced_popup->addAction( i18n("Keep &Above Others") );
mKeepAboveOpAction->setIcon( KIcon( "go-up" ) ); mKeepAboveOpAction->setIcon( KIcon( "up" ) );
KAction *kaction = qobject_cast<KAction*>( keys->action("Window Above Other Windows") ); KAction *kaction = qobject_cast<KAction*>( keys->action("Window Above Other Windows") );
if ( kaction!=0 ) if ( kaction!=0 )
mKeepAboveOpAction->setShortcut( kaction->globalShortcut().primary() ); mKeepAboveOpAction->setShortcut( kaction->globalShortcut().primary() );
@ -68,7 +69,7 @@ QMenu* Workspace::clientPopup()
mKeepAboveOpAction->setData( Options::KeepAboveOp ); mKeepAboveOpAction->setData( Options::KeepAboveOp );
mKeepBelowOpAction = advanced_popup->addAction( i18n("Keep &Below Others") ); mKeepBelowOpAction = advanced_popup->addAction( i18n("Keep &Below Others") );
mKeepBelowOpAction->setIcon( KIcon( "go-down" ) ); mKeepBelowOpAction->setIcon( KIcon( "down" ) );
kaction = qobject_cast<KAction*>( keys->action("Window Below Other Windows") ); kaction = qobject_cast<KAction*>( keys->action("Window Below Other Windows") );
if ( kaction!=0 ) if ( kaction!=0 )
mKeepBelowOpAction->setShortcut( kaction->globalShortcut().primary() ); mKeepBelowOpAction->setShortcut( kaction->globalShortcut().primary() );
@ -76,7 +77,7 @@ QMenu* Workspace::clientPopup()
mKeepBelowOpAction->setData( Options::KeepBelowOp ); mKeepBelowOpAction->setData( Options::KeepBelowOp );
mFullScreenOpAction = advanced_popup->addAction( i18n("&Fullscreen") ); mFullScreenOpAction = advanced_popup->addAction( i18n("&Fullscreen") );
mFullScreenOpAction->setIcon( KIcon( "view-fullscreen" ) ); mFullScreenOpAction->setIcon( KIcon( "window_fullscreen" ) );
kaction = qobject_cast<KAction*>( keys->action("Window Fullscreen") ); kaction = qobject_cast<KAction*>( keys->action("Window Fullscreen") );
if ( kaction!=0 ) if ( kaction!=0 )
mFullScreenOpAction->setShortcut( kaction->globalShortcut().primary() ); mFullScreenOpAction->setShortcut( kaction->globalShortcut().primary() );
@ -111,22 +112,18 @@ QMenu* Workspace::clientPopup()
desk_popup_index = popup->actions().count(); desk_popup_index = popup->actions().count();
if (options->useTranslucency){ if (options->useTranslucency){
QMenu *trans_popup = new QMenu( popup ); trans_popup = new QMenu( popup );
QVBoxLayout *transLayout = new QVBoxLayout(trans_popup); trans_popup->setFont(KGlobalSettings::menuFont());
trans_popup->setLayout( transLayout ); connect( trans_popup, SIGNAL( triggered(QAction*) ), this, SLOT( setPopupClientOpacity(QAction*)));
transButton = new QPushButton(trans_popup); const int levels[] = { 100, 90, 75, 50, 25, 10 };
transButton->setObjectName("transButton"); for( unsigned int i = 0;
transButton->setToolTip( i18n("Reset opacity to default value")); i < sizeof( levels ) / sizeof( levels[ 0 ] );
transSlider = new QSlider(trans_popup); ++i )
transSlider->setObjectName( "transSlider" ); {
transSlider->setRange( 0, 100 ); action = trans_popup->addAction( QString::number( levels[ i ] ) + "%" );
transSlider->setValue( 100 ); action->setCheckable( true );
transSlider->setOrientation( Qt::Vertical ); action->setData( levels[ i ] );
transSlider->setToolTip( i18n("Slide this to set the window's opacity")); }
connect(transButton, SIGNAL(clicked()), SLOT(resetClientOpacity()));
connect(transButton, SIGNAL(clicked()), trans_popup, SLOT(hide()));
connect(transSlider, SIGNAL(valueChanged(int)), SLOT(setTransButtonText(int)));
connect(transSlider, SIGNAL(valueChanged(int)), this, SLOT(setPopupClientOpacity(int)));
action = popup->addMenu( trans_popup ); action = popup->addMenu( trans_popup );
action->setText( i18n("&Opacity") ); action->setText( i18n("&Opacity") );
} }
@ -176,7 +173,7 @@ QMenu* Workspace::clientPopup()
} }
mCloseOpAction = popup->addAction( i18n("&Close") ); mCloseOpAction = popup->addAction( i18n("&Close") );
mCloseOpAction->setIcon( KIcon( "window-close" ) ); mCloseOpAction->setIcon( KIcon( "fileclose" ) );
kaction = qobject_cast<KAction*>( keys->action("Window Close") ); kaction = qobject_cast<KAction*>( keys->action("Window Close") );
if ( kaction!=0 ) if ( kaction!=0 )
mCloseOpAction->setShortcut( kaction->globalShortcut().primary() ); mCloseOpAction->setShortcut( kaction->globalShortcut().primary() );
@ -185,31 +182,14 @@ QMenu* Workspace::clientPopup()
return popup; return popup;
} }
//sets the transparency of the client to given value(given by slider) void Workspace::setPopupClientOpacity( QAction* action )
void Workspace::setPopupClientOpacity(int value)
{ {
// TODO if( active_popup_client == NULL )
return;
int level = action->data().toInt();
active_popup_client->setOpacity( level / 100.0 );
} }
void Workspace::setTransButtonText(int value)
{
value = 100 - value;
if(value < 0)
transButton->setText("000 %");
else if (value >= 100 )
transButton->setText("100 %");
else if(value < 10)
transButton->setText("00"+QString::number(value)+" %");
else if(value < 100)
transButton->setText('0'+QString::number(value)+" %");
}
void Workspace::resetClientOpacity()
{
// TODO
}
/*! /*!
The client popup menu will become visible soon. The client popup menu will become visible soon.
@ -244,6 +224,16 @@ void Workspace::clientPopupAboutToShow()
mNoBorderOpAction->setChecked( active_popup_client->noBorder() ); mNoBorderOpAction->setChecked( active_popup_client->noBorder() );
mMinimizeOpAction->setEnabled( active_popup_client->isMinimizable() ); mMinimizeOpAction->setEnabled( active_popup_client->isMinimizable() );
mCloseOpAction->setEnabled( active_popup_client->isCloseable() ); mCloseOpAction->setEnabled( active_popup_client->isCloseable() );
if (options->useTranslucency)
{
foreach( QAction* action, trans_popup->actions())
{
if( action->data().toInt() == qRound( active_popup_client->opacity() * 100 ))
action->setChecked( true );
else
action->setChecked( false );
}
}
} }
@ -448,7 +438,7 @@ void Workspace::clientPopupActivated( QAction *action )
} }
void Workspace::performWindowOperation( Client* c, Options::WindowOperation op ) void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
{ {
if ( !c ) if ( !c )
return; return;
@ -457,19 +447,19 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
QCursor::setPos( c->geometry().center() ); QCursor::setPos( c->geometry().center() );
if (op == Options::ResizeOp || op == Options::UnrestrictedResizeOp ) if (op == Options::ResizeOp || op == Options::UnrestrictedResizeOp )
QCursor::setPos( c->geometry().bottomRight()); QCursor::setPos( c->geometry().bottomRight());
switch ( op ) switch ( op )
{ {
case Options::MoveOp: case Options::MoveOp:
c->performMouseCommand( Options::MouseMove, QCursor::pos() ); c->performMouseCommand( Options::MouseMove, cursorPos() );
break; break;
case Options::UnrestrictedMoveOp: case Options::UnrestrictedMoveOp:
c->performMouseCommand( Options::MouseUnrestrictedMove, QCursor::pos() ); c->performMouseCommand( Options::MouseUnrestrictedMove, cursorPos() );
break; break;
case Options::ResizeOp: case Options::ResizeOp:
c->performMouseCommand( Options::MouseResize, QCursor::pos() ); c->performMouseCommand( Options::MouseResize, cursorPos() );
break; break;
case Options::UnrestrictedResizeOp: case Options::UnrestrictedResizeOp:
c->performMouseCommand( Options::MouseUnrestrictedResize, QCursor::pos() ); c->performMouseCommand( Options::MouseUnrestrictedResize, cursorPos() );
break; break;
case Options::CloseOp: case Options::CloseOp:
c->closeWindow(); c->closeWindow();
@ -491,7 +481,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
c->minimize(); c->minimize();
break; break;
case Options::ShadeOp: case Options::ShadeOp:
c->performMouseCommand( Options::MouseShade, QCursor::pos()); c->performMouseCommand( Options::MouseShade, cursorPos());
break; break;
case Options::OnAllDesktopsOp: case Options::OnAllDesktopsOp:
c->setOnAllDesktops( !c->isOnAllDesktops() ); c->setOnAllDesktops( !c->isOnAllDesktops() );
@ -521,7 +511,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
break; break;
} }
case Options::OperationsOp: case Options::OperationsOp:
c->performMouseCommand( Options::MouseShade, QCursor::pos()); c->performMouseCommand( Options::MouseShade, cursorPos());
break; break;
case Options::WindowRulesOp: case Options::WindowRulesOp:
editWindowRules( c, false ); editWindowRules( c, false );
@ -546,7 +536,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPos, bool handled ) bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPos, bool handled )
{ {
bool replay = false; bool replay = false;
switch (command) switch (command)
{ {
case Options::MouseRaise: case Options::MouseRaise:
workspace()->raiseClient( this ); workspace()->raiseClient( this );
@ -686,10 +676,10 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo
workspace()->windowToNextDesktop( this ); workspace()->windowToNextDesktop( this );
break; break;
case Options::MouseOpacityMore: case Options::MouseOpacityMore:
// TODO setOpacity( qMin( opacity() + 0.1, 1.0 ));
break; break;
case Options::MouseOpacityLess: case Options::MouseOpacityLess:
// TODO setOpacity( qMax( opacity() - 0.1, 0.0 ));
break; break;
case Options::MouseNothing: case Options::MouseNothing:
replay = true; replay = true;
@ -704,6 +694,18 @@ void Workspace::showWindowMenuAt( unsigned long, int, int )
slotWindowOperations(); slotWindowOperations();
} }
void Workspace::loadEffect( const QString& name )
{
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->loadEffect( name );
}
void Workspace::unloadEffect( const QString& name )
{
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->unloadEffect( name );
}
void Workspace::slotActivateAttentionWindow() void Workspace::slotActivateAttentionWindow()
{ {
if( attention_chain.count() > 0 ) if( attention_chain.count() > 0 )
@ -713,13 +715,13 @@ void Workspace::slotActivateAttentionWindow()
void Workspace::slotSwitchDesktopNext() void Workspace::slotSwitchDesktopNext()
{ {
int d = currentDesktop() + 1; int d = currentDesktop() + 1;
if ( d > numberOfDesktops() ) if ( d > numberOfDesktops() )
{ {
if ( options->rollOverDesktops ) if ( options->rollOverDesktops )
{ {
d = 1; d = 1;
} }
else else
{ {
return; return;
} }
@ -730,7 +732,7 @@ void Workspace::slotSwitchDesktopNext()
void Workspace::slotSwitchDesktopPrevious() void Workspace::slotSwitchDesktopPrevious()
{ {
int d = currentDesktop() - 1; int d = currentDesktop() - 1;
if ( d <= 0 ) if ( d <= 0 )
{ {
if ( options->rollOverDesktops ) if ( options->rollOverDesktops )
d = numberOfDesktops(); d = numberOfDesktops();
@ -915,7 +917,7 @@ void Workspace::slotWindowToNextDesktop()
{ {
windowToNextDesktop( active_popup_client ? active_popup_client : active_client ); windowToNextDesktop( active_popup_client ? active_popup_client : active_client );
} }
void Workspace::windowToNextDesktop( Client* c ) void Workspace::windowToNextDesktop( Client* c )
{ {
int d = currentDesktop() + 1; int d = currentDesktop() + 1;
@ -937,7 +939,7 @@ void Workspace::slotWindowToPreviousDesktop()
{ {
windowToPreviousDesktop( active_popup_client ? active_popup_client : active_client ); windowToPreviousDesktop( active_popup_client ? active_popup_client : active_client );
} }
void Workspace::windowToPreviousDesktop( Client* c ) void Workspace::windowToPreviousDesktop( Client* c )
{ {
int d = currentDesktop() - 1; int d = currentDesktop() - 1;
@ -1032,7 +1034,7 @@ void Workspace::slotSendToDesktop( QAction *action )
int desk = action->data().toInt(); int desk = action->data().toInt();
if ( !active_popup_client ) if ( !active_popup_client )
return; return;
if ( desk == 0 ) if ( desk == 0 )
{ // the 'on_all_desktops' menu entry { // the 'on_all_desktops' menu entry
active_popup_client->setOnAllDesktops( !active_popup_client->isOnAllDesktops()); active_popup_client->setOnAllDesktops( !active_popup_client->isOnAllDesktops());
return; return;
@ -1191,7 +1193,7 @@ bool Workspace::shortcutAvailable( const KShortcut& cut, Client* ignore ) const
++it ) ++it )
{ {
if( (*it) != ignore && (*it)->shortcut() == cut ) if( (*it) != ignore && (*it)->shortcut() == cut )
return false; return false;
} }
return true; return true;
} }

View file

@ -498,7 +498,7 @@ Client* Workspace::createClient( Window w, bool is_mapped )
if( scene ) if( scene )
scene->windowAdded( c ); scene->windowAdded( c );
if( effects ) if( effects )
effects->windowAdded( c->effectWindow()); static_cast<EffectsHandlerImpl*>(effects)->windowAdded( c->effectWindow());
return c; return c;
} }
@ -516,7 +516,7 @@ Unmanaged* Workspace::createUnmanaged( Window w )
if( scene ) if( scene )
scene->windowAdded( c ); scene->windowAdded( c );
if( effects ) if( effects )
effects->windowAdded( c->effectWindow()); static_cast<EffectsHandlerImpl*>(effects)->windowAdded( c->effectWindow());
return c; return c;
} }
@ -644,7 +644,7 @@ void Workspace::removeDeleted( Deleted* c, allowed_t )
if( scene ) if( scene )
scene->windowDeleted( c ); scene->windowDeleted( c );
if( effects ) if( effects )
effects->windowDeleted( c->effectWindow()); static_cast<EffectsHandlerImpl*>(effects)->windowDeleted( c->effectWindow());
deleted.removeAll( c ); deleted.removeAll( c );
} }
@ -1327,7 +1327,7 @@ bool Workspace::setCurrentDesktop( int new_desktop )
popupinfo->showInfo( desktopName(currentDesktop()) ); popupinfo->showInfo( desktopName(currentDesktop()) );
if( effects != NULL && old_desktop != 0 && old_desktop != new_desktop ) if( effects != NULL && old_desktop != 0 && old_desktop != new_desktop )
effects->desktopChanged( old_desktop ); static_cast<EffectsHandlerImpl*>(effects)->desktopChanged( old_desktop );
return true; return true;
} }
@ -2187,7 +2187,7 @@ void Workspace::checkElectricBorder(const QPoint &pos, Time now)
if (timestampDiff(electric_time_first, now) > treshold_set) if (timestampDiff(electric_time_first, now) > treshold_set)
{ {
electric_current_border = ElectricNone; electric_current_border = ElectricNone;
if( effects && effects->borderActivated( border )) if( effects && static_cast<EffectsHandlerImpl*>(effects)->borderActivated( border ))
{} // handled by effects {} // handled by effects
else else
electricBorderSwitchDesktop( border, pos ); electricBorderSwitchDesktop( border, pos );