Merge r649608, r649403, r649230 and r648582 from trunk (porting).

svn path=/branches/work/kwin_composite/; revision=649948
This commit is contained in:
Luboš Luňák 2007-04-03 13:24:05 +00:00
parent 983df01853
commit 3617d1bf8a
14 changed files with 982 additions and 817 deletions

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 KWinInternal
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 )
{
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 )
{
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 )
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 )
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 )
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 )
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?
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 )
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

@ -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 && 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() )
@ -456,7 +473,29 @@ bool Workspace::workspaceEvent( XEvent * e )
if( electricBorder( e )) if( electricBorder( 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 )
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 )
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 )
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 )
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 )
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,14 @@ 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 ); checkElectricBorders( true );
if( compositing() )
{
finishCompositing();
QTimer::singleShot( 0, this, SLOT( setupCompositing() ) );
}
} }
/*! /*!
@ -215,7 +222,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 +1416,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 +1449,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 +1669,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 )
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 +1738,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 +1757,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 )
effects->windowGeometryShapeChanged( effectWindow(), geom_before_block );
addWorkspaceRepaint( geom_before_block );
geom_before_block = geom;
} }
/*! /*!
@ -1747,11 +1777,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 +1790,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 +1855,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 +2107,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 +2263,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 +2293,8 @@ 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 )
effects->windowUserMovedResized( effectWindow(), true, false );
return true; return true;
} }
@ -2273,6 +2308,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 )
effects->windowUserMovedResized( effectWindow(), false, true );
} }
void Client::leaveMoveResize() void Client::leaveMoveResize()
@ -2536,7 +2573,8 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
} }
if ( isMove() ) if ( isMove() )
workspace()->clientMoved(globalPos, xTime()); workspace()->clientMoved(globalPos, xTime());
if( effects )
effects->windowUserMovedResized( effectWindow(), false, false );
} }
} // namespace } // namespace

View file

@ -531,11 +531,8 @@ void KWinDecorationModule::save()
emit pluginSave( kwinConfig ); emit pluginSave( kwinConfig );
kwinConfig.sync(); kwinConfig.sync();
// Send signal to all kwin instances QDBusInterface kwin( "org.kde.kwin", "/KWin", "org.kde.KWin" );
QDBusMessage message = kwin.call( "reconfigure" );
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
} }

View file

@ -40,8 +40,8 @@
namespace KWinInternal namespace KWinInternal
{ {
DetectWidget::DetectWidget( QWidget* parent ) DetectWidget::DetectWidget( QWidget* parent, const char* name )
: DetectWidgetBase( parent ) : DetectWidgetBase( parent, name )
{ {
} }

View file

@ -20,7 +20,7 @@
#ifndef __DETECTWIDGET_H__ #ifndef __DETECTWIDGET_H__
#define __DETECTWIDGET_H__ #define __DETECTWIDGET_H__
#include "ui_detectwidgetbase.h" #include "detectwidgetbase.h"
#include <kdialog.h> #include <kdialog.h>
#include <kwm.h> #include <kwm.h>
@ -33,21 +33,12 @@
namespace KWinInternal namespace KWinInternal
{ {
class DetectWidgetBase : public QWidget, public Ui::DetectWidgetBase
{
public:
DetectWidgetBase( QWidget *parent ) : QWidget( parent ) {
setupUi( this );
}
};
class DetectWidget class DetectWidget
: public DetectWidgetBase : public DetectWidgetBase
{ {
Q_OBJECT Q_OBJECT
public: public:
DetectWidget( QWidget* parent = NULL ); DetectWidget( QWidget* parent = NULL, const char* name = NULL );
}; };
class DetectDialog class DetectDialog

View file

@ -22,6 +22,7 @@
#include <klocale.h> #include <klocale.h>
#include <kwm.h> #include <kwm.h>
#include <QtDBus/QtDBus> #include <QtDBus/QtDBus>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <fixx11h.h> #include <fixx11h.h>
@ -255,10 +256,8 @@ static int edit( Window wid, bool whole_app )
delete orig_rule; delete orig_rule;
} }
saveRules( rules ); saveRules( rules );
// Send signal to all kwin instances QDBusInterface kwin( "org.kde.kwin", "/KWin", "org.kde.KWin" );
QDBusMessage message = kwin.call( "reconfigure" );
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
return 0; return 0;
} }

View file

@ -383,16 +383,16 @@ void RulesWidget::setRules( Rules* rules )
role->setText( rules->windowrole ); role->setText( rules->windowrole );
role_match->setCurrentIndex( rules->windowrolematch ); role_match->setCurrentIndex( rules->windowrolematch );
roleMatchChanged(); roleMatchChanged();
types->item(0)->setSelected( rules->types & NET::NormalMask ); types->setSelected( 0, rules->types & NET::NormalMask );
types->item(1)->setSelected( rules->types & NET::DialogMask ); types->setSelected( 1, rules->types & NET::DialogMask );
types->item(2)->setSelected( rules->types & NET::UtilityMask ); types->setSelected( 2, rules->types & NET::UtilityMask );
types->item(3)->setSelected( rules->types & NET::DockMask ); types->setSelected( 3, rules->types & NET::DockMask );
types->item(4)->setSelected( rules->types & NET::ToolbarMask ); types->setSelected( 4, rules->types & NET::ToolbarMask );
types->item(5)->setSelected( rules->types & NET::MenuMask ); types->setSelected( 5, rules->types & NET::MenuMask );
types->item(6)->setSelected( rules->types & NET::SplashMask ); types->setSelected( 6, rules->types & NET::SplashMask );
types->item(7)->setSelected( rules->types & NET::DesktopMask ); types->setSelected( 7, rules->types & NET::DesktopMask );
types->item(8)->setSelected( rules->types & NET::OverrideMask ); types->setSelected( 8, rules->types & NET::OverrideMask );
types->item(9)->setSelected( rules->types & NET::TopMenuMask ); types->setSelected( 9, rules->types & NET::TopMenuMask );
title->setText( rules->title ); title->setText( rules->title );
title_match->setCurrentIndex( rules->titlematch ); title_match->setCurrentIndex( rules->titlematch );
titleMatchChanged(); titleMatchChanged();
@ -466,25 +466,25 @@ Rules* RulesWidget::rules() const
rules->windowrolematch = static_cast< Rules::StringMatch >( role_match->currentIndex()); rules->windowrolematch = static_cast< Rules::StringMatch >( role_match->currentIndex());
rules->types = 0; rules->types = 0;
bool all_types = true; bool all_types = true;
for( int i = 0; for( unsigned int i = 0;
i < types->count(); i < types->count();
++i ) ++i )
if( !types->item(i)->isSelected()) if( !types->isSelected( i ))
all_types = false; all_types = false;
if( all_types ) // if all types are selected, use AllTypesMask (for future expansion) if( all_types ) // if all types are selected, use AllTypesMask (for future expansion)
rules->types = NET::AllTypesMask; rules->types = NET::AllTypesMask;
else else
{ {
rules->types |= types->item(0)->isSelected() ? NET::NormalMask : 0; rules->types |= types->isSelected( 0 ) ? NET::NormalMask : 0;
rules->types |= types->item(1)->isSelected() ? NET::DialogMask : 0; rules->types |= types->isSelected( 1 ) ? NET::DialogMask : 0;
rules->types |= types->item(2)->isSelected() ? NET::UtilityMask : 0; rules->types |= types->isSelected( 2 ) ? NET::UtilityMask : 0;
rules->types |= types->item(3)->isSelected() ? NET::DockMask : 0; rules->types |= types->isSelected( 3 ) ? NET::DockMask : 0;
rules->types |= types->item(4)->isSelected() ? NET::ToolbarMask : 0; rules->types |= types->isSelected( 4 ) ? NET::ToolbarMask : 0;
rules->types |= types->item(5)->isSelected() ? NET::MenuMask : 0; rules->types |= types->isSelected( 5 ) ? NET::MenuMask : 0;
rules->types |= types->item(6)->isSelected() ? NET::SplashMask : 0; rules->types |= types->isSelected( 6 ) ? NET::SplashMask : 0;
rules->types |= types->item(7)->isSelected() ? NET::DesktopMask : 0; rules->types |= types->isSelected( 7 ) ? NET::DesktopMask : 0;
rules->types |= types->item(8)->isSelected() ? NET::OverrideMask : 0; rules->types |= types->isSelected( 8 ) ? NET::OverrideMask : 0;
rules->types |= types->item(9)->isSelected() ? NET::TopMenuMask : 0; rules->types |= types->isSelected( 9 ) ? NET::TopMenuMask : 0;
} }
rules->title = title->text(); rules->title = title->text();
rules->titlematch = static_cast< Rules::StringMatch >( title_match->currentIndex()); rules->titlematch = static_cast< Rules::StringMatch >( title_match->currentIndex());
@ -567,19 +567,19 @@ void RulesWidget::detected( bool ok )
roleMatchChanged(); roleMatchChanged();
if( detect_dlg->selectedWholeApp()) if( detect_dlg->selectedWholeApp())
{ {
for( int i = 0; for( unsigned int i = 0;
i < types->count(); i < types->count();
++i ) ++i )
types->item(i)->setSelected( true ); types->setSelected( i, true );
} }
else else
{ {
NET::WindowType type = detect_dlg->selectedType(); NET::WindowType type = detect_dlg->selectedType();
for( int i = 0; for( unsigned int i = 0;
i < types->count(); i < types->count();
++i ) ++i )
types->item(i)->setSelected( false ); types->setSelected( i, false );
types->item( typeToCombo(type) )->setSelected( true ); types->setSelected( typeToCombo( type ), true );
} }
title->setText( detect_dlg->selectedTitle()); title->setText( detect_dlg->selectedTitle());
title_match->setCurrentIndex( detect_dlg->titleMatch()); title_match->setCurrentIndex( detect_dlg->titleMatch());
@ -653,10 +653,10 @@ bool RulesWidget::finalCheck()
description->setText( i18n( "Unnamed entry" )); description->setText( i18n( "Unnamed entry" ));
} }
bool all_types = true; bool all_types = true;
for( int i = 0; for( unsigned int i = 0;
i < types->count(); i < types->count();
++i ) ++i )
if( !types->item(i)->isSelected()) if( !types->isSelected( i ))
all_types = false; all_types = false;
if( wmclass_match->currentIndex() == Rules::UnimportantMatch && all_types ) if( wmclass_match->currentIndex() == Rules::UnimportantMatch && all_types )
{ {
@ -680,7 +680,7 @@ void RulesWidget::prepareWindowSpecific( WId window )
void RulesWidget::shortcutEditClicked() void RulesWidget::shortcutEditClicked()
{ {
#ifdef __GNUC__ #ifdef __GNUC__
#warning KShortcutDialog is gone, and it is a good opportunity to clean up here #warning KShortcutDialog is gone, and it's a good opportunity to clean up here
#endif #endif
#if 0 #if 0
EditShortcutDialog dlg( topLevelWidget()); EditShortcutDialog dlg( topLevelWidget());

View file

@ -32,6 +32,7 @@ DEALINGS IN THE SOFTWARE.
#include <klibloader.h> #include <klibloader.h>
#include <kconfiggroup.h> #include <kconfiggroup.h>
#include <assert.h> #include <assert.h>
#include <kconfig.h>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>

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 )
effects->loadEffect( name );
}
void Workspace::unloadEffect( const QString& name )
{
if( effects )
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;
} }

178
utils.cpp
View file

@ -25,11 +25,13 @@ License. See the file "COPYING" for the exact licensing terms.
#include <assert.h> #include <assert.h>
#include <kdebug.h> #include <kdebug.h>
#include <kshortcut.h> #include <kshortcut.h>
#include <kkeyserver.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <QX11Info> #include <QX11Info>
#include <stdio.h> #include <stdio.h>
#include "atoms.h" #include "atoms.h"
@ -42,19 +44,68 @@ namespace KWinInternal
#ifndef KCMRULES #ifndef KCMRULES
// used to store the return values of bool Extensions::has_shape = false;
// XShapeQueryExtension. int Extensions::shape_event_base = 0;
// Necessary since shaped window are an extension to X bool Extensions::has_randr = false;
int Shape::kwin_shape_version = 0; int Extensions::randr_event_base = 0;
int Shape::kwin_shape_event = 0; bool Extensions::has_damage = false;
int Extensions::damage_event_base = 0;
bool Extensions::has_composite = false;
bool Extensions::has_composite_overlay = false;
bool Extensions::has_fixes = false;
// does the window w need a shape combine mask around it? void Extensions::init()
bool Shape::hasShape( WId w) {
int dummy;
has_shape = XShapeQueryExtension( display(), &shape_event_base, &dummy);
#ifdef HAVE_XRANDR
has_randr = XRRQueryExtension( display(), &randr_event_base, &dummy );
if( has_randr )
{
int major, minor;
XRRQueryVersion( display(), &major, &minor );
has_randr = ( major > 1 || ( major == 1 && minor >= 1 ) );
}
#else
has_randr = false;
#endif
#ifdef HAVE_XDAMAGE
has_damage = XDamageQueryExtension( display(), &damage_event_base, &dummy );
#else
has_damage = false;
#endif
#ifdef HAVE_XCOMPOSITE
has_composite = XCompositeQueryExtension( display(), &dummy, &dummy );
if( has_composite )
{
int major, minor;
XCompositeQueryVersion( display(), &major, &minor );
has_composite = ( major > 0 || minor >= 2 );
has_composite_overlay = ( major > 0 || minor >= 3 );
}
#else
has_composite = false;
has_composite_overlay = false;
#endif
#ifdef HAVE_XFIXES
has_fixes = XFixesQueryExtension( display(), &dummy, &dummy );
#else
has_fixes = false;
#endif
}
int Extensions::shapeNotifyEvent()
{
return shape_event_base + ShapeNotify;
}
// does the window w need a shape combine mask around it?
bool Extensions::hasShape( Window w )
{ {
int xws, yws, xbs, ybs; int xws, yws, xbs, ybs;
unsigned int wws, hws, wbs, hbs; unsigned int wws, hws, wbs, hbs;
int boundingShaped = 0, clipShaped = 0; int boundingShaped = 0, clipShaped = 0;
if (!available()) if( !Extensions::shapeAvailable())
return false; return false;
XShapeQueryExtents(display(), w, XShapeQueryExtents(display(), w,
&boundingShaped, &xws, &yws, &wws, &hws, &boundingShaped, &xws, &yws, &wws, &hws,
@ -62,21 +113,22 @@ bool Shape::hasShape( WId w)
return boundingShaped != 0; return boundingShaped != 0;
} }
int Shape::shapeEvent() int Extensions::randrNotifyEvent()
{ {
return kwin_shape_event; #ifdef HAVE_XRANDR
return randr_event_base + RRScreenChangeNotify;
#else
return 0;
#endif
} }
void Shape::init() int Extensions::damageNotifyEvent()
{ {
kwin_shape_version = 0; #ifdef HAVE_XDAMAGE
int dummy; return damage_event_base + XDamageNotify;
if( !XShapeQueryExtension( display(), &kwin_shape_event, &dummy )) #else
return; return 0;
int major, minor; #endif
if( !XShapeQueryVersion( display(), &major, &minor ))
return;
kwin_shape_version = major * 0x10 + minor;
} }
void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move, void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move,
@ -301,6 +353,93 @@ bool grabbedXServer()
return server_grab_count > 0; return server_grab_count > 0;
} }
// converting between X11 mouse/keyboard state mask and Qt button/keyboard states
int qtToX11Button( Qt::MouseButton button )
{
if( button == Qt::LeftButton )
return Button1;
else if( button == Qt::MidButton )
return Button2;
else if( button == Qt::RightButton )
return Button3;
return AnyButton; // 0
}
Qt::MouseButton x11ToQtMouseButton( int button )
{
if( button == Button1 )
return Qt::LeftButton;
if( button == Button2 )
return Qt::MidButton;
if( button == Button3 )
return Qt::RightButton;
return Qt::NoButton;
}
int qtToX11State( Qt::MouseButtons 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::MouseButtons x11ToQtMouseButtons( int state )
{
Qt::MouseButtons ret = 0;
if( state & Button1Mask )
ret |= Qt::LeftButton;
if( state & Button2Mask )
ret |= Qt::MidButton;
if( state & Button3Mask )
ret |= Qt::RightButton;
return ret;
}
Qt::KeyboardModifiers x11ToQtKeyboardModifiers( int state )
{
Qt::KeyboardModifiers ret = 0;
if( state & ShiftMask )
ret |= Qt::ShiftModifier;
if( state & ControlMask )
ret |= Qt::ControlModifier;
if( state & KKeyServer::modXAlt())
ret |= Qt::AltModifier;
if( state & KKeyServer::modXMeta())
ret |= Qt::MetaModifier;
return ret;
}
// Optimized version of QCursor::pos() that tries to avoid X roundtrips
// by updating the value only when the X timestamp changes.
static QPoint last_cursor_pos;
static Time last_cursor_timestamp = CurrentTime;
QPoint cursorPos()
{
last_cursor_timestamp = CurrentTime;
if( last_cursor_timestamp == CurrentTime
|| last_cursor_timestamp != QX11Info::appTime())
{
last_cursor_timestamp = QX11Info::appTime();
last_cursor_pos = QCursor::pos();
}
return last_cursor_pos;
}
#endif #endif
bool isLocalMachine( const QByteArray& host ) bool isLocalMachine( const QByteArray& host )
@ -369,7 +508,6 @@ void ShortcutDialog::accept()
} }
#endif //0 #endif //0
#endif //KCMRULES #endif //KCMRULES
} // namespace } // namespace
#ifndef KCMRULES #ifndef KCMRULES

119
utils.h
View file

@ -12,6 +12,33 @@ License. See the file "COPYING" for the exact licensing terms.
#ifndef KWIN_UTILS_H #ifndef KWIN_UTILS_H
#define KWIN_UTILS_H #define KWIN_UTILS_H
#include <config.h>
#include <config-X11.h>
#include <config-kwin.h>
#include <X11/Xlib.h>
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
#ifdef HAVE_XCOMPOSITE
#include <X11/extensions/Xcomposite.h>
#if XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR >= 3
#define HAVE_XCOMPOSITE_OVERLAY
#endif
#endif
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#include <fixx11h.h>
#include <QWidget> #include <QWidget>
#include <kmanagerselection.h> #include <kmanagerselection.h>
#include <netwm_def.h> #include <netwm_def.h>
@ -22,9 +49,17 @@ License. See the file "COPYING" for the exact licensing terms.
namespace KWinInternal namespace KWinInternal
{ {
#ifndef HAVE_XDAMAGE
typedef long Damage;
struct XDamageNotifyEvent
{
};
#endif
const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask
| NET::UtilityMask | NET::SplashMask; | NET::UtilityMask | NET::SplashMask | NET::DropdownMenuMask | NET::PopupMenuMask
| NET::TooltipMask | NET::NotificationMask | NET::ComboBoxMask | NET::DNDIconMask;
const long ClientWinMask = KeyPressMask | KeyReleaseMask | const long ClientWinMask = KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask | ButtonPressMask | ButtonReleaseMask |
@ -39,12 +74,21 @@ const long ClientWinMask = KeyPressMask | KeyReleaseMask |
const QPoint invalidPoint( INT_MIN, INT_MIN ); const QPoint invalidPoint( INT_MIN, INT_MIN );
class Toplevel;
class Client; class Client;
class Unmanaged;
class Deleted;
class Group; class Group;
class Options; class Options;
typedef QList< Toplevel* > ToplevelList;
typedef QList< const Toplevel* > ConstToplevelList;
typedef QList< Client* > ClientList; typedef QList< Client* > ClientList;
typedef QList< const Client* > ConstClientList; typedef QList< const Client* > ConstClientList;
typedef QList< Unmanaged* > UnmanagedList;
typedef QList< const Unmanaged* > ConstUnmanagedList;
typedef QList< Deleted* > DeletedList;
typedef QList< const Deleted* > ConstDeletedList;
typedef QList< Group* > GroupList; typedef QList< Group* > GroupList;
typedef QList< const Group* > ConstGroupList; typedef QList< const Group* > ConstGroupList;
@ -87,6 +131,7 @@ enum allowed_t { Allowed };
// some enums to have more readable code, instead of using bools // some enums to have more readable code, instead of using bools
enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet }; enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet };
// Areas, mostly related to Xinerama // Areas, mostly related to Xinerama
enum clientAreaOption enum clientAreaOption
{ {
@ -109,24 +154,32 @@ enum ShadeMode
ShadeActivated // "shaded", but visible due to alt+tab to the window ShadeActivated // "shaded", but visible due to alt+tab to the window
}; };
class Shape class Extensions
{ {
public: public:
static bool available() { return kwin_shape_version > 0; }
static int version() { return kwin_shape_version; } // as 16*major+minor, i.e. two hex digits
static bool hasShape( WId w);
static int shapeEvent();
static void init(); static void init();
static bool shapeAvailable() { return has_shape; }
static int shapeNotifyEvent();
static bool randrAvailable() { return has_randr; }
static int randrNotifyEvent();
static bool damageAvailable() { return has_damage; }
static int damageNotifyEvent();
static bool compositeAvailable() { return has_composite; }
static bool compositeOverlayAvailable() { return has_composite && has_composite_overlay; }
static bool fixesAvailable() { return has_fixes; }
static bool hasShape( Window w );
private: private:
static int kwin_shape_version; static bool has_shape;
static int kwin_shape_event; static int shape_event_base;
static bool has_randr;
static int randr_event_base;
static bool has_damage;
static int damage_event_base;
static bool has_composite;
static bool has_composite_overlay;
static bool has_fixes;
}; };
// compile with XShape older than 1.0
#ifndef ShapeInput
const int ShapeInput = 2;
#endif
class Motif class Motif
{ {
public: public:
@ -226,34 +279,40 @@ int displayHeight()
return XDisplayHeight( display(), DefaultScreen( display())); return XDisplayHeight( display(), DefaultScreen( display()));
} }
QPoint cursorPos();
class Scene;
extern Scene* scene;
inline bool compositing() { return scene != NULL; }
// the docs say it's UrgencyHint, but it's often #defined as XUrgencyHint // the docs say it's UrgencyHint, but it's often #defined as XUrgencyHint
#ifndef UrgencyHint #ifndef UrgencyHint
#define UrgencyHint XUrgencyHint #define UrgencyHint XUrgencyHint
#endif #endif
// for STL-like algo's // for STL-like algo's
#define KWIN_CHECK_PREDICATE( name, check ) \ #define KWIN_CHECK_PREDICATE( name, cls, check ) \
struct name \ struct name \
{ \ { \
inline bool operator()( const Client* cl ) { return check; } \ inline bool operator()( const cls* cl ) { return check; }; \
} }
#define KWIN_COMPARE_PREDICATE( name, type, check ) \ #define KWIN_COMPARE_PREDICATE( name, cls, type, check ) \
struct name \ struct name \
{ \ { \
typedef type type_helper; /* in order to work also with type being 'const Client*' etc. */ \ typedef type type_helper; /* in order to work also with type being 'const Client*' etc. */ \
inline name( const type_helper& compare_value ) : value( compare_value ) {} \ inline name( const type_helper& compare_value ) : value( compare_value ) {}; \
inline bool operator()( const Client* cl ) { return check; } \ inline bool operator()( const cls* cl ) { return check; }; \
const type_helper& value; \ const type_helper& value; \
} }
#define KWIN_PROCEDURE( name, action ) \ #define KWIN_PROCEDURE( name, cls, action ) \
struct name \ struct name \
{ \ { \
inline void operator()( Client* cl ) { action; } \ inline void operator()( cls* cl ) { action; }; \
} }
KWIN_CHECK_PREDICATE( TruePredicate, cl == cl /*true, avoid warning about 'cl' */ ); KWIN_CHECK_PREDICATE( TruePredicate, Client, cl == cl /*true, avoid warning about 'cl' */ );
template< typename T > template< typename T >
Client* findClientInList( const ClientList& list, T predicate ) Client* findClientInList( const ClientList& list, T predicate )
@ -266,6 +325,17 @@ Client* findClientInList( const ClientList& list, T predicate )
return NULL; return NULL;
} }
template< typename T >
Unmanaged* findUnmanagedInList( const UnmanagedList& list, T predicate )
{
for ( UnmanagedList::ConstIterator it = list.begin(); it != list.end(); ++it)
{
if ( predicate( const_cast< const Unmanaged* >( *it)))
return *it;
}
return NULL;
}
inline inline
int timestampCompare( Time time1, Time time2 ) // like strcmp() int timestampCompare( Time time1, Time time2 ) // like strcmp()
{ {
@ -280,7 +350,12 @@ Time timestampDiff( Time time1, Time time2 ) // returns time2 - time1
bool isLocalMachine( const QByteArray& host ); bool isLocalMachine( const QByteArray& host );
void checkNonExistentClients(); // converting between X11 mouse/keyboard state mask and Qt button/keyboard states
int qtToX11Button( Qt::MouseButton button );
Qt::MouseButton x11ToQtMouseButton( int button );
int qtToX11State( Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers );
Qt::MouseButtons x11ToQtMouseButtons( int state );
Qt::KeyboardModifiers x11ToQtKeyboardModifiers( int state );
#ifndef KCMRULES #ifndef KCMRULES
// Qt dialogs emit no signal when closed :( // Qt dialogs emit no signal when closed :(

View file

@ -43,6 +43,10 @@ License. See the file "COPYING" for the exact licensing terms.
#include "group.h" #include "group.h"
#include "rules.h" #include "rules.h"
#include "kwinadaptor.h" #include "kwinadaptor.h"
#include "unmanaged.h"
#include "scene.h"
#include "deleted.h"
#include "effects.h"
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
#include <X11/keysym.h> #include <X11/keysym.h>
@ -76,7 +80,6 @@ Workspace::Workspace( bool restore )
active_popup_client( NULL ), active_popup_client( NULL ),
desktop_widget (0), desktop_widget (0),
temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL, false ), temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL, false ),
rules_updates_disabled( false ),
active_client (0), active_client (0),
last_active_client (0), last_active_client (0),
most_recently_raised (0), most_recently_raised (0),
@ -95,6 +98,7 @@ Workspace::Workspace( bool restore )
popupinfo (0), popupinfo (0),
popup (0), popup (0),
advanced_popup (0), advanced_popup (0),
trans_popup (0),
desk_popup (0), desk_popup (0),
desk_popup_index (0), desk_popup_index (0),
keys (0), keys (0),
@ -124,12 +128,16 @@ Workspace::Workspace( bool restore )
topmenu_space( NULL ), topmenu_space( NULL ),
set_active_client_recursion( 0 ), set_active_client_recursion( 0 ),
block_stacking_updates( 0 ), block_stacking_updates( 0 ),
forced_global_mouse_grab( false ) forced_global_mouse_grab( false ),
cm_selection( NULL ),
compositeRate( 0 ),
overlay( None ),
transSlider( NULL ),
transButton( NULL )
{ {
(void) new KWinAdaptor( this ); (void) new KWinAdaptor( this );
QDBusConnection dbus = QDBusConnection::sessionBus(); QDBusConnection::sessionBus().registerObject("/KWin", this);
dbus.registerObject("/KWin", this);
dbus.connect(QString(), "/KWin", "org.kde.KWin", "reloadConfig", this, SLOT(slotReloadConfig()));
_self = this; _self = this;
mgr = new PluginMgr; mgr = new PluginMgr;
root = rootWindow(); root = rootWindow();
@ -170,10 +178,12 @@ Workspace::Workspace( bool restore )
ColormapChangeMask | ColormapChangeMask |
SubstructureRedirectMask | SubstructureRedirectMask |
SubstructureNotifyMask | SubstructureNotifyMask |
FocusChangeMask // for NotifyDetailNone FocusChangeMask | // for NotifyDetailNone
ExposureMask
); );
Shape::init(); Extensions::init();
setupCompositing();
// compatibility // compatibility
long data = 1; long data = 1;
@ -279,7 +289,6 @@ void Workspace::init()
NET::WM2ExtendedStrut | NET::WM2ExtendedStrut |
NET::WM2KDETemporaryRules | NET::WM2KDETemporaryRules |
NET::WM2ShowingDesktop | NET::WM2ShowingDesktop |
NET::WM2DesktopLayout |
0 0
, ,
NET::ActionMove | NET::ActionMove |
@ -323,6 +332,7 @@ void Workspace::init()
connect(&reconfigureTimer, SIGNAL(timeout()), this, connect(&reconfigureTimer, SIGNAL(timeout()), this,
SLOT(slotReconfigure())); SLOT(slotReconfigure()));
connect( &updateToolWindowsTimer, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows())); connect( &updateToolWindowsTimer, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows()));
connect( &compositeTimer, SIGNAL( timeout()), SLOT( performCompositing()));
connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this, connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this,
SLOT(slotReconfigure())); SLOT(slotReconfigure()));
@ -360,7 +370,10 @@ void Workspace::init()
XWindowAttributes attr; XWindowAttributes attr;
XGetWindowAttributes(display(), wins[i], &attr); XGetWindowAttributes(display(), wins[i], &attr);
if (attr.override_redirect ) if (attr.override_redirect )
{
createUnmanaged( wins[ i ] );
continue; continue;
}
if( topmenu_space && topmenu_space->winId() == wins[ i ] ) if( topmenu_space && topmenu_space->winId() == wins[ i ] )
continue; continue;
if (attr.map_state != IsUnmapped) if (attr.map_state != IsUnmapped)
@ -422,6 +435,7 @@ void Workspace::init()
Workspace::~Workspace() Workspace::~Workspace()
{ {
finishCompositing();
blockStackingUpdates( true ); blockStackingUpdates( true );
// TODO grabXServer(); // TODO grabXServer();
// use stacking_order, so that kwin --replace keeps stacking order // use stacking_order, so that kwin --replace keeps stacking order
@ -431,12 +445,12 @@ Workspace::~Workspace()
{ {
// only release the window // only release the window
(*it)->releaseWindow( true ); (*it)->releaseWindow( true );
// No removeClient() is called, it does more than just removing. // no removeClient() is called !
// However, remove from some lists to e.g. prevent performTransiencyCheck()
// from crashing.
clients.remove( *it );
desktops.remove( *it );
} }
for( UnmanagedList::ConstIterator it = unmanaged.begin();
it != unmanaged.end();
++it )
(*it)->release();
delete desktop_widget; delete desktop_widget;
delete tab_box; delete tab_box;
delete popupinfo; delete popupinfo;
@ -480,6 +494,28 @@ Client* Workspace::createClient( Window w, bool is_mapped )
return NULL; return NULL;
} }
addClient( c, Allowed ); addClient( c, Allowed );
if( scene )
scene->windowAdded( c );
if( effects )
effects->windowAdded( c->effectWindow());
return c;
}
Unmanaged* Workspace::createUnmanaged( Window w )
{
if( w == overlay )
return NULL;
Unmanaged* c = new Unmanaged( this );
if( !c->track( w ))
{
Unmanaged::deleteUnmanaged( c, Allowed );
return NULL;
}
addUnmanaged( c, Allowed );
if( scene )
scene->windowAdded( c );
if( effects )
effects->windowAdded( c->effectWindow());
return c; return c;
} }
@ -520,7 +556,13 @@ void Workspace::addClient( Client* c, allowed_t )
updateStackingOrder( true ); // propagate new client updateStackingOrder( true ); // propagate new client
if( c->isUtility() || c->isMenu() || c->isToolbar()) if( c->isUtility() || c->isMenu() || c->isToolbar())
updateToolWindows( true ); updateToolWindows( true );
checkNonExistentClients(); if( tab_grab )
tab_box->reset( true );
}
void Workspace::addUnmanaged( Unmanaged* c, allowed_t )
{
unmanaged.append( c );
} }
/* /*
@ -541,6 +583,12 @@ void Workspace::removeClient( Client* c, allowed_t )
if( c->isNormalWindow()) if( c->isNormalWindow())
Notify::raise( Notify::Delete ); Notify::raise( Notify::Delete );
if( tab_grab )
{
if( tab_box->currentClient() == c )
tab_box->nextPrev( true );
}
Q_ASSERT( clients.contains( c ) || desktops.contains( c )); Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
clients.removeAll( c ); clients.removeAll( c );
desktops.removeAll( c ); desktops.removeAll( c );
@ -571,12 +619,34 @@ void Workspace::removeClient( Client* c, allowed_t )
updateStackingOrder( true ); updateStackingOrder( true );
if (tab_grab) if( tab_grab )
tab_box->repaint(); tab_box->reset( true );
updateClientArea(); updateClientArea();
} }
void Workspace::removeUnmanaged( Unmanaged* c, allowed_t )
{
assert( unmanaged.contains( c ));
unmanaged.removeAll( c );
}
void Workspace::addDeleted( Deleted* c, allowed_t )
{
assert( !deleted.contains( c ));
deleted.append( c );
}
void Workspace::removeDeleted( Deleted* c, allowed_t )
{
assert( deleted.contains( c ));
if( scene )
scene->windowDeleted( c );
if( effects )
effects->windowDeleted( c->effectWindow());
deleted.removeAll( c );
}
void Workspace::updateFocusChains( Client* c, FocusChainChange change ) void Workspace::updateFocusChains( Client* c, FocusChainChange change )
{ {
if( !c->wantsTabFocus()) // doesn't want tab focus, remove if( !c->wantsTabFocus()) // doesn't want tab focus, remove
@ -602,13 +672,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change )
focus_chain[ i ].prepend( c ); focus_chain[ i ].prepend( c );
} }
else if( !focus_chain[ i ].contains( c )) else if( !focus_chain[ i ].contains( c ))
{ // add it after the active one focus_chain[ i ].prepend( c ); // otherwise add as the last one
if( active_client != NULL && active_client != c
&& !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c );
else
focus_chain[ i ].append( c ); // otherwise add as the first one
}
} }
} }
else //now only on desktop, remove it anywhere else else //now only on desktop, remove it anywhere else
@ -628,13 +692,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change )
focus_chain[ i ].prepend( c ); focus_chain[ i ].prepend( c );
} }
else if( !focus_chain[ i ].contains( c )) else if( !focus_chain[ i ].contains( c ))
{ // add it after the active one focus_chain[ i ].prepend( c );
if( active_client != NULL && active_client != c
&& !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c );
else
focus_chain[ i ].append( c ); // otherwise add as the first one
}
} }
else else
focus_chain[ i ].removeAll( c ); focus_chain[ i ].removeAll( c );
@ -651,13 +709,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change )
global_focus_chain.prepend( c ); global_focus_chain.prepend( c );
} }
else if( !global_focus_chain.contains( c )) else if( !global_focus_chain.contains( c ))
{ // add it after the active one global_focus_chain.prepend( c );
if( active_client != NULL && active_client != c
&& !global_focus_chain.isEmpty() && global_focus_chain.last() == active_client )
global_focus_chain.insert( global_focus_chain.size() - 1, c );
else
global_focus_chain.append( c ); // otherwise add as the first one
}
} }
void Workspace::updateCurrentTopMenu() void Workspace::updateCurrentTopMenu()
@ -875,11 +927,6 @@ void Workspace::updateColormap()
} }
} }
void Workspace::slotReloadConfig()
{
reconfigure();
}
void Workspace::reconfigure() void Workspace::reconfigure()
{ {
reconfigureTimer.start( 200 ); reconfigureTimer.start( 200 );
@ -896,7 +943,7 @@ void Workspace::slotSettingsChanged(int category)
/*! /*!
Reread settings Reread settings
*/ */
KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() ); KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes() );
void Workspace::slotReconfigure() void Workspace::slotReconfigure()
{ {
@ -953,6 +1000,11 @@ void Workspace::slotReconfigure()
updateTopMenuGeometry(); updateTopMenuGeometry();
updateCurrentTopMenu(); updateCurrentTopMenu();
} }
if( options->useTranslucency )
setupCompositing();
else
finishCompositing();
loadWindowRules(); loadWindowRules();
for( ClientList::Iterator it = clients.begin(); for( ClientList::Iterator it = clients.begin();
@ -1235,16 +1287,15 @@ bool Workspace::setCurrentDesktop( int new_desktop )
// and active_client is on_all_desktops and under mouse (hence == old_active_client), // and active_client is on_all_desktops and under mouse (hence == old_active_client),
// conserve focus (thanks to Volker Schatz <V.Schatz at thphys.uni-heidelberg.de>) // conserve focus (thanks to Volker Schatz <V.Schatz at thphys.uni-heidelberg.de>)
else if( active_client && active_client->isShown( true ) && active_client->isOnCurrentDesktop()) else if( active_client && active_client->isShown( true ) && active_client->isOnCurrentDesktop())
c = active_client; c= active_client;
if( c == NULL && !desktops.isEmpty())
c = findDesktop( true, currentDesktop());
if( c != active_client ) if( c != active_client )
setActiveClient( NULL, Allowed ); setActiveClient( NULL, Allowed );
if ( c ) if ( c )
requestFocus( c ); requestFocus( c );
else if( !desktops.isEmpty() )
requestFocus( findDesktop( true, currentDesktop()));
else else
focusToNull(); focusToNull();
@ -1266,6 +1317,10 @@ bool Workspace::setCurrentDesktop( int new_desktop )
if( old_desktop != 0 ) // not for the very first time if( old_desktop != 0 ) // not for the very first time
popupinfo->showInfo( desktopName(currentDesktop()) ); popupinfo->showInfo( desktopName(currentDesktop()) );
if( effects != NULL && old_desktop != 0 )
effects->desktopChanged( old_desktop );
return true; return true;
} }
@ -1498,26 +1553,25 @@ void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate )
updateClientArea(); updateClientArea();
} }
void Workspace::setDesktopLayout(NET::Orientation o, int x, int y,NET::DesktopLayoutCorner c) void Workspace::setDesktopLayout(int o, int x, int y)
{ {
Q_UNUSED( c ); // I don't find this worth bothering, feel free to layoutOrientation = (Qt::Orientation) o;
layoutOrientation = ( o == NET::OrientationHorizontal ? Qt::Horizontal : Qt::Vertical );
layoutX = x; layoutX = x;
layoutY = y; layoutY = y;
} }
void Workspace::calcDesktopLayout(int &x, int &y) const void Workspace::calcDesktopLayout(int &x, int &y) const
{ {
x = layoutX; // <= 0 means compute it from the other and total number of desktops x = layoutX;
y = layoutY; y = layoutY;
if((x <= 0) && (y > 0)) if ((x == -1) && (y > 0))
x = (numberOfDesktops()+y-1) / y; x = (numberOfDesktops()+y-1) / y;
else if((y <=0) && (x > 0)) else if ((y == -1) && (x > 0))
y = (numberOfDesktops()+x-1) / x; y = (numberOfDesktops()+x-1) / x;
if(x <=0) if (x == -1)
x = 1; x = 1;
if (y <= 0) if (y == -1)
y = 1; y = 1;
} }
@ -1649,7 +1703,7 @@ void Workspace::slotGrabWindow()
QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() ); QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() );
//No XShape - no work. //No XShape - no work.
if( Shape::available()) if( Extensions::shapeAvailable())
{ {
//As the first step, get the mask from XShape. //As the first step, get the mask from XShape.
int count, order; int count, order;
@ -1850,7 +1904,7 @@ bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
bool is_alt = km & Mod1Mask; bool is_alt = km & Mod1Mask;
bool is_shift = km & ShiftMask; bool is_shift = km & ShiftMask;
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 ( kc ) switch ( kc )
{ {
@ -2002,7 +2056,8 @@ void Workspace::createBorderWindows()
XSetWindowAttributes attributes; XSetWindowAttributes attributes;
unsigned long valuemask; unsigned long valuemask;
attributes.override_redirect = True; attributes.override_redirect = True;
attributes.event_mask = ( EnterWindowMask | LeaveWindowMask ); attributes.event_mask = (EnterWindowMask | LeaveWindowMask |
VisibilityChangeMask);
valuemask= (CWOverrideRedirect | CWEventMask | CWCursor ); valuemask= (CWOverrideRedirect | CWEventMask | CWCursor );
attributes.cursor = XCreateFontCursor(display(), attributes.cursor = XCreateFontCursor(display(),
XC_sb_up_arrow); XC_sb_up_arrow);
@ -2394,7 +2449,7 @@ void Workspace::helperDialog( const QString& message, const Client* c )
{ {
KConfig cfg( "kwin_dialogsrc" ); KConfig cfg( "kwin_dialogsrc" );
KConfigGroup cg(&cfg, "Notification Messages" ); // this depends on KMessageBox KConfigGroup cg(&cfg, "Notification Messages" ); // this depends on KMessageBox
if( !cg.readEntry( type, true )) // has don't show again checked if( !cg.readEntry( type, QVariant(true )).toBool()) // has don't show again checked
return; // save launching kdialog return; // save launching kdialog
proc << "--dontagain" << "kwin_dialogsrc:" + type; proc << "--dontagain" << "kwin_dialogsrc:" + type;
} }

View file

@ -18,6 +18,8 @@ License. See the file "COPYING" for the exact licensing terms.
#include <QCursor> #include <QCursor>
#include <netwm.h> #include <netwm.h>
#include <kxmessages.h> #include <kxmessages.h>
#include <qdatetime.h>
#include <kmanagerselection.h>
#include "utils.h" #include "utils.h"
#include "kdecoration.h" #include "kdecoration.h"
@ -34,7 +36,6 @@ class KStartupInfoId;
class KStartupInfoData; class KStartupInfoData;
class QSlider; class QSlider;
class QPushButton; class QPushButton;
class K3Process;
namespace KWinInternal namespace KWinInternal
{ {
@ -77,7 +78,7 @@ class Workspace : public QObject, public KDecorationDefines
virtual ~Workspace(); virtual ~Workspace();
static Workspace * self() { return _self; } static Workspace * self() { return _self; }
bool workspaceEvent( XEvent * ); bool workspaceEvent( XEvent * );
KDecoration* createDecoration( KDecorationBridge* bridge ); KDecoration* createDecoration( KDecorationBridge* bridge );
@ -87,6 +88,9 @@ class Workspace : public QObject, public KDecorationDefines
template< typename T > Client* findClient( T predicate ); template< typename T > Client* findClient( T predicate );
template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate ); template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate );
template< typename T > void forEachClient( T procedure ); template< typename T > void forEachClient( T procedure );
template< typename T > Unmanaged* findUnmanaged( T predicate );
template< typename T1, typename T2 > void forEachUnmanaged( T1 procedure, T2 predicate );
template< typename T > void forEachUnmanaged( T procedure );
QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const; QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const;
QRect clientArea( clientAreaOption, const Client* c ) const; QRect clientArea( clientAreaOption, const Client* c ) const;
@ -165,12 +169,22 @@ class Workspace : public QObject, public KDecorationDefines
QWidget* desktopWidget(); QWidget* desktopWidget();
// for TabBox // for TabBox
Client* nextFocusChainClient(Client*) const; Client* currentTabBoxClient() const;
Client* previousFocusChainClient(Client*) const; ClientList currentTabBoxClientList() const;
Client* nextStaticClient(Client*) const; int currentTabBoxDesktop() const;
Client* previousStaticClient(Client*) const; QList< int > currentTabBoxDesktopList() const;
void setTabBoxClient(Client*);
void setTabBoxDesktop(int);
Client* nextClientFocusChain(Client*) const;
Client* previousClientFocusChain(Client*) const;
Client* nextClientStatic(Client*) const;
Client* previousClientStatic(Client*) const;
int nextDesktopFocusChain( int iDesktop ) const; int nextDesktopFocusChain( int iDesktop ) const;
int previousDesktopFocusChain( int iDesktop ) const; int previousDesktopFocusChain( int iDesktop ) const;
int nextDesktopStatic( int iDesktop ) const;
int previousDesktopStatic( int iDesktop ) const;
void refTabBox();
void unrefTabBox();
void closeTabBox(); void closeTabBox();
/** /**
@ -181,7 +195,7 @@ class Workspace : public QObject, public KDecorationDefines
ClientList ensureStackingOrder( const ClientList& clients ) const; ClientList ensureStackingOrder( const ClientList& clients ) const;
Client* topClientOnDesktop( int desktop, bool unconstrained = false, bool only_normal = true ) const; Client* topClientOnDesktop( int desktop, bool unconstrained = false ) const;
Client* findDesktop( bool topmost, int desktop ) const; Client* findDesktop( bool topmost, int desktop ) const;
void sendClientToDesktop( Client* c, int desktop, bool dont_activate ); void sendClientToDesktop( Client* c, int desktop, bool dont_activate );
void windowToPreviousDesktop( Client* c ); void windowToPreviousDesktop( Client* c );
@ -190,6 +204,10 @@ class Workspace : public QObject, public KDecorationDefines
// KDE4 remove me - and it's also in the DCOP interface :( // KDE4 remove me - and it's also in the DCOP interface :(
void showWindowMenuAt( unsigned long id, int x, int y ); void showWindowMenuAt( unsigned long id, int x, int y );
void loadEffect( const QString& name );
void unloadEffect( const QString& name );
/** /**
* Shows the menu operations menu for the client and makes it active if * Shows the menu operations menu for the client and makes it active if
* it's not already. * it's not already.
@ -213,8 +231,6 @@ class Workspace : public QObject, public KDecorationDefines
WindowRules findWindowRules( const Client*, bool ); WindowRules findWindowRules( const Client*, bool );
void rulesUpdated(); void rulesUpdated();
void discardUsedWindowRules( Client* c, bool withdraw ); void discardUsedWindowRules( Client* c, bool withdraw );
void disableRulesUpdates( bool disable );
bool rulesUpdatesDisabled() const;
// dcop interface // dcop interface
void cascadeDesktop(); void cascadeDesktop();
@ -226,7 +242,7 @@ class Workspace : public QObject, public KDecorationDefines
void circulateDesktopApplications(); void circulateDesktopApplications();
QString desktopName( int desk ) const; QString desktopName( int desk ) const;
void setDesktopLayout(NET::Orientation o, int x, int y, NET::DesktopLayoutCorner c); void setDesktopLayout(int o, int x, int y);
void setShowingDesktop( bool showing ); void setShowingDesktop( bool showing );
void resetShowingDesktop( bool keep_hidden ); void resetShowingDesktop( bool keep_hidden );
bool showingDesktop() const; bool showingDesktop() const;
@ -236,14 +252,17 @@ class Workspace : public QObject, public KDecorationDefines
void sendPingToWindow( Window w, Time timestamp ); // called from Client::pingWindow() void sendPingToWindow( Window w, Time timestamp ); // called from Client::pingWindow()
void sendTakeActivity( Client* c, Time timestamp, long flags ); // called from Client::takeActivity() void sendTakeActivity( Client* c, Time timestamp, long flags ); // called from Client::takeActivity()
// only called from Client::destroyClient() or Client::releaseWindow() void removeClient( Client*, allowed_t ); // only called from Client::destroyClient() or Client::releaseWindow()
void removeClient( Client*, allowed_t );
void setActiveClient( Client*, allowed_t ); void setActiveClient( Client*, allowed_t );
Group* findGroup( Window leader ) const; Group* findGroup( Window leader ) const;
void addGroup( Group* group, allowed_t ); void addGroup( Group* group, allowed_t );
void removeGroup( Group* group, allowed_t ); void removeGroup( Group* group, allowed_t );
Group* findClientLeaderGroup( const Client* c ) const; Group* findClientLeaderGroup( const Client* c ) const;
void removeUnmanaged( Unmanaged*, allowed_t ); // only called from Unmanaged::release()
void removeDeleted( Deleted*, allowed_t );
void addDeleted( Deleted*, allowed_t );
bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data ); bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data );
void focusToNull(); // SELI public? void focusToNull(); // SELI public?
@ -279,6 +298,19 @@ class Workspace : public QObject, public KDecorationDefines
void toggleTopDockShadows(bool on); void toggleTopDockShadows(bool on);
// when adding repaints caused by a window, you probably want to use
// either Toplevel::addRepaint() or Toplevel::addWorkspaceRepaint()
void addRepaint( const QRect& r );
void addRepaint( int x, int y, int w, int h );
void addRepaintFull();
// creates XComposite overlay window, call initOverlay() afterwards
bool createOverlay();
// init overlay and the destination window in it
void setupOverlay( Window window );
// destroys XComposite overlay window
void destroyOverlay();
Window overlayWindow();
public slots: public slots:
void refresh(); void refresh();
// keybindings // keybindings
@ -408,15 +440,14 @@ class Workspace : public QObject, public KDecorationDefines
void cleanupTemporaryRules(); void cleanupTemporaryRules();
void writeWindowRules(); void writeWindowRules();
void slotBlockShortcuts(int data); void slotBlockShortcuts(int data);
void slotReloadConfig(); void setPopupClientOpacity( QAction* action );
// kompmgr void setupCompositing();
void setPopupClientOpacity(int v); void performCompositing();
void resetClientOpacity(); void lostCMSelection();
void setTransButtonText(int value);
// end
protected: protected:
bool keyPressMouseEmulation( XKeyEvent& ev ); bool keyPressMouseEmulation( XKeyEvent& ev );
bool netCheck( XEvent* e );
private: private:
void init(); void init();
@ -460,6 +491,8 @@ class Workspace : public QObject, public KDecorationDefines
// this is the right way to create a new client // this is the right way to create a new client
Client* createClient( Window w, bool is_mapped ); Client* createClient( Window w, bool is_mapped );
void addClient( Client* c, allowed_t ); void addClient( Client* c, allowed_t );
Unmanaged* createUnmanaged( Window w );
void addUnmanaged( Unmanaged* c, allowed_t );
Window findSpecialEventWindow( XEvent* e ); Window findSpecialEventWindow( XEvent* e );
@ -501,6 +534,9 @@ class Workspace : public QObject, public KDecorationDefines
void closeActivePopup(); void closeActivePopup();
void updateClientArea( bool force ); void updateClientArea( bool force );
void finishCompositing();
bool windowRepaintsPending() const;
SystemTrayWindowList systemTrayWins; SystemTrayWindowList systemTrayWins;
@ -521,7 +557,6 @@ class Workspace : public QObject, public KDecorationDefines
QList<Rules*> rules; QList<Rules*> rules;
KXMessages temporaryRulesMessages; KXMessages temporaryRulesMessages;
QTimer rulesUpdatedTimer; QTimer rulesUpdatedTimer;
bool rules_updates_disabled;
static const char* windowTypeToTxt( NET::WindowType type ); static const char* windowTypeToTxt( NET::WindowType type );
static NET::WindowType txtToWindowType( const char* txt ); static NET::WindowType txtToWindowType( const char* txt );
static bool sessionInfoWindowTypeMatch( Client* c, SessionInfo* info ); static bool sessionInfoWindowTypeMatch( Client* c, SessionInfo* info );
@ -538,10 +573,12 @@ class Workspace : public QObject, public KDecorationDefines
ClientList clients; ClientList clients;
ClientList desktops; ClientList desktops;
UnmanagedList unmanaged;
DeletedList deleted;
ClientList unconstrained_stacking_order; // topmost last ClientList unconstrained_stacking_order;
ClientList stacking_order; // topmost last ClientList stacking_order;
QVector< ClientList > focus_chain; // currently ative last QVector< ClientList > focus_chain;
ClientList global_focus_chain; // this one is only for things like tabbox's MRU ClientList global_focus_chain; // this one is only for things like tabbox's MRU
ClientList should_get_focus; // last is most recent ClientList should_get_focus; // last is most recent
ClientList attention_chain; ClientList attention_chain;
@ -575,6 +612,7 @@ class Workspace : public QObject, public KDecorationDefines
QMenu *popup; QMenu *popup;
QMenu *advanced_popup; QMenu *advanced_popup;
QMenu *trans_popup;
QMenu *desk_popup; QMenu *desk_popup;
int desk_popup_index; int desk_popup_index;
@ -658,12 +696,14 @@ class Workspace : public QObject, public KDecorationDefines
bool forced_global_mouse_grab; bool forced_global_mouse_grab;
friend class StackingUpdatesBlocker; friend class StackingUpdatesBlocker;
//kompmgr KSelectionOwner* cm_selection;
QTimer compositeTimer;
QTime lastCompositePaint;
int compositeRate;
QRegion repaints_region;
Window overlay; // XComposite overlay window
QSlider *transSlider; QSlider *transSlider;
QPushButton *transButton; QPushButton *transButton;
private:
friend bool performTransiencyCheck();
}; };
// helper for Workspace::blockStackingUpdates() being called in pairs (true/false) // helper for Workspace::blockStackingUpdates() being called in pairs (true/false)
@ -688,6 +728,7 @@ class RootInfo : public NETRootInfo
protected: protected:
virtual void changeNumberOfDesktops(int n); virtual void changeNumberOfDesktops(int n);
virtual void changeCurrentDesktop(int d); virtual void changeCurrentDesktop(int d);
// virtual void changeActiveWindow(Window w); the extended version is used
virtual void changeActiveWindow(Window w,NET::RequestSource src, Time timestamp, Window active_window); virtual void changeActiveWindow(Window w,NET::RequestSource src, Time timestamp, Window active_window);
virtual void closeWindow(Window w); virtual void closeWindow(Window w);
virtual void moveResize(Window w, int x_root, int y_root, unsigned long direction); virtual void moveResize(Window w, int x_root, int y_root, unsigned long direction);
@ -805,10 +846,9 @@ inline bool Workspace::globalShortcutsDisabled() const
return global_shortcuts_disabled || global_shortcuts_disabled_for_client; return global_shortcuts_disabled || global_shortcuts_disabled_for_client;
} }
inline inline Window Workspace::overlayWindow()
bool Workspace::rulesUpdatesDisabled() const
{ {
return rules_updates_disabled; return overlay;
} }
template< typename T > template< typename T >
@ -838,7 +878,27 @@ inline void Workspace::forEachClient( T procedure )
return forEachClient( procedure, TruePredicate()); return forEachClient( procedure, TruePredicate());
} }
KWIN_COMPARE_PREDICATE( ClientMatchPredicate, const Client*, cl == value ); template< typename T >
inline Unmanaged* Workspace::findUnmanaged( T predicate )
{
return findUnmanagedInList( unmanaged, predicate );
}
template< typename T1, typename T2 >
inline void Workspace::forEachUnmanaged( T1 procedure, T2 predicate )
{
for ( UnmanagedList::ConstIterator it = unmanaged.begin(); it != unmanaged.end(); ++it)
if ( predicate( const_cast< const Unmanaged* >( *it)))
procedure( *it );
}
template< typename T >
inline void Workspace::forEachUnmanaged( T procedure )
{
return forEachUnmanaged( procedure, TruePredicate());
}
KWIN_COMPARE_PREDICATE( ClientMatchPredicate, Client, const Client*, cl == value );
inline bool Workspace::hasClient( const Client* c ) inline bool Workspace::hasClient( const Client* c )
{ {
return findClient( ClientMatchPredicate( c )); return findClient( ClientMatchPredicate( c ));