From 3617d1bf8af99d55f868f4914c58bb33ce77a24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Tue, 3 Apr 2007 13:24:05 +0000 Subject: [PATCH] Merge r649608, r649403, r649230 and r648582 from trunk (porting). svn path=/branches/work/kwin_composite/; revision=649948 --- client.cpp | 601 +++++----------------- events.cpp | 290 ++++++++--- geometry.cpp | 102 ++-- kcmkwin/kwindecoration/kwindecoration.cpp | 7 +- kcmkwin/kwinrules/detectwidget.cpp | 4 +- kcmkwin/kwinrules/detectwidget.h | 13 +- kcmkwin/kwinrules/main.cpp | 7 +- kcmkwin/kwinrules/ruleswidget.cpp | 60 +-- lib/kdecoration_plugins_p.cpp | 1 + useractions.cpp | 124 ++--- utils.cpp | 178 ++++++- utils.h | 119 ++++- workspace.cpp | 173 ++++--- workspace.h | 120 +++-- 14 files changed, 982 insertions(+), 817 deletions(-) diff --git a/client.cpp b/client.cpp index 61a6477c6f..4b5d6c2706 100644 --- a/client.cpp +++ b/client.cpp @@ -28,6 +28,9 @@ License. See the file "COPYING" for the exact licensing terms. #include "atoms.h" #include "notifications.h" #include "rules.h" +#include "scene.h" +#include "effects.h" +#include "deleted.h" #include #include @@ -63,12 +66,10 @@ namespace KWinInternal is done in manage(). */ Client::Client( Workspace *ws ) - : QObject( NULL ), + : Toplevel( ws ), client( None ), wrapper( None ), - frame( None ), decoration( NULL ), - wspace( ws ), bridge( new Bridge( this )), move_faked_activity( false ), move_resize_grab_window( None ), @@ -82,7 +83,7 @@ Client::Client( Workspace *ws ) process_killer( NULL ), user_time( CurrentTime ), // not known yet allowed_actions( 0 ), - postpone_geometry_updates( 0 ), + block_geometry_updates( 0 ), pending_geometry_update( false ), shade_geometry_change( false ), border_left( 0 ), @@ -111,7 +112,6 @@ Client::Client( Workspace *ws ) deleting = false; keep_above = false; keep_below = false; - is_shape = false; motif_noborder = false; motif_may_move = true; motif_may_resize = true; @@ -124,6 +124,7 @@ Client::Client( Workspace *ws ) modal = false; noborder = false; user_noborder = false; + not_obscured = false; urgency = false; ignore_focus_stealing = false; demands_attention = false; @@ -142,7 +143,7 @@ Client::Client( Workspace *ws ) 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 ); // SELI initialize xsizehints?? @@ -155,11 +156,11 @@ Client::~Client() { assert(!moveResizeMode); assert( client == None ); - assert( frame == None && wrapper == None ); + assert( wrapper == None ); +// assert( frameId() == None ); assert( decoration == NULL ); - assert( postpone_geometry_updates == 0 ); + assert( block_geometry_updates == 0 ); assert( !check_active_modal ); - delete info; delete bridge; } @@ -176,15 +177,21 @@ void Client::releaseWindow( bool on_shutdown ) { assert( !deleting ); deleting = true; + Deleted* del = Deleted::create( this ); + if( effects ) + { + effects->windowClosed( effectWindow()); + scene->windowClosed( this, del ); + } + finishCompositing(); workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules StackingUpdatesBlocker blocker( workspace()); if (moveResizeMode) leaveMoveResize(); finishWindowRules(); - ++postpone_geometry_updates; - // grab X during the release to make removing of properties, setting to withdrawn state - // and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2) - grabXServer(); + ++block_geometry_updates; + if( isOnCurrentDesktop() && isShown( true )) + addWorkspaceRepaint( geometry()); setMappingState( WithdrawnState ); 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) @@ -222,12 +229,12 @@ void Client::releaseWindow( bool on_shutdown ) client = None; XDestroyWindow( display(), wrapper ); wrapper = None; - XDestroyWindow( display(), frame ); - frame = None; - --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry - checkNonExistentClients(); + XDestroyWindow( display(), frameId()); +// frame = None; + --block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry + disownDataPassedToDeleted(); + del->unrefWindow(); deleteClient( this, Allowed ); - ungrabXServer(); } // like releaseWindow(), but this one is called when the window has been already destroyed @@ -236,12 +243,21 @@ void Client::destroyClient() { assert( !deleting ); deleting = true; + Deleted* del = Deleted::create( this ); + if( effects ) + { + effects->windowClosed( effectWindow()); + scene->windowClosed( this, del ); + } + finishCompositing(); workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules StackingUpdatesBlocker blocker( workspace()); if (moveResizeMode) leaveMoveResize(); finishWindowRules(); - ++postpone_geometry_updates; + ++block_geometry_updates; + if( isOnCurrentDesktop() && isShown( true )) + addWorkspaceRepaint( geometry()); setModal( false ); hidden = true; // so that it's not considered visible anymore workspace()->clientHidden( this ); @@ -251,10 +267,11 @@ void Client::destroyClient() client = None; // invalidate XDestroyWindow( display(), wrapper ); wrapper = None; - XDestroyWindow( display(), frame ); - frame = None; - --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry - checkNonExistentClients(); + XDestroyWindow( display(), frameId()); +// frame = None; + --block_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry + disownDataPassedToDeleted(); + del->unrefWindow(); deleteClient( this, Allowed ); } @@ -264,12 +281,12 @@ void Client::updateDecoration( bool check_workspace_pos, bool force ) || ( decoration != NULL && !noBorder()))) return; bool do_show = false; - postponeGeometryUpdates( true ); + QRect oldgeom = geometry(); + blockGeometryUpdates( true ); if( force ) destroyDecoration(); if( !noBorder()) { - setMask( QRegion()); // reset shape mask decoration = workspace()->createDecoration( bridge ); // TODO check decoration's minimum size? decoration->init(); @@ -284,12 +301,18 @@ void Client::updateDecoration( bool check_workspace_pos, bool force ) workarea_diff_x = save_workarea_diff_x; workarea_diff_y = save_workarea_diff_y; do_show = true; + if( compositing() ) + discardWindowPixmap(); + if( scene != NULL ) + scene->windowGeometryShapeChanged( this ); + if( effects != NULL ) + effects->windowGeometryShapeChanged( effectWindow(), oldgeom ); } else destroyDecoration(); if( check_workspace_pos ) checkWorkspacePosition(); - postponeGeometryUpdates( false ); + blockGeometryUpdates( false ); if( do_show ) decoration->widget()->show(); updateFrameExtents(); @@ -297,6 +320,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force ) void Client::destroyDecoration() { + QRect oldgeom = geometry(); if( decoration != NULL ) { delete decoration; @@ -310,6 +334,12 @@ void Client::destroyDecoration() move( grav ); workarea_diff_x = save_workarea_diff_x; 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 && new_top == border_top && new_bottom == border_bottom ) return; - GeometryUpdatesPostponer blocker( this ); + GeometryUpdatesBlocker blocker( this ); move( calculateGravitation( true )); border_left = new_left; border_right = new_right; @@ -339,7 +369,7 @@ void Client::checkBorderSizes() void Client::detectNoBorder() { - if( Shape::hasShape( window())) + if( shape()) { noborder = true; return; @@ -427,47 +457,25 @@ void Client::setUserNoBorder( bool set ) 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 if( shape() && !noBorder()) { noborder = 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 ) @@ -496,7 +504,12 @@ void Client::setMask( const QRegion& reg, int mode ) xrects, rects.count(), ShapeSet, mode ); delete[] xrects; } - updateShape(); + if( compositing()) + addDamageFull(); + if( scene != NULL ) + scene->windowGeometryShapeChanged( this ); + if( effects != NULL ) + effects->windowGeometryShapeChanged( effectWindow(), geometry()); } QRegion Client::mask() const @@ -555,10 +568,6 @@ void Client::minimize( bool avoid_animation ) 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; updateVisibility(); @@ -566,6 +575,8 @@ void Client::minimize( bool avoid_animation ) workspace()->updateMinimizedOfTransients( this ); updateWindowRules(); 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 ) @@ -575,142 +586,34 @@ void Client::unminimize( bool avoid_animation ) Notify::raise( Notify::UnMinimize ); minimized = false; - if( isOnCurrentDesktop() && isShown( true )) - { - if( mainClients().isEmpty() && !avoid_animation ) - animateMinimizeOrUnminimize( false ); - } updateVisibility(); updateAllowedActions(); workspace()->updateMinimizedOfTransients( this ); updateWindowRules(); + if( effects && !avoid_animation ) + effects->windowUnminimized( effectWindow()); } -extern bool blockAnimation; - -void Client::animateMinimizeOrUnminimize( bool minimize ) +QRect Client::iconGeometry() const { -#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(); - QRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height ); - if ( !icongeom.isValid() ) - return; - - 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 ) + QRect geom( r.pos.x, r.pos.y, r.size.width, r.size.height ); + if( geom.isValid() ) + return geom; + else { - QFont font = options->font(isActive()); - QFontMetrics fm( font ); - QPixmap pm( w, fm.lineSpacing() ); - pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) ); - QPainter p( &pm ); - p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() )); - p.setFont(options->font(isActive())); - p.drawText( pm.rect(), Qt::AlignLeft|Qt::AlignVCenter|Qt::TextSingleLine, caption() ); - return pm; + // Check all mainwindows of this window (recursively) + foreach( Client* mainwin, mainClients() ) + { + geom = mainwin->iconGeometry(); + if( geom.isValid() ) + return geom; + } + // No mainwindow (or their parents) with icon geometry was found + return QRect(); + } } - bool Client::isShadeable() const { return !isSpecialWindow() && !noBorder(); @@ -745,19 +648,15 @@ void Client::setShade( ShadeMode mode ) } assert( decoration != NULL ); // noborder windows can't be shaded - GeometryUpdatesPostponer blocker( this ); + GeometryUpdatesBlocker blocker( this ); // decorations may turn off some borders when shaded 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 if ( isShade()) { // shade_mode == ShadeNormal - // we're about to shade, texx xcompmgr to prepare - long _shade = 1; - XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L); + addWorkspaceRepaint( geometry()); // shade - int h = height(); shade_geometry_change = true; QSize s( sizeForClientSize( QSize( clientSize()))); s.setHeight( border_top + border_bottom ); @@ -765,21 +664,6 @@ void Client::setShade( ShadeMode mode ) XUnmapWindow( display(), wrapper ); XUnmapWindow( display(), client ); 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 ); shade_geometry_change = false; if( isActive()) @@ -789,43 +673,24 @@ void Client::setShade( ShadeMode mode ) else 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 { - int h = height(); shade_geometry_change = true; 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; plainResize( s ); if( shade_mode == ShadeHover || shade_mode == ShadeActivated ) setActive( true ); XMapWindow( display(), wrapperId()); XMapWindow( display(), window()); - XDeleteProperty (display(), client, atoms->net_wm_window_shade); if ( isActive() ) workspace()->requestFocus( this ); } checkMaximizeGeometry(); info->setState( isShade() ? NET::Shaded : 0, NET::Shaded ); info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden ); + discardWindowPixmap(); updateVisibility(); updateAllowedActions(); workspace()->updateMinimizedOfTransients( this ); @@ -929,8 +794,8 @@ void Client::setMappingState(int s) XChangeProperty(display(), window(), atoms->wm_state, atoms->wm_state, 32, PropModeReplace, (unsigned char *)data, 2); - if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry - postponeGeometryUpdates( false ); + if( was_unmanaged ) // manage() did block_geometry_updates = 1, now it's ok to finally set the geometry + blockGeometryUpdates( false ); } /*! @@ -941,12 +806,17 @@ void Client::rawShow() { if( decoration != NULL ) decoration->widget()->show(); // not really necessary, but let it know the state - XMapWindow( display(), frame ); + XMapWindow( display(), frameId()); if( !isShade()) { XMapWindow( display(), wrapper ); 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() { + addWorkspaceRepaint( geometry()); // 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 // 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 // here. XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify - XUnmapWindow( display(), frame ); + XUnmapWindow( display(), frameId()); XUnmapWindow( display(), wrapper ); XUnmapWindow( display(), client ); XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask ); @@ -1197,6 +1068,17 @@ void Client::setDesktop( int desktop ) 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 ) { if(( b && isOnAllDesktops()) @@ -1208,11 +1090,6 @@ void Client::setOnAllDesktops( bool b ) setDesktop( workspace()->currentDesktop()); } -bool Client::isOnCurrentDesktop() const - { - return isOnDesktop( workspace()->currentDesktop()); - } - // performs activation and/or raising of the window void Client::takeActivity( int flags, bool handled, allowed_t ) { @@ -1308,7 +1185,7 @@ QString Client::readName() const 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 ) { @@ -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 { return ( isNormalWindow() || isDialog()) && wantsInput(); @@ -1625,89 +1383,12 @@ bool Client::wantsInput() const 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 { return isDesktop() || isDock() || isSplash() || isTopMenu() || 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 @@ -1804,46 +1485,10 @@ void Client::cancelAutoRaise() autoRaiseTimer = 0; } -#ifndef NDEBUG -kdbgstream& operator<<( kdbgstream& stream, const Client* cl ) +void Client::debug( kdbgstream& stream ) const { - if( cl == NULL ) - return stream << "\'NULL_CLIENT\'"; - return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'"; + stream << "\'ID:" << window() << ";WMCLASS:" << resourceClass() << ":" << resourceName() << ";Caption:" << 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() { diff --git a/events.cpp b/events.cpp index 70cbe54355..d81a841c8f 100644 --- a/events.cpp +++ b/events.cpp @@ -21,6 +21,9 @@ License. See the file "COPYING" for the exact licensing terms. #include "tabbox.h" #include "group.h" #include "rules.h" +#include "unmanaged.h" +#include "scene.h" +#include "effects.h" #include #include @@ -83,6 +86,10 @@ void WinInfo::changeState( unsigned long state, unsigned long mask ) m_client->setFullScreen( true, false ); } +void WinInfo::disable() + { + m_client = NULL; // only used when the object is passed to Deleted + } // **************************************** // RootInfo @@ -199,15 +206,10 @@ bool Workspace::workspaceEvent( XEvent * e ) XUngrabKeyboard( display(), xTime() ); } - if( e->type == PropertyNotify || e->type == ClientMessage ) + if ( e->type == PropertyNotify || e->type == ClientMessage ) { - unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ]; - rootInfo->event( e, dirty, NETRootInfo::PROPERTIES_SIZE ); - if( dirty[ NETRootInfo::PROTOCOLS ] & NET::DesktopNames ) - saveDesktopSettings(); - if( dirty[ NETRootInfo::PROTOCOLS2 ] & NET::WM2DesktopLayout ) - setDesktopLayout( rootInfo->desktopLayoutOrientation(), rootInfo->desktopLayoutColumnsRows().width(), - rootInfo->desktopLayoutColumnsRows().height(), rootInfo->desktopLayoutCorner()); + if ( netCheck( e ) ) + return true; } // events that should be handled before Clients can get them @@ -223,6 +225,8 @@ bool Workspace::workspaceEvent( XEvent * e ) tab_box->handleMouseEvent( e ); return true; } + if( effects && effects->checkInputWindowEvent( e )) + return true; break; case KeyPress: { @@ -267,6 +271,11 @@ bool Workspace::workspaceEvent( XEvent * e ) if( c->windowEvent( e )) return true; } + else if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xany.window ))) + { + if( c->windowEvent( e )) + return true; + } else { Window special = findSpecialEventWindow( e ); @@ -324,13 +333,8 @@ bool Workspace::workspaceEvent( XEvent * e ) } return true; } - 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: { //do not confuse Qt with these events. After all, _we_ are the @@ -380,6 +384,19 @@ bool Workspace::workspaceEvent( XEvent * e ) } 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: { if ( QWhatsThis::inWhatsThisMode() ) @@ -456,7 +473,29 @@ bool Workspace::workspaceEvent( XEvent * e ) if( electricBorder( e )) return true; 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: + 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; } 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 // **************************************** @@ -508,6 +561,7 @@ bool Client::windowEvent( XEvent* e ) if( e->xany.window == window()) // avoid doing stuff on frame or wrapper { unsigned long dirty[ 2 ]; + double old_opacity = opacity(); info->event( e, dirty, 2 ); // pass through the NET stuff if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 ) @@ -538,6 +592,21 @@ bool Client::windowEvent( XEvent* e ) if( demandAttentionKNotifyTimer != NULL ) 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? @@ -618,15 +687,25 @@ bool Client::windowEvent( XEvent* e ) workspace()->updateColormap(); } break; + case VisibilityNotify: + visibilityNotifyEvent( &e->xvisibility ); + break; default: if( e->xany.window == window()) - { - if( e->type == Shape::shapeEvent() ) { - is_shape = Shape::hasShape( window()); // workaround for #19644 - updateShape(); + if( e->type == Extensions::shapeNotifyEvent() ) + { + 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; } return true; // eat all events @@ -728,8 +807,6 @@ void Client::destroyNotifyEvent( XDestroyWindowEvent* e ) } -bool blockAnimation = false; - /*! Handles client messages for the client window */ @@ -742,14 +819,13 @@ void Client::clientMessageEvent( XClientMessageEvent* e ) { if( isTopMenu() && workspace()->managingTopMenus()) return; // kwin controls these - if( e->data.l[ 1 ] ) - blockAnimation = true; + bool avoid_animation = ( e->data.l[ 1 ] ); if( e->data.l[ 0 ] == IconicState ) minimize(); else if( e->data.l[ 0 ] == NormalState ) { // copied from mapRequest() if( isMinimized()) - unminimize(); + unminimize( avoid_animation ); if( isShade()) setShade( ShadeNone ); if( !isOnCurrentDesktop()) @@ -760,7 +836,6 @@ void Client::clientMessageEvent( XClientMessageEvent* e ) demandAttention(); } } - blockAnimation = false; } else if ( e->message_type == atoms->wm_change_state) { @@ -829,6 +904,7 @@ void Client::configureRequestEvent( XConfigureRequestEvent* e ) */ void Client::propertyNotifyEvent( XPropertyEvent* e ) { + Toplevel::propertyNotifyEvent( e ); if( e->window != window()) return; // ignore frame/wrapper switch ( e->atom ) @@ -852,10 +928,6 @@ void Client::propertyNotifyEvent( XPropertyEvent* e ) default: if ( e->atom == atoms->wm_protocols ) 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 ) getMotifHints(); break; @@ -995,13 +1067,18 @@ void Client::ungrabButton( int modifier ) */ 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() { // remove the grab for no modifiers only if the window // 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 ) ungrabButton( None ); 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 // for the decoration window cannot be (easily) intercepted as X11 events bool Client::eventFilter( QObject* o, QEvent* e ) @@ -1095,6 +1141,15 @@ bool Client::eventFilter( QObject* o, QEvent* e ) // on the decoration widget. if( ev->size() != size()) 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; } @@ -1436,6 +1491,17 @@ void Client::focusOutEvent( XFocusOutEvent* e ) 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 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; key_code = key_code & 0xffff; int delta = is_control?1:is_alt?32:8; - QPoint pos = QCursor::pos(); + QPoint pos = cursorPos(); switch ( key_code ) { case Qt::Key_Left: @@ -1530,6 +1596,104 @@ void Client::keyPressEvent( uint key_code ) 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 // **************************************** diff --git a/geometry.cpp b/geometry.cpp index b2944e1f55..96bce38390 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -28,6 +28,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "notifications.h" #include "geometrytip.h" #include "rules.h" +#include "effects.h" #include #include @@ -48,8 +49,14 @@ void Workspace::desktopResized() desktop_geometry.width = geom.width(); desktop_geometry.height = geom.height(); rootInfo->setDesktopGeometry( -1, desktop_geometry ); + updateClientArea(); 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 ) desktop = currentDesktop(); QDesktopWidget *desktopwidget = KApplication::desktop(); - int screen = desktopwidget->isVirtualDesktop() ? desktopwidget->screenNumber( p ) : desktopwidget->primaryScreen(); + int screen = desktopwidget->screenNumber( p ); if( screen < 0 ) screen = desktopwidget->primaryScreen(); 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()) { QRect orig_geometry = geometry(); - GeometryUpdatesPostponer blocker( this ); + GeometryUpdatesBlocker blocker( this ); move( new_pos ); plainResize( ns ); 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 { QRect orig_geometry = geometry(); - GeometryUpdatesPostponer blocker( this ); + GeometryUpdatesBlocker blocker( this ); int save_gravity = xSizeHint.win_gravity; xSizeHint.win_gravity = gravity; 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 ); } - if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h )) + if( force == NormalGeometrySet && geom == QRect( x, y, w, h )) return; - frame_geometry = QRect( x, y, w, h ); + geom = QRect( x, y, w, h ); updateWorkareaDiffs(); - if( postpone_geometry_updates != 0 ) + if( block_geometry_updates != 0 ) { pending_geometry_update = true; return; } - resizeDecoration( QSize( w, h )); - XMoveResizeWindow( display(), frameId(), x, y, w, h ); -// resizeDecoration( QSize( w, h )); - if( !isShade()) + if( geom_before_block.size() != geom.size()) { - QSize cs = clientSize(); - XMoveResizeWindow( display(), wrapperId(), clientPos().x(), clientPos().y(), - cs.width(), cs.height()); - XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height()); + resizeDecoration( QSize( w, h )); + XMoveResizeWindow( display(), frameId(), x, y, w, h ); + if( !isShade()) + { + 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? updateWorkareaDiffs(); sendSyntheticConfigureNotify(); updateWindowRules(); 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 ) @@ -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() << kBacktrace() << endl; } - if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h )) + if( force == NormalGeometrySet && geom.size() == QSize( w, h )) return; - frame_geometry.setSize( QSize( w, h )); + geom.setSize( QSize( w, h )); updateWorkareaDiffs(); - if( postpone_geometry_updates != 0 ) + if( block_geometry_updates != 0 ) { pending_geometry_update = true; return; @@ -1735,11 +1757,19 @@ void Client::plainResize( int w, int h, ForceGeometry_t force ) cs.width(), cs.height()); XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height()); } - updateShape(); + if( shape()) + updateShape(); updateWorkareaDiffs(); sendSyntheticConfigureNotify(); updateWindowRules(); 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 ) { - if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y )) + if( force == NormalGeometrySet && geom.topLeft() == QPoint( x, y )) return; - frame_geometry.moveTopLeft( QPoint( x, y )); + geom.moveTopLeft( QPoint( x, y )); updateWorkareaDiffs(); - if( postpone_geometry_updates != 0 ) + if( block_geometry_updates != 0 ) { pending_geometry_update = true; return; @@ -1760,20 +1790,23 @@ void Client::move( int x, int y, ForceGeometry_t force ) sendSyntheticConfigureNotify(); updateWindowRules(); 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::postponeGeometryUpdates( bool postpone ) +void Client::blockGeometryUpdates( bool block ) { - if( postpone ) + if( block ) { - if( postpone_geometry_updates == 0 ) + if( block_geometry_updates == 0 ) pending_geometry_update = false; - ++postpone_geometry_updates; + ++block_geometry_updates; } else { - if( --postpone_geometry_updates == 0 ) + if( --block_geometry_updates == 0 ) { if( pending_geometry_update ) { @@ -1822,7 +1855,7 @@ void Client::changeMaximize( bool vertical, bool horizontal, bool adjust ) if( !adjust && max_mode == old_mode ) return; - GeometryUpdatesPostponer blocker( this ); + GeometryUpdatesBlocker blocker( this ); // maximing one way and unmaximizing the other way shouldn't happen Q_ASSERT( !( vertical && horizontal ) @@ -2074,7 +2107,7 @@ void Client::setFullScreen( bool set, bool user ) if( was_fs == isFullScreen()) return; StackingUpdatesBlocker blocker1( workspace()); - GeometryUpdatesPostponer blocker2( this ); + GeometryUpdatesBlocker blocker2( this ); workspace()->updateClientLayer( this ); // active fullscreens get different layer info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen ); updateDecoration( false, false ); @@ -2230,7 +2263,7 @@ bool Client::startMoveResize() XMapRaised( display(), move_resize_grab_window ); if( XGrabPointer( display(), move_resize_grab_window, False, 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; if( XGrabKeyboard( display(), frameId(), False, GrabModeAsync, GrabModeAsync, xTime() ) == Success ) has_grab = true; @@ -2260,6 +2293,8 @@ bool Client::startMoveResize() // not needed anymore? kapp->installEventFilter( eater ); } Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart ); + if( effects ) + effects->windowUserMovedResized( effectWindow(), true, false ); return true; } @@ -2273,6 +2308,8 @@ void Client::finishMoveResize( bool cancel ) checkMaximizeGeometry(); // FRAME update(); Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd ); + if( effects ) + effects->windowUserMovedResized( effectWindow(), false, true ); } void Client::leaveMoveResize() @@ -2536,7 +2573,8 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) } if ( isMove() ) workspace()->clientMoved(globalPos, xTime()); + if( effects ) + effects->windowUserMovedResized( effectWindow(), false, false ); } - } // namespace diff --git a/kcmkwin/kwindecoration/kwindecoration.cpp b/kcmkwin/kwindecoration/kwindecoration.cpp index 779af351fc..9a3878929c 100644 --- a/kcmkwin/kwindecoration/kwindecoration.cpp +++ b/kcmkwin/kwindecoration/kwindecoration.cpp @@ -531,11 +531,8 @@ void KWinDecorationModule::save() emit pluginSave( kwinConfig ); kwinConfig.sync(); - // Send signal to all kwin instances - QDBusMessage message = - QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); - QDBusConnection::sessionBus().send(message); - + QDBusInterface kwin( "org.kde.kwin", "/KWin", "org.kde.KWin" ); + kwin.call( "reconfigure" ); } diff --git a/kcmkwin/kwinrules/detectwidget.cpp b/kcmkwin/kwinrules/detectwidget.cpp index 5d37fb5505..c815b4433f 100644 --- a/kcmkwin/kwinrules/detectwidget.cpp +++ b/kcmkwin/kwinrules/detectwidget.cpp @@ -40,8 +40,8 @@ namespace KWinInternal { -DetectWidget::DetectWidget( QWidget* parent ) -: DetectWidgetBase( parent ) +DetectWidget::DetectWidget( QWidget* parent, const char* name ) +: DetectWidgetBase( parent, name ) { } diff --git a/kcmkwin/kwinrules/detectwidget.h b/kcmkwin/kwinrules/detectwidget.h index 8ba3a661ae..21eaf6c025 100644 --- a/kcmkwin/kwinrules/detectwidget.h +++ b/kcmkwin/kwinrules/detectwidget.h @@ -20,7 +20,7 @@ #ifndef __DETECTWIDGET_H__ #define __DETECTWIDGET_H__ -#include "ui_detectwidgetbase.h" +#include "detectwidgetbase.h" #include #include @@ -33,21 +33,12 @@ namespace KWinInternal { -class DetectWidgetBase : public QWidget, public Ui::DetectWidgetBase -{ -public: - DetectWidgetBase( QWidget *parent ) : QWidget( parent ) { - setupUi( this ); - } -}; - - class DetectWidget : public DetectWidgetBase { Q_OBJECT public: - DetectWidget( QWidget* parent = NULL ); + DetectWidget( QWidget* parent = NULL, const char* name = NULL ); }; class DetectDialog diff --git a/kcmkwin/kwinrules/main.cpp b/kcmkwin/kwinrules/main.cpp index d72e978e6f..6f6e31a89f 100644 --- a/kcmkwin/kwinrules/main.cpp +++ b/kcmkwin/kwinrules/main.cpp @@ -22,6 +22,7 @@ #include #include #include + #include #include @@ -255,10 +256,8 @@ static int edit( Window wid, bool whole_app ) delete orig_rule; } saveRules( rules ); - // Send signal to all kwin instances - QDBusMessage message = - QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); - QDBusConnection::sessionBus().send(message); + QDBusInterface kwin( "org.kde.kwin", "/KWin", "org.kde.KWin" ); + kwin.call( "reconfigure" ); return 0; } diff --git a/kcmkwin/kwinrules/ruleswidget.cpp b/kcmkwin/kwinrules/ruleswidget.cpp index d145b706cb..63b0214281 100644 --- a/kcmkwin/kwinrules/ruleswidget.cpp +++ b/kcmkwin/kwinrules/ruleswidget.cpp @@ -383,16 +383,16 @@ void RulesWidget::setRules( Rules* rules ) role->setText( rules->windowrole ); role_match->setCurrentIndex( rules->windowrolematch ); roleMatchChanged(); - types->item(0)->setSelected( rules->types & NET::NormalMask ); - types->item(1)->setSelected( rules->types & NET::DialogMask ); - types->item(2)->setSelected( rules->types & NET::UtilityMask ); - types->item(3)->setSelected( rules->types & NET::DockMask ); - types->item(4)->setSelected( rules->types & NET::ToolbarMask ); - types->item(5)->setSelected( rules->types & NET::MenuMask ); - types->item(6)->setSelected( rules->types & NET::SplashMask ); - types->item(7)->setSelected( rules->types & NET::DesktopMask ); - types->item(8)->setSelected( rules->types & NET::OverrideMask ); - types->item(9)->setSelected( rules->types & NET::TopMenuMask ); + types->setSelected( 0, rules->types & NET::NormalMask ); + types->setSelected( 1, rules->types & NET::DialogMask ); + types->setSelected( 2, rules->types & NET::UtilityMask ); + types->setSelected( 3, rules->types & NET::DockMask ); + types->setSelected( 4, rules->types & NET::ToolbarMask ); + types->setSelected( 5, rules->types & NET::MenuMask ); + types->setSelected( 6, rules->types & NET::SplashMask ); + types->setSelected( 7, rules->types & NET::DesktopMask ); + types->setSelected( 8, rules->types & NET::OverrideMask ); + types->setSelected( 9, rules->types & NET::TopMenuMask ); title->setText( rules->title ); title_match->setCurrentIndex( rules->titlematch ); titleMatchChanged(); @@ -466,25 +466,25 @@ Rules* RulesWidget::rules() const rules->windowrolematch = static_cast< Rules::StringMatch >( role_match->currentIndex()); rules->types = 0; bool all_types = true; - for( int i = 0; + for( unsigned int i = 0; i < types->count(); ++i ) - if( !types->item(i)->isSelected()) + if( !types->isSelected( i )) all_types = false; if( all_types ) // if all types are selected, use AllTypesMask (for future expansion) rules->types = NET::AllTypesMask; else { - rules->types |= types->item(0)->isSelected() ? NET::NormalMask : 0; - rules->types |= types->item(1)->isSelected() ? NET::DialogMask : 0; - rules->types |= types->item(2)->isSelected() ? NET::UtilityMask : 0; - rules->types |= types->item(3)->isSelected() ? NET::DockMask : 0; - rules->types |= types->item(4)->isSelected() ? NET::ToolbarMask : 0; - rules->types |= types->item(5)->isSelected() ? NET::MenuMask : 0; - rules->types |= types->item(6)->isSelected() ? NET::SplashMask : 0; - rules->types |= types->item(7)->isSelected() ? NET::DesktopMask : 0; - rules->types |= types->item(8)->isSelected() ? NET::OverrideMask : 0; - rules->types |= types->item(9)->isSelected() ? NET::TopMenuMask : 0; + rules->types |= types->isSelected( 0 ) ? NET::NormalMask : 0; + rules->types |= types->isSelected( 1 ) ? NET::DialogMask : 0; + rules->types |= types->isSelected( 2 ) ? NET::UtilityMask : 0; + rules->types |= types->isSelected( 3 ) ? NET::DockMask : 0; + rules->types |= types->isSelected( 4 ) ? NET::ToolbarMask : 0; + rules->types |= types->isSelected( 5 ) ? NET::MenuMask : 0; + rules->types |= types->isSelected( 6 ) ? NET::SplashMask : 0; + rules->types |= types->isSelected( 7 ) ? NET::DesktopMask : 0; + rules->types |= types->isSelected( 8 ) ? NET::OverrideMask : 0; + rules->types |= types->isSelected( 9 ) ? NET::TopMenuMask : 0; } rules->title = title->text(); rules->titlematch = static_cast< Rules::StringMatch >( title_match->currentIndex()); @@ -567,19 +567,19 @@ void RulesWidget::detected( bool ok ) roleMatchChanged(); if( detect_dlg->selectedWholeApp()) { - for( int i = 0; + for( unsigned int i = 0; i < types->count(); ++i ) - types->item(i)->setSelected( true ); + types->setSelected( i, true ); } else { NET::WindowType type = detect_dlg->selectedType(); - for( int i = 0; + for( unsigned int i = 0; i < types->count(); ++i ) - types->item(i)->setSelected( false ); - types->item( typeToCombo(type) )->setSelected( true ); + types->setSelected( i, false ); + types->setSelected( typeToCombo( type ), true ); } title->setText( detect_dlg->selectedTitle()); title_match->setCurrentIndex( detect_dlg->titleMatch()); @@ -653,10 +653,10 @@ bool RulesWidget::finalCheck() description->setText( i18n( "Unnamed entry" )); } bool all_types = true; - for( int i = 0; + for( unsigned int i = 0; i < types->count(); ++i ) - if( !types->item(i)->isSelected()) + if( !types->isSelected( i )) all_types = false; if( wmclass_match->currentIndex() == Rules::UnimportantMatch && all_types ) { @@ -680,7 +680,7 @@ void RulesWidget::prepareWindowSpecific( WId window ) void RulesWidget::shortcutEditClicked() { #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 #if 0 EditShortcutDialog dlg( topLevelWidget()); diff --git a/lib/kdecoration_plugins_p.cpp b/lib/kdecoration_plugins_p.cpp index 026d76a544..d6d3f4973a 100644 --- a/lib/kdecoration_plugins_p.cpp +++ b/lib/kdecoration_plugins_p.cpp @@ -32,6 +32,7 @@ DEALINGS IN THE SOFTWARE. #include #include #include +#include #include #include diff --git a/useractions.cpp b/useractions.cpp index 3d1c52356a..87e30da55d 100644 --- a/useractions.cpp +++ b/useractions.cpp @@ -19,6 +19,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "client.h" #include "workspace.h" +#include "effects.h" #include #include @@ -60,7 +61,7 @@ QMenu* Workspace::clientPopup() advanced_popup->setFont(KGlobalSettings::menuFont()); mKeepAboveOpAction = advanced_popup->addAction( i18n("Keep &Above Others") ); - mKeepAboveOpAction->setIcon( KIcon( "go-up" ) ); + mKeepAboveOpAction->setIcon( KIcon( "up" ) ); KAction *kaction = qobject_cast( keys->action("Window Above Other Windows") ); if ( kaction!=0 ) mKeepAboveOpAction->setShortcut( kaction->globalShortcut().primary() ); @@ -68,7 +69,7 @@ QMenu* Workspace::clientPopup() mKeepAboveOpAction->setData( Options::KeepAboveOp ); mKeepBelowOpAction = advanced_popup->addAction( i18n("Keep &Below Others") ); - mKeepBelowOpAction->setIcon( KIcon( "go-down" ) ); + mKeepBelowOpAction->setIcon( KIcon( "down" ) ); kaction = qobject_cast( keys->action("Window Below Other Windows") ); if ( kaction!=0 ) mKeepBelowOpAction->setShortcut( kaction->globalShortcut().primary() ); @@ -76,7 +77,7 @@ QMenu* Workspace::clientPopup() mKeepBelowOpAction->setData( Options::KeepBelowOp ); mFullScreenOpAction = advanced_popup->addAction( i18n("&Fullscreen") ); - mFullScreenOpAction->setIcon( KIcon( "view-fullscreen" ) ); + mFullScreenOpAction->setIcon( KIcon( "window_fullscreen" ) ); kaction = qobject_cast( keys->action("Window Fullscreen") ); if ( kaction!=0 ) mFullScreenOpAction->setShortcut( kaction->globalShortcut().primary() ); @@ -111,22 +112,18 @@ QMenu* Workspace::clientPopup() desk_popup_index = popup->actions().count(); if (options->useTranslucency){ - QMenu *trans_popup = new QMenu( popup ); - QVBoxLayout *transLayout = new QVBoxLayout(trans_popup); - trans_popup->setLayout( transLayout ); - transButton = new QPushButton(trans_popup); - transButton->setObjectName("transButton"); - transButton->setToolTip( i18n("Reset opacity to default value")); - transSlider = new QSlider(trans_popup); - transSlider->setObjectName( "transSlider" ); - transSlider->setRange( 0, 100 ); - transSlider->setValue( 100 ); - transSlider->setOrientation( Qt::Vertical ); - 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))); + trans_popup = new QMenu( popup ); + trans_popup->setFont(KGlobalSettings::menuFont()); + connect( trans_popup, SIGNAL( triggered(QAction*) ), this, SLOT( setPopupClientOpacity(QAction*))); + const int levels[] = { 100, 90, 75, 50, 25, 10 }; + for( unsigned int i = 0; + i < sizeof( levels ) / sizeof( levels[ 0 ] ); + ++i ) + { + action = trans_popup->addAction( QString::number( levels[ i ] ) + "%" ); + action->setCheckable( true ); + action->setData( levels[ i ] ); + } action = popup->addMenu( trans_popup ); action->setText( i18n("&Opacity") ); } @@ -176,7 +173,7 @@ QMenu* Workspace::clientPopup() } mCloseOpAction = popup->addAction( i18n("&Close") ); - mCloseOpAction->setIcon( KIcon( "window-close" ) ); + mCloseOpAction->setIcon( KIcon( "fileclose" ) ); kaction = qobject_cast( keys->action("Window Close") ); if ( kaction!=0 ) mCloseOpAction->setShortcut( kaction->globalShortcut().primary() ); @@ -185,31 +182,14 @@ QMenu* Workspace::clientPopup() return popup; } -//sets the transparency of the client to given value(given by slider) -void Workspace::setPopupClientOpacity(int value) +void Workspace::setPopupClientOpacity( QAction* action ) { - // 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. @@ -244,6 +224,16 @@ void Workspace::clientPopupAboutToShow() mNoBorderOpAction->setChecked( active_popup_client->noBorder() ); mMinimizeOpAction->setEnabled( active_popup_client->isMinimizable() ); 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 ) return; @@ -457,19 +447,19 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op ) QCursor::setPos( c->geometry().center() ); if (op == Options::ResizeOp || op == Options::UnrestrictedResizeOp ) QCursor::setPos( c->geometry().bottomRight()); - switch ( op ) + switch ( op ) { case Options::MoveOp: - c->performMouseCommand( Options::MouseMove, QCursor::pos() ); + c->performMouseCommand( Options::MouseMove, cursorPos() ); break; case Options::UnrestrictedMoveOp: - c->performMouseCommand( Options::MouseUnrestrictedMove, QCursor::pos() ); + c->performMouseCommand( Options::MouseUnrestrictedMove, cursorPos() ); break; case Options::ResizeOp: - c->performMouseCommand( Options::MouseResize, QCursor::pos() ); + c->performMouseCommand( Options::MouseResize, cursorPos() ); break; case Options::UnrestrictedResizeOp: - c->performMouseCommand( Options::MouseUnrestrictedResize, QCursor::pos() ); + c->performMouseCommand( Options::MouseUnrestrictedResize, cursorPos() ); break; case Options::CloseOp: c->closeWindow(); @@ -491,7 +481,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op ) c->minimize(); break; case Options::ShadeOp: - c->performMouseCommand( Options::MouseShade, QCursor::pos()); + c->performMouseCommand( Options::MouseShade, cursorPos()); break; case Options::OnAllDesktopsOp: c->setOnAllDesktops( !c->isOnAllDesktops() ); @@ -521,7 +511,7 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op ) break; } case Options::OperationsOp: - c->performMouseCommand( Options::MouseShade, QCursor::pos()); + c->performMouseCommand( Options::MouseShade, cursorPos()); break; case Options::WindowRulesOp: 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 replay = false; - switch (command) + switch (command) { case Options::MouseRaise: workspace()->raiseClient( this ); @@ -686,10 +676,10 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo workspace()->windowToNextDesktop( this ); break; case Options::MouseOpacityMore: - // TODO + setOpacity( qMin( opacity() + 0.1, 1.0 )); break; case Options::MouseOpacityLess: - // TODO + setOpacity( qMax( opacity() - 0.1, 0.0 )); break; case Options::MouseNothing: replay = true; @@ -704,6 +694,18 @@ void Workspace::showWindowMenuAt( unsigned long, int, int ) 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() { if( attention_chain.count() > 0 ) @@ -713,13 +715,13 @@ void Workspace::slotActivateAttentionWindow() void Workspace::slotSwitchDesktopNext() { int d = currentDesktop() + 1; - if ( d > numberOfDesktops() ) + if ( d > numberOfDesktops() ) { - if ( options->rollOverDesktops ) + if ( options->rollOverDesktops ) { d = 1; } - else + else { return; } @@ -730,7 +732,7 @@ void Workspace::slotSwitchDesktopNext() void Workspace::slotSwitchDesktopPrevious() { int d = currentDesktop() - 1; - if ( d <= 0 ) + if ( d <= 0 ) { if ( options->rollOverDesktops ) d = numberOfDesktops(); @@ -915,7 +917,7 @@ void Workspace::slotWindowToNextDesktop() { windowToNextDesktop( active_popup_client ? active_popup_client : active_client ); } - + void Workspace::windowToNextDesktop( Client* c ) { int d = currentDesktop() + 1; @@ -937,7 +939,7 @@ void Workspace::slotWindowToPreviousDesktop() { windowToPreviousDesktop( active_popup_client ? active_popup_client : active_client ); } - + void Workspace::windowToPreviousDesktop( Client* c ) { int d = currentDesktop() - 1; @@ -1032,7 +1034,7 @@ void Workspace::slotSendToDesktop( QAction *action ) int desk = action->data().toInt(); if ( !active_popup_client ) return; - if ( desk == 0 ) + if ( desk == 0 ) { // the 'on_all_desktops' menu entry active_popup_client->setOnAllDesktops( !active_popup_client->isOnAllDesktops()); return; @@ -1191,7 +1193,7 @@ bool Workspace::shortcutAvailable( const KShortcut& cut, Client* ignore ) const ++it ) { if( (*it) != ignore && (*it)->shortcut() == cut ) - return false; + return false; } return true; } diff --git a/utils.cpp b/utils.cpp index 3d89097e9d..34630230d7 100644 --- a/utils.cpp +++ b/utils.cpp @@ -25,11 +25,13 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include +#include #include #include #include #include + #include #include "atoms.h" @@ -42,19 +44,68 @@ namespace KWinInternal #ifndef KCMRULES -// used to store the return values of -// XShapeQueryExtension. -// Necessary since shaped window are an extension to X -int Shape::kwin_shape_version = 0; -int Shape::kwin_shape_event = 0; +bool Extensions::has_shape = false; +int Extensions::shape_event_base = 0; +bool Extensions::has_randr = false; +int Extensions::randr_event_base = 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? -bool Shape::hasShape( WId w) +void Extensions::init() + { + 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; unsigned int wws, hws, wbs, hbs; int boundingShaped = 0, clipShaped = 0; - if (!available()) + if( !Extensions::shapeAvailable()) return false; XShapeQueryExtents(display(), w, &boundingShaped, &xws, &yws, &wws, &hws, @@ -62,21 +113,22 @@ bool Shape::hasShape( WId w) 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; - int dummy; - if( !XShapeQueryExtension( display(), &kwin_shape_event, &dummy )) - return; - int major, minor; - if( !XShapeQueryVersion( display(), &major, &minor )) - return; - kwin_shape_version = major * 0x10 + minor; +#ifdef HAVE_XDAMAGE + return damage_event_base + XDamageNotify; +#else + return 0; +#endif } void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move, @@ -301,6 +353,93 @@ bool grabbedXServer() 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 bool isLocalMachine( const QByteArray& host ) @@ -369,7 +508,6 @@ void ShortcutDialog::accept() } #endif //0 #endif //KCMRULES - } // namespace #ifndef KCMRULES diff --git a/utils.h b/utils.h index 5e66722308..6e679355ab 100644 --- a/utils.h +++ b/utils.h @@ -12,6 +12,33 @@ License. See the file "COPYING" for the exact licensing terms. #ifndef KWIN_UTILS_H #define KWIN_UTILS_H +#include +#include +#include + +#include + +#ifdef HAVE_XRANDR +#include +#endif + +#ifdef HAVE_XCOMPOSITE +#include +#if XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR >= 3 +#define HAVE_XCOMPOSITE_OVERLAY +#endif +#endif + +#ifdef HAVE_XDAMAGE +#include +#endif + +#ifdef HAVE_XFIXES +#include +#endif + +#include + #include #include #include @@ -22,9 +49,17 @@ License. See the file "COPYING" for the exact licensing terms. namespace KWinInternal { +#ifndef HAVE_XDAMAGE +typedef long Damage; +struct XDamageNotifyEvent + { + }; +#endif + const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask | 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 | ButtonPressMask | ButtonReleaseMask | @@ -39,12 +74,21 @@ const long ClientWinMask = KeyPressMask | KeyReleaseMask | const QPoint invalidPoint( INT_MIN, INT_MIN ); +class Toplevel; class Client; +class Unmanaged; +class Deleted; class Group; class Options; +typedef QList< Toplevel* > ToplevelList; +typedef QList< const Toplevel* > ConstToplevelList; typedef QList< Client* > ClientList; 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< const Group* > ConstGroupList; @@ -87,6 +131,7 @@ enum allowed_t { Allowed }; // some enums to have more readable code, instead of using bools enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet }; + // Areas, mostly related to Xinerama enum clientAreaOption { @@ -109,24 +154,32 @@ enum ShadeMode ShadeActivated // "shaded", but visible due to alt+tab to the window }; -class Shape +class Extensions { 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 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: - static int kwin_shape_version; - static int kwin_shape_event; + static bool has_shape; + 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 { public: @@ -226,34 +279,40 @@ int displayHeight() 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 #ifndef UrgencyHint #define UrgencyHint XUrgencyHint #endif // for STL-like algo's -#define KWIN_CHECK_PREDICATE( name, check ) \ +#define KWIN_CHECK_PREDICATE( name, cls, check ) \ 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 \ { \ 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 bool operator()( const Client* cl ) { return check; } \ + inline name( const type_helper& compare_value ) : value( compare_value ) {}; \ + inline bool operator()( const cls* cl ) { return check; }; \ const type_helper& value; \ } -#define KWIN_PROCEDURE( name, action ) \ +#define KWIN_PROCEDURE( name, cls, action ) \ 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 > Client* findClientInList( const ClientList& list, T predicate ) @@ -266,6 +325,17 @@ Client* findClientInList( const ClientList& list, T predicate ) 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 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 ); -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 // Qt dialogs emit no signal when closed :( diff --git a/workspace.cpp b/workspace.cpp index f6c8b5be8a..1fcc55a0aa 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -43,6 +43,10 @@ License. See the file "COPYING" for the exact licensing terms. #include "group.h" #include "rules.h" #include "kwinadaptor.h" +#include "unmanaged.h" +#include "scene.h" +#include "deleted.h" +#include "effects.h" #include #include @@ -76,7 +80,6 @@ Workspace::Workspace( bool restore ) active_popup_client( NULL ), desktop_widget (0), temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL, false ), - rules_updates_disabled( false ), active_client (0), last_active_client (0), most_recently_raised (0), @@ -95,6 +98,7 @@ Workspace::Workspace( bool restore ) popupinfo (0), popup (0), advanced_popup (0), + trans_popup (0), desk_popup (0), desk_popup_index (0), keys (0), @@ -124,12 +128,16 @@ Workspace::Workspace( bool restore ) topmenu_space( NULL ), set_active_client_recursion( 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 ); - QDBusConnection dbus = QDBusConnection::sessionBus(); - dbus.registerObject("/KWin", this); - dbus.connect(QString(), "/KWin", "org.kde.KWin", "reloadConfig", this, SLOT(slotReloadConfig())); + QDBusConnection::sessionBus().registerObject("/KWin", this); + _self = this; mgr = new PluginMgr; root = rootWindow(); @@ -170,10 +178,12 @@ Workspace::Workspace( bool restore ) ColormapChangeMask | SubstructureRedirectMask | SubstructureNotifyMask | - FocusChangeMask // for NotifyDetailNone + FocusChangeMask | // for NotifyDetailNone + ExposureMask ); - Shape::init(); + Extensions::init(); + setupCompositing(); // compatibility long data = 1; @@ -279,7 +289,6 @@ void Workspace::init() NET::WM2ExtendedStrut | NET::WM2KDETemporaryRules | NET::WM2ShowingDesktop | - NET::WM2DesktopLayout | 0 , NET::ActionMove | @@ -323,6 +332,7 @@ void Workspace::init() connect(&reconfigureTimer, SIGNAL(timeout()), this, SLOT(slotReconfigure())); connect( &updateToolWindowsTimer, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows())); + connect( &compositeTimer, SIGNAL( timeout()), SLOT( performCompositing())); connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this, SLOT(slotReconfigure())); @@ -360,7 +370,10 @@ void Workspace::init() XWindowAttributes attr; XGetWindowAttributes(display(), wins[i], &attr); if (attr.override_redirect ) + { + createUnmanaged( wins[ i ] ); continue; + } if( topmenu_space && topmenu_space->winId() == wins[ i ] ) continue; if (attr.map_state != IsUnmapped) @@ -422,6 +435,7 @@ void Workspace::init() Workspace::~Workspace() { + finishCompositing(); blockStackingUpdates( true ); // TODO grabXServer(); // use stacking_order, so that kwin --replace keeps stacking order @@ -431,12 +445,12 @@ Workspace::~Workspace() { // only release the window (*it)->releaseWindow( true ); - // No removeClient() is called, it does more than just removing. - // However, remove from some lists to e.g. prevent performTransiencyCheck() - // from crashing. - clients.remove( *it ); - desktops.remove( *it ); + // no removeClient() is called ! } + for( UnmanagedList::ConstIterator it = unmanaged.begin(); + it != unmanaged.end(); + ++it ) + (*it)->release(); delete desktop_widget; delete tab_box; delete popupinfo; @@ -480,6 +494,28 @@ Client* Workspace::createClient( Window w, bool is_mapped ) return NULL; } 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; } @@ -520,7 +556,13 @@ void Workspace::addClient( Client* c, allowed_t ) updateStackingOrder( true ); // propagate new client if( c->isUtility() || c->isMenu() || c->isToolbar()) 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()) Notify::raise( Notify::Delete ); + if( tab_grab ) + { + if( tab_box->currentClient() == c ) + tab_box->nextPrev( true ); + } + Q_ASSERT( clients.contains( c ) || desktops.contains( c )); clients.removeAll( c ); desktops.removeAll( c ); @@ -571,12 +619,34 @@ void Workspace::removeClient( Client* c, allowed_t ) updateStackingOrder( true ); - if (tab_grab) - tab_box->repaint(); + if( tab_grab ) + tab_box->reset( true ); 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 ) { 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 ); } else if( !focus_chain[ i ].contains( c )) - { // add it after the active 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 - } + focus_chain[ i ].prepend( c ); // otherwise add as the last one } } 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 ); } else if( !focus_chain[ i ].contains( c )) - { // add it after the active 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 - } + focus_chain[ i ].prepend( c ); } else focus_chain[ i ].removeAll( c ); @@ -651,13 +709,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change ) global_focus_chain.prepend( c ); } else if( !global_focus_chain.contains( c )) - { // add it after the active one - 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 - } + global_focus_chain.prepend( c ); } void Workspace::updateCurrentTopMenu() @@ -875,11 +927,6 @@ void Workspace::updateColormap() } } -void Workspace::slotReloadConfig() -{ - reconfigure(); -} - void Workspace::reconfigure() { reconfigureTimer.start( 200 ); @@ -896,7 +943,7 @@ void Workspace::slotSettingsChanged(int category) /*! Reread settings */ -KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() ); +KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes() ); void Workspace::slotReconfigure() { @@ -953,6 +1000,11 @@ void Workspace::slotReconfigure() updateTopMenuGeometry(); updateCurrentTopMenu(); } + + if( options->useTranslucency ) + setupCompositing(); + else + finishCompositing(); loadWindowRules(); 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), // conserve focus (thanks to Volker Schatz ) else if( active_client && active_client->isShown( true ) && active_client->isOnCurrentDesktop()) - c = active_client; - - if( c == NULL && !desktops.isEmpty()) - c = findDesktop( true, currentDesktop()); + c= active_client; if( c != active_client ) setActiveClient( NULL, Allowed ); if ( c ) requestFocus( c ); + else if( !desktops.isEmpty() ) + requestFocus( findDesktop( true, currentDesktop())); else focusToNull(); @@ -1266,6 +1317,10 @@ bool Workspace::setCurrentDesktop( int new_desktop ) if( old_desktop != 0 ) // not for the very first time popupinfo->showInfo( desktopName(currentDesktop()) ); + + if( effects != NULL && old_desktop != 0 ) + effects->desktopChanged( old_desktop ); + return true; } @@ -1498,26 +1553,25 @@ void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate ) 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 = ( o == NET::OrientationHorizontal ? Qt::Horizontal : Qt::Vertical ); + layoutOrientation = (Qt::Orientation) o; layoutX = x; layoutY = y; } 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; - if((x <= 0) && (y > 0)) + if ((x == -1) && (y > 0)) x = (numberOfDesktops()+y-1) / y; - else if((y <=0) && (x > 0)) + else if ((y == -1) && (x > 0)) y = (numberOfDesktops()+x-1) / x; - if(x <=0) + if (x == -1) x = 1; - if (y <= 0) + if (y == -1) y = 1; } @@ -1649,7 +1703,7 @@ void Workspace::slotGrabWindow() QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() ); //No XShape - no work. - if( Shape::available()) + if( Extensions::shapeAvailable()) { //As the first step, get the mask from XShape. int count, order; @@ -1850,7 +1904,7 @@ bool Workspace::keyPressMouseEmulation( XKeyEvent& ev ) bool is_alt = km & Mod1Mask; bool is_shift = km & ShiftMask; int delta = is_control?1:is_alt?32:8; - QPoint pos = QCursor::pos(); + QPoint pos = cursorPos(); switch ( kc ) { @@ -2002,7 +2056,8 @@ void Workspace::createBorderWindows() XSetWindowAttributes attributes; unsigned long valuemask; attributes.override_redirect = True; - attributes.event_mask = ( EnterWindowMask | LeaveWindowMask ); + attributes.event_mask = (EnterWindowMask | LeaveWindowMask | + VisibilityChangeMask); valuemask= (CWOverrideRedirect | CWEventMask | CWCursor ); attributes.cursor = XCreateFontCursor(display(), XC_sb_up_arrow); @@ -2394,7 +2449,7 @@ void Workspace::helperDialog( const QString& message, const Client* c ) { KConfig cfg( "kwin_dialogsrc" ); 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 proc << "--dontagain" << "kwin_dialogsrc:" + type; } diff --git a/workspace.h b/workspace.h index 35f83690b3..8636c48c58 100644 --- a/workspace.h +++ b/workspace.h @@ -18,6 +18,8 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include +#include +#include #include "utils.h" #include "kdecoration.h" @@ -34,7 +36,6 @@ class KStartupInfoId; class KStartupInfoData; class QSlider; class QPushButton; -class K3Process; namespace KWinInternal { @@ -77,7 +78,7 @@ class Workspace : public QObject, public KDecorationDefines virtual ~Workspace(); static Workspace * self() { return _self; } - + bool workspaceEvent( XEvent * ); KDecoration* createDecoration( KDecorationBridge* bridge ); @@ -87,6 +88,9 @@ class Workspace : public QObject, public KDecorationDefines template< typename T > Client* findClient( T predicate ); template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate ); 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 Client* c ) const; @@ -165,12 +169,22 @@ class Workspace : public QObject, public KDecorationDefines QWidget* desktopWidget(); // for TabBox - Client* nextFocusChainClient(Client*) const; - Client* previousFocusChainClient(Client*) const; - Client* nextStaticClient(Client*) const; - Client* previousStaticClient(Client*) const; + Client* currentTabBoxClient() const; + ClientList currentTabBoxClientList() const; + int currentTabBoxDesktop() 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 previousDesktopFocusChain( int iDesktop ) const; + int nextDesktopStatic( int iDesktop ) const; + int previousDesktopStatic( int iDesktop ) const; + void refTabBox(); + void unrefTabBox(); void closeTabBox(); /** @@ -181,7 +195,7 @@ class Workspace : public QObject, public KDecorationDefines 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; void sendClientToDesktop( Client* c, int desktop, bool dont_activate ); 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 :( 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 * it's not already. @@ -213,8 +231,6 @@ class Workspace : public QObject, public KDecorationDefines WindowRules findWindowRules( const Client*, bool ); void rulesUpdated(); void discardUsedWindowRules( Client* c, bool withdraw ); - void disableRulesUpdates( bool disable ); - bool rulesUpdatesDisabled() const; // dcop interface void cascadeDesktop(); @@ -226,7 +242,7 @@ class Workspace : public QObject, public KDecorationDefines void circulateDesktopApplications(); 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 resetShowingDesktop( bool keep_hidden ); bool showingDesktop() const; @@ -236,14 +252,17 @@ class Workspace : public QObject, public KDecorationDefines void sendPingToWindow( Window w, Time timestamp ); // called from Client::pingWindow() 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 ); + void removeClient( Client*, allowed_t ); // only called from Client::destroyClient() or Client::releaseWindow() void setActiveClient( Client*, allowed_t ); Group* findGroup( Window leader ) const; void addGroup( Group* group, allowed_t ); void removeGroup( Group* group, allowed_t ); 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 ); void focusToNull(); // SELI public? @@ -279,6 +298,19 @@ class Workspace : public QObject, public KDecorationDefines 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: void refresh(); // keybindings @@ -408,15 +440,14 @@ class Workspace : public QObject, public KDecorationDefines void cleanupTemporaryRules(); void writeWindowRules(); void slotBlockShortcuts(int data); - void slotReloadConfig(); - // kompmgr - void setPopupClientOpacity(int v); - void resetClientOpacity(); - void setTransButtonText(int value); - // end + void setPopupClientOpacity( QAction* action ); + void setupCompositing(); + void performCompositing(); + void lostCMSelection(); protected: bool keyPressMouseEmulation( XKeyEvent& ev ); + bool netCheck( XEvent* e ); private: void init(); @@ -460,6 +491,8 @@ class Workspace : public QObject, public KDecorationDefines // this is the right way to create a new client Client* createClient( Window w, bool is_mapped ); void addClient( Client* c, allowed_t ); + Unmanaged* createUnmanaged( Window w ); + void addUnmanaged( Unmanaged* c, allowed_t ); Window findSpecialEventWindow( XEvent* e ); @@ -501,6 +534,9 @@ class Workspace : public QObject, public KDecorationDefines void closeActivePopup(); void updateClientArea( bool force ); + + void finishCompositing(); + bool windowRepaintsPending() const; SystemTrayWindowList systemTrayWins; @@ -521,7 +557,6 @@ class Workspace : public QObject, public KDecorationDefines QList rules; KXMessages temporaryRulesMessages; QTimer rulesUpdatedTimer; - bool rules_updates_disabled; static const char* windowTypeToTxt( NET::WindowType type ); static NET::WindowType txtToWindowType( const char* txt ); static bool sessionInfoWindowTypeMatch( Client* c, SessionInfo* info ); @@ -538,10 +573,12 @@ class Workspace : public QObject, public KDecorationDefines ClientList clients; ClientList desktops; + UnmanagedList unmanaged; + DeletedList deleted; - ClientList unconstrained_stacking_order; // topmost last - ClientList stacking_order; // topmost last - QVector< ClientList > focus_chain; // currently ative last + ClientList unconstrained_stacking_order; + ClientList stacking_order; + QVector< ClientList > focus_chain; ClientList global_focus_chain; // this one is only for things like tabbox's MRU ClientList should_get_focus; // last is most recent ClientList attention_chain; @@ -575,6 +612,7 @@ class Workspace : public QObject, public KDecorationDefines QMenu *popup; QMenu *advanced_popup; + QMenu *trans_popup; QMenu *desk_popup; int desk_popup_index; @@ -658,12 +696,14 @@ class Workspace : public QObject, public KDecorationDefines bool forced_global_mouse_grab; friend class StackingUpdatesBlocker; - //kompmgr + KSelectionOwner* cm_selection; + QTimer compositeTimer; + QTime lastCompositePaint; + int compositeRate; + QRegion repaints_region; + Window overlay; // XComposite overlay window QSlider *transSlider; QPushButton *transButton; - - private: - friend bool performTransiencyCheck(); }; // helper for Workspace::blockStackingUpdates() being called in pairs (true/false) @@ -688,6 +728,7 @@ class RootInfo : public NETRootInfo protected: virtual void changeNumberOfDesktops(int n); 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 closeWindow(Window w); 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; } -inline -bool Workspace::rulesUpdatesDisabled() const +inline Window Workspace::overlayWindow() { - return rules_updates_disabled; + return overlay; } template< typename T > @@ -838,7 +878,27 @@ inline void Workspace::forEachClient( T procedure ) 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 ) { return findClient( ClientMatchPredicate( c ));