From 02032f85875ee9ccf3ff3af3d8eeecf582a42561 Mon Sep 17 00:00:00 2001 From: Rivo Laks Date: Tue, 10 Apr 2007 18:47:13 +0000 Subject: [PATCH] Move most (all?) internal methods from EffectsHandler to EffectsHandlerImpl. The ugly side effect of this is that there are tons of static_casts in the code now... maybe it would be better to add effectImpl() convenience method and use that? svn path=/branches/work/kwin_composite/; revision=652348 --- activation.cpp | 10 +- client.cpp | 601 +++++++++----------------------------------- composite.cpp | 4 +- effects.cpp | 211 +++++++++++++++- effects.h | 25 +- events.cpp | 294 +++++++++++++++++----- geometry.cpp | 111 +++++--- lib/kwineffects.cpp | 212 ---------------- lib/kwineffects.h | 26 -- scene.cpp | 2 +- tabbox.cpp | 567 +++++++++++++++++++++++------------------ toplevel.cpp | 2 +- unmanaged.cpp | 4 +- useractions.cpp | 124 ++++----- workspace.cpp | 10 +- 15 files changed, 1072 insertions(+), 1131 deletions(-) diff --git a/activation.cpp b/activation.cpp index 1d8ab18bd8..c3d8447a76 100644 --- a/activation.cpp +++ b/activation.cpp @@ -29,6 +29,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "atoms.h" #include "group.h" #include "rules.h" +#include "effects.h" #include namespace KWin @@ -221,8 +222,8 @@ void Workspace::setActiveClient( Client* c, allowed_t ) ++set_active_client_recursion; if( active_client != NULL ) { // note that this may call setActiveClient( NULL ), therefore the recursion counter - active_client->setActive( false ); - } + active_client->setActive( false ); + } active_client = c; Q_ASSERT( c == NULL || c->isActive()); if( active_client != NULL ) @@ -245,6 +246,8 @@ void Workspace::setActiveClient( Client* c, allowed_t ) rootInfo->setActiveWindow( active_client? active_client->window() : 0 ); updateColormap(); + if( effects ) + static_cast(effects)->windowActivated( active_client ? active_client->effectWindow() : NULL ); --set_active_client_recursion; } @@ -263,7 +266,6 @@ void Workspace::activateClient( Client* c, bool force ) { if( c == NULL ) { - focusToNull(); setActiveClient( NULL, Allowed ); return; } @@ -698,7 +700,7 @@ void Client::demandAttentionKNotify() } // TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it -KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*, +KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, Client, const Client*, // ignore already existing splashes, toolbars, utilities, menus and topmenus, // as the app may show those before the main window !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu() diff --git a/client.cpp b/client.cpp index 0c31579776..bf4c63e83f 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 KWin 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 ) + { + static_cast(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 ) + { + static_cast(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 ) + static_cast(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 ) + static_cast(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 ) + static_cast(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 ) + static_cast(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? + static_cast(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 ) + static_cast(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/composite.cpp b/composite.cpp index 4569d869d0..5ccf8a87e9 100644 --- a/composite.cpp +++ b/composite.cpp @@ -431,7 +431,7 @@ void Toplevel::addDamage( int x, int y, int w, int h ) r &= rect(); damage_region += r; repaints_region += r; - effects->windowDamaged( effectWindow(), r ); + static_cast(effects)->windowDamaged( effectWindow(), r ); } void Toplevel::addDamageFull() @@ -440,7 +440,7 @@ void Toplevel::addDamageFull() return; damage_region = rect(); repaints_region = rect(); - effects->windowDamaged( effectWindow(), rect()); + static_cast(effects)->windowDamaged( effectWindow(), rect()); } void Toplevel::resetDamage( const QRect& r ) diff --git a/effects.cpp b/effects.cpp index 04289e9cb8..4c4e256cba 100644 --- a/effects.cpp +++ b/effects.cpp @@ -16,7 +16,13 @@ License. See the file "COPYING" for the exact licensing terms. #include "scene_xrender.h" #include "workspace.h" +#include + #include "kdebug.h" +#include "klibloader.h" +#include "kdesktopfile.h" +#include "kconfiggroup.h" +#include "kstandarddirs.h" #include @@ -116,11 +122,112 @@ void EffectsHandlerImpl::drawWindow( EffectWindow* w, int mask, QRegion region, scene->finalDrawWindow( static_cast( w ), mask, region, data ); } +// start another painting pass +void EffectsHandlerImpl::startPaint() + { + assert( current_paint_screen == 0 ); + assert( current_paint_window == 0 ); + assert( current_draw_window == 0 ); + assert( current_transform == 0 ); + } + +void EffectsHandlerImpl::windowUserMovedResized( EffectWindow* c, bool first, bool last ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->windowUserMovedResized( c, first, last ); + } + void EffectsHandlerImpl::windowOpacityChanged( EffectWindow* c, double old_opacity ) { if( static_cast(c)->window()->opacity() == old_opacity ) return; - EffectsHandler::windowOpacityChanged( c, old_opacity ); + foreach( EffectPair ep, loaded_effects ) + ep.second->windowOpacityChanged( c, old_opacity ); + } + +void EffectsHandlerImpl::windowAdded( EffectWindow* c ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->windowAdded( c ); + } + +void EffectsHandlerImpl::windowDeleted( EffectWindow* c ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->windowDeleted( c ); + } + +void EffectsHandlerImpl::windowClosed( EffectWindow* c ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->windowClosed( c ); + } + +void EffectsHandlerImpl::windowActivated( EffectWindow* c ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->windowActivated( c ); + } + +void EffectsHandlerImpl::windowMinimized( EffectWindow* c ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->windowMinimized( c ); + } + +void EffectsHandlerImpl::windowUnminimized( EffectWindow* c ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->windowUnminimized( c ); + } + +void EffectsHandlerImpl::desktopChanged( int old ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->desktopChanged( old ); + } + +void EffectsHandlerImpl::windowDamaged( EffectWindow* w, const QRect& r ) + { + if( w == NULL ) + return; + foreach( EffectPair ep, loaded_effects ) + ep.second->windowDamaged( w, r ); + } + +void EffectsHandlerImpl::windowGeometryShapeChanged( EffectWindow* w, const QRect& old ) + { + if( w == NULL ) // during late cleanup effectWindow() may be already NULL + return; // in some functions that may still call this + foreach( EffectPair ep, loaded_effects ) + ep.second->windowGeometryShapeChanged( w, old ); + } + +void EffectsHandlerImpl::tabBoxAdded( int mode ) + { + foreach( EffectPair ep, loaded_effects ) + ep.second->tabBoxAdded( mode ); + } + +void EffectsHandlerImpl::tabBoxClosed() + { + foreach( EffectPair ep, loaded_effects ) + ep.second->tabBoxClosed(); + } + +void EffectsHandlerImpl::tabBoxUpdated() + { + foreach( EffectPair ep, loaded_effects ) + ep.second->tabBoxUpdated(); + } + +bool EffectsHandlerImpl::borderActivated( ElectricBorder border ) + { + bool ret = false; + foreach( EffectPair ep, loaded_effects ) + if( ep.second->borderActivated( border )) + ret = true; // bail out or tell all? + return ret; } void EffectsHandlerImpl::activateWindow( EffectWindow* c ) @@ -283,6 +390,108 @@ unsigned long EffectsHandlerImpl::xrenderBufferPicture() return None; } +KLibrary* EffectsHandlerImpl::findEffectLibrary( const QString& effectname ) + { + QString libname = "kwin4_effect_" + effectname.toLower(); + + QString desktopfile = KStandardDirs::locate("appdata", + "effects/" + effectname.toLower() + ".desktop"); + if( !desktopfile.isEmpty() ) + { + KDesktopFile desktopconf( desktopfile ); + KConfigGroup conf = desktopconf.desktopGroup(); + libname = conf.readEntry( "X-KDE-Library", libname ); + } + + KLibrary* library = KLibLoader::self()->library(QFile::encodeName(libname)); + if( !library ) + { + kError( 1212 ) << k_funcinfo << "couldn't open library for effect '" << + effectname << "'" << endl; + return 0; + } + + return library; + } + +void EffectsHandlerImpl::loadEffect( const QString& name ) + { + assert( current_paint_screen == 0 ); + assert( current_paint_window == 0 ); + assert( current_draw_window == 0 ); + assert( current_transform == 0 ); + + // Make sure a single effect won't be loaded multiple times + for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); it++) + { + if( (*it).first == name ) + { + kDebug( 1212 ) << "EffectsHandler::loadEffect : Effect already loaded : " << name << endl; + return; + } + } + + + kDebug( 1212 ) << k_funcinfo << "Trying to load " << name << endl; + KLibrary* library = findEffectLibrary( name ); + if( !library ) + { + return; + } + + QString supported_symbol = "effect_supported_" + name; + KLibrary::void_function_ptr supported_func = library->resolveFunction(supported_symbol.toAscii().data()); + QString create_symbol = "effect_create_" + name; + KLibrary::void_function_ptr create_func = library->resolveFunction(create_symbol.toAscii().data()); + if( supported_func ) + { + typedef bool (*t_supportedfunc)(); + t_supportedfunc supported = reinterpret_cast(supported_func); + if(!supported()) + { + kWarning( 1212 ) << "EffectsHandler::loadEffect : Effect " << name << " is not supported" << endl; + library->unload(); + return; + } + } + if(!create_func) + { + kError( 1212 ) << "EffectsHandler::loadEffect : effect_create function not found" << endl; + library->unload(); + return; + } + typedef Effect* (*t_createfunc)(); + t_createfunc create = reinterpret_cast(create_func); + + Effect* e = create(); + + loaded_effects.append( EffectPair( name, e ) ); + effect_libraries[ name ] = library; + } + +void EffectsHandlerImpl::unloadEffect( const QString& name ) + { + assert( current_paint_screen == 0 ); + assert( current_paint_window == 0 ); + assert( current_draw_window == 0 ); + assert( current_transform == 0 ); + + for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); it++) + { + if ( (*it).first == name ) + { + kDebug( 1212 ) << "EffectsHandler::unloadEffect : Unloading Effect : " << name << endl; + delete (*it).second; + loaded_effects.erase(it); + effect_libraries[ name ]->unload(); + return; + } + } + + kDebug( 1212 ) << "EffectsHandler::unloadEffect : Effect not loaded : " << name << endl; + } + + //**************************************** // EffectWindowImpl //**************************************** diff --git a/effects.h b/effects.h index 57714d4477..5912786d12 100644 --- a/effects.h +++ b/effects.h @@ -34,7 +34,6 @@ class EffectsHandlerImpl : public EffectsHandler virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); - virtual void windowOpacityChanged( EffectWindow* c, double old_opacity ); virtual void activateWindow( EffectWindow* c ); virtual int currentDesktop() const; @@ -58,6 +57,30 @@ class EffectsHandlerImpl : public EffectsHandler virtual void reserveElectricBorderSwitching( bool reserve ); virtual unsigned long xrenderBufferPicture(); + + // internal (used by kwin core or compositing code) + virtual void startPaint(); + virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last ); + virtual void windowOpacityChanged( EffectWindow* c, double old_opacity ); + virtual void windowAdded( EffectWindow* c ); + virtual void windowClosed( EffectWindow* c ); + virtual void windowDeleted( EffectWindow* c ); + virtual void windowActivated( EffectWindow* c ); + virtual void windowMinimized( EffectWindow* c ); + virtual void windowUnminimized( EffectWindow* c ); + virtual void desktopChanged( int old ); + virtual void windowDamaged( EffectWindow* w, const QRect& r ); + virtual void windowGeometryShapeChanged( EffectWindow* w, const QRect& old ); + virtual void tabBoxAdded( int mode ); + virtual void tabBoxClosed(); + virtual void tabBoxUpdated(); + virtual bool borderActivated( ElectricBorder border ); + + void loadEffect( const QString& name ); + void unloadEffect( const QString& name ); + + protected: + KLibrary* findEffectLibrary( const QString& effectname ); }; class EffectWindowImpl : public EffectWindow diff --git a/events.cpp b/events.cpp index cc58bdfaa2..b90c27d79f 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 && static_cast(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() ) @@ -388,7 +405,7 @@ bool Workspace::workspaceEvent( XEvent * e ) if ( w ) QWhatsThis::leaveWhatsThisMode(); } - if( electricBorder(e)) + if( electricBorderEvent(e)) return true; break; } @@ -453,10 +470,32 @@ bool Workspace::workspaceEvent( XEvent * e ) case FocusOut: return true; // always eat these, they would tell Qt that KWin is the active app case ClientMessage: - if( electricBorder( e )) + if( electricBorderEvent( 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 ) + static_cast(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 ) + static_cast(effects)->windowOpacityChanged( effectWindow(), old_opacity ); + } + } + switch (e->type) + { + case UnmapNotify: + unmapNotifyEvent( &e->xunmap ); + break; + case MapNotify: + mapNotifyEvent( &e->xmap ); + break; + case ConfigureNotify: + configureNotifyEvent( &e->xconfigure ); + break; + case PropertyNotify: + propertyNotifyEvent( &e->xproperty ); + default: + { + if( e->type == Extensions::shapeNotifyEvent() ) + { + detectShape( window()); + addDamageFull(); + if( scene != NULL ) + scene->windowGeometryShapeChanged( this ); + if( effects != NULL ) + static_cast(effects)->windowGeometryShapeChanged( effectWindow(), geometry()); + } +#ifdef HAVE_XDAMAGE + if( e->type == Extensions::damageNotifyEvent()) + damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e )); +#endif + break; + } + } + return false; // don't eat events, even our own unmanaged widgets are tracked + } + +void Unmanaged::mapNotifyEvent( XMapEvent* ) + { + } + +void Unmanaged::unmapNotifyEvent( XUnmapEvent* ) + { + release(); + } + +void Unmanaged::configureNotifyEvent( XConfigureEvent* e ) + { + if( effects ) + static_cast(effects)->checkInputWindowStacking(); // keep them on top + QRect newgeom( e->x, e->y, e->width, e->height ); + if( newgeom == geom ) + return; + addWorkspaceRepaint( geometry()); // damage old area + QRect old = geom; + geom = newgeom; + discardWindowPixmap(); + if( scene != NULL ) + scene->windowGeometryShapeChanged( this ); + if( effects != NULL ) + static_cast(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 dc831d7bf1..10cb131289 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,15 @@ void Workspace::desktopResized() desktop_geometry.width = geom.width(); desktop_geometry.height = geom.height(); rootInfo->setDesktopGeometry( -1, desktop_geometry ); + updateClientArea(); - checkElectricBorders( true ); + destroyElectricBorders(); + updateElectricBorders(); + if( compositing() ) + { + finishCompositing(); + QTimer::singleShot( 0, this, SLOT( setupCompositing() ) ); + } } /*! @@ -215,7 +223,7 @@ QRect Workspace::clientArea( clientAreaOption opt, const QPoint& p, int desktop if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 ) 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 +1417,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 +1450,7 @@ void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, i if( ns != size()) // don't restore if some app sets its own size again { QRect orig_geometry = geometry(); - GeometryUpdatesPostponer blocker( this ); + GeometryUpdatesBlocker blocker( this ); int save_gravity = xSizeHint.win_gravity; xSizeHint.win_gravity = gravity; resizeWithChecks( ns ); @@ -1662,31 +1670,46 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force ) { client_size = QSize( w - border_left - border_right, h - border_top - border_bottom ); } - 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 ) + static_cast(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 +1739,11 @@ void Client::plainResize( int w, int h, ForceGeometry_t force ) kDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl; kDebug() << 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 +1758,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 ) + static_cast(effects)->windowGeometryShapeChanged( effectWindow(), geom_before_block ); + addWorkspaceRepaint( geom_before_block ); + geom_before_block = geom; } /*! @@ -1747,11 +1778,11 @@ void Client::plainResize( int w, int h, ForceGeometry_t force ) */ void Client::move( int x, int y, ForceGeometry_t force ) { - 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 +1791,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 +1856,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 +2108,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 +2264,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 +2294,10 @@ bool Client::startMoveResize() // not needed anymore? kapp->installEventFilter( eater ); } Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart ); + if( effects ) + static_cast(effects)->windowUserMovedResized( effectWindow(), true, false ); + if( options->electricBorders() == Options::ElectricMoveOnly ) + workspace()->reserveElectricBorderSwitching( true ); return true; } @@ -2273,6 +2311,8 @@ void Client::finishMoveResize( bool cancel ) checkMaximizeGeometry(); // FRAME update(); Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd ); + if( effects ) + static_cast(effects)->windowUserMovedResized( effectWindow(), false, true ); } void Client::leaveMoveResize() @@ -2298,6 +2338,8 @@ void Client::leaveMoveResize() moveResizeMode = false; delete eater; eater = 0; + if( options->electricBorders() == Options::ElectricMoveOnly ) + workspace()->reserveElectricBorderSwitching( false ); } // This function checks if it actually makes sense to perform a restricted move/resize. @@ -2535,8 +2577,9 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) } // so the geometry tip will be painted above the outline } if ( isMove() ) - workspace()->clientMoved(globalPos, xTime()); + workspace()->checkElectricBorder(globalPos, xTime()); + if( effects ) + static_cast(effects)->windowUserMovedResized( effectWindow(), false, false ); } - } // namespace diff --git a/lib/kwineffects.cpp b/lib/kwineffects.cpp index a6a31fdac5..46d88142b9 100644 --- a/lib/kwineffects.cpp +++ b/lib/kwineffects.cpp @@ -11,13 +11,8 @@ License. See the file "COPYING" for the exact licensing terms. #include "kwineffects.h" #include -#include #include "kdebug.h" -#include "klibloader.h" -#include "kdesktopfile.h" -#include "kconfiggroup.h" -#include "kstandarddirs.h" #include @@ -212,113 +207,6 @@ EffectsHandler::~EffectsHandler() assert( loaded_effects.count() == 0 ); } -void EffectsHandler::windowUserMovedResized( EffectWindow* c, bool first, bool last ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->windowUserMovedResized( c, first, last ); - } - -void EffectsHandler::windowOpacityChanged( EffectWindow* c, double old_opacity ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->windowOpacityChanged( c, old_opacity ); - } - -void EffectsHandler::windowAdded( EffectWindow* c ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->windowAdded( c ); - } - -void EffectsHandler::windowDeleted( EffectWindow* c ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->windowDeleted( c ); - } - -void EffectsHandler::windowClosed( EffectWindow* c ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->windowClosed( c ); - } - -void EffectsHandler::windowActivated( EffectWindow* c ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->windowActivated( c ); - } - -void EffectsHandler::windowMinimized( EffectWindow* c ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->windowMinimized( c ); - } - -void EffectsHandler::windowUnminimized( EffectWindow* c ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->windowUnminimized( c ); - } - -void EffectsHandler::desktopChanged( int old ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->desktopChanged( old ); - } - -void EffectsHandler::windowDamaged( EffectWindow* w, const QRect& r ) - { - if( w == NULL ) - return; - foreach( EffectPair ep, loaded_effects ) - ep.second->windowDamaged( w, r ); - } - -void EffectsHandler::windowGeometryShapeChanged( EffectWindow* w, const QRect& old ) - { - if( w == NULL ) // during late cleanup effectWindow() may be already NULL - return; // in some functions that may still call this - foreach( EffectPair ep, loaded_effects ) - ep.second->windowGeometryShapeChanged( w, old ); - } - -void EffectsHandler::tabBoxAdded( int mode ) - { - foreach( EffectPair ep, loaded_effects ) - ep.second->tabBoxAdded( mode ); - } - -void EffectsHandler::tabBoxClosed() - { - foreach( EffectPair ep, loaded_effects ) - ep.second->tabBoxClosed(); - } - -void EffectsHandler::tabBoxUpdated() - { - foreach( EffectPair ep, loaded_effects ) - ep.second->tabBoxUpdated(); - } - -bool EffectsHandler::borderActivated( ElectricBorder border ) - { - bool ret = false; - foreach( EffectPair ep, loaded_effects ) - if( ep.second->borderActivated( border )) - ret = true; // bail out or tell all? - return ret; - } - - -// start another painting pass -void EffectsHandler::startPaint() - { - assert( current_paint_screen == 0 ); - assert( current_paint_window == 0 ); - assert( current_draw_window == 0 ); - assert( current_transform == 0 ); - } - QRect EffectsHandler::transformWindowDamage( EffectWindow* w, const QRect& r ) { if( current_transform < loaded_effects.size()) @@ -341,106 +229,6 @@ Window EffectsHandler::createFullScreenInputWindow( Effect* e, const QCursor& cu return createInputWindow( e, 0, 0, displayWidth(), displayHeight(), cursor ); } -KLibrary* EffectsHandler::findEffectLibrary( const QString& effectname ) -{ - QString libname = "kwin4_effect_" + effectname.toLower(); - - QString desktopfile = KStandardDirs::locate("appdata", - "effects/" + effectname.toLower() + ".desktop"); - if( !desktopfile.isEmpty() ) - { - KDesktopFile desktopconf( desktopfile ); - KConfigGroup conf = desktopconf.desktopGroup(); - libname = conf.readEntry( "X-KDE-Library", libname ); - } - - KLibrary* library = KLibLoader::self()->library(QFile::encodeName(libname)); - if( !library ) - { - kError( 1212 ) << k_funcinfo << "couldn't open library for effect '" << - effectname << "'" << endl; - return 0; - } - - return library; -} - -void EffectsHandler::loadEffect( const QString& name ) - { - assert( current_paint_screen == 0 ); - assert( current_paint_window == 0 ); - assert( current_draw_window == 0 ); - assert( current_transform == 0 ); - - // Make sure a single effect won't be loaded multiple times - for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); it++) - { - if( (*it).first == name ) - { - kDebug( 1212 ) << "EffectsHandler::loadEffect : Effect already loaded : " << name << endl; - return; - } - } - - - kDebug( 1212 ) << k_funcinfo << "Trying to load " << name << endl; - KLibrary* library = findEffectLibrary( name ); - if( !library ) - { - return; - } - - QString supported_symbol = "effect_supported_" + name; - KLibrary::void_function_ptr supported_func = library->resolveFunction(supported_symbol.toAscii().data()); - QString create_symbol = "effect_create_" + name; - KLibrary::void_function_ptr create_func = library->resolveFunction(create_symbol.toAscii().data()); - if( supported_func ) - { - typedef bool (*t_supportedfunc)(); - t_supportedfunc supported = reinterpret_cast(supported_func); - if(!supported()) - { - kWarning( 1212 ) << "EffectsHandler::loadEffect : Effect " << name << " is not supported" << endl; - library->unload(); - return; - } - } - if(!create_func) - { - kError( 1212 ) << "EffectsHandler::loadEffect : effect_create function not found" << endl; - library->unload(); - return; - } - typedef Effect* (*t_createfunc)(); - t_createfunc create = reinterpret_cast(create_func); - - Effect* e = create(); - - loaded_effects.append( EffectPair( name, e ) ); - effect_libraries[ name ] = library; - } - -void EffectsHandler::unloadEffect( const QString& name ) - { - assert( current_paint_screen == 0 ); - assert( current_paint_window == 0 ); - assert( current_draw_window == 0 ); - assert( current_transform == 0 ); - - for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); it++) - { - if ( (*it).first == name ) - { - kDebug( 1212 ) << "EffectsHandler::unloadEffect : Unloading Effect : " << name << endl; - delete (*it).second; - loaded_effects.erase(it); - effect_libraries[ name ]->unload(); - return; - } - } - - kDebug( 1212 ) << "EffectsHandler::unloadEffect : Effect not loaded : " << name << endl; - } EffectsHandler* effects = 0; diff --git a/lib/kwineffects.h b/lib/kwineffects.h index 6b2854d172..cc1d019312 100644 --- a/lib/kwineffects.h +++ b/lib/kwineffects.h @@ -188,35 +188,9 @@ class KWIN_EXPORT EffectsHandler virtual void addRepaint( const QRect& r ) = 0; virtual void addRepaint( int x, int y, int w, int h ) = 0; - // internal (used by kwin core or compositing code) - virtual void startPaint(); - virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last ); - virtual void windowOpacityChanged( EffectWindow* c, double old_opacity ); - virtual void windowAdded( EffectWindow* c ); - virtual void windowClosed( EffectWindow* c ); - virtual void windowDeleted( EffectWindow* c ); - virtual void windowActivated( EffectWindow* c ); - virtual void windowMinimized( EffectWindow* c ); - virtual void windowUnminimized( EffectWindow* c ); - virtual bool checkInputWindowEvent( XEvent* e ) = 0; - virtual void checkInputWindowStacking() = 0; - virtual void desktopChanged( int old ); - virtual void windowDamaged( EffectWindow* w, const QRect& r ); - virtual void windowGeometryShapeChanged( EffectWindow* w, const QRect& old ); - virtual void tabBoxAdded( int mode ); - virtual void tabBoxClosed(); - virtual void tabBoxUpdated(); - virtual bool borderActivated( ElectricBorder border ); - CompositingType compositingType() const { return compositing_type; } virtual unsigned long xrenderBufferPicture() = 0; - //void registerEffect( const QString& name, EffectFactory* factory ); - void loadEffect( const QString& name ); - void unloadEffect( const QString& name ); - - protected: - KLibrary* findEffectLibrary( const QString& effectname ); protected: QVector< EffectPair > loaded_effects; diff --git a/scene.cpp b/scene.cpp index 55d8fbc5c6..8435df714a 100644 --- a/scene.cpp +++ b/scene.cpp @@ -93,7 +93,7 @@ void Scene::paintScreen( int* mask, QRegion* region ) ? 0 : PAINT_SCREEN_REGION; updateTimeDiff(); // preparation step - effects->startPaint(); + static_cast(effects)->startPaint(); effects->prePaintScreen( mask, region, time_diff ); if( *mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS )) { // Region painting is not possible with transformations, diff --git a/tabbox.cpp b/tabbox.cpp index f817359d5f..e6252d7dec 100644 --- a/tabbox.cpp +++ b/tabbox.cpp @@ -12,6 +12,7 @@ License. See the file "COPYING" for the exact licensing terms. //#define QT_CLEAN_NAMESPACE #include "tabbox.h" #include "workspace.h" +#include "effects.h" #include "client.h" #include #include @@ -24,7 +25,6 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include -#include #include #include #include @@ -43,39 +43,30 @@ namespace KWin extern QPixmap* kwin_get_menu_pix_hack(); -TabBox::TabBox( Workspace *ws, const char *name ) - : Q3Frame( 0, name, Qt::WNoAutoErase ), current_client( NULL ), wspace(ws) +TabBox::TabBox( Workspace *ws ) + : QFrame( 0, Qt::X11BypassWindowManagerHint ) + , wspace(ws) + , client(0) + , display_refcount( 0 ) { - setFrameStyle(QFrame::StyledPanel | QFrame::Plain); + setFrameStyle(QFrame::StyledPanel); + setFrameShadow(QFrame::Plain); + setBackgroundRole(QPalette::Base); setLineWidth(2); - setMargin(2); + setContentsMargins( 2, 2, 2, 2 ); showMiniIcon = false; no_tasks = i18n("*** No Windows ***"); m = DesktopMode; // init variables + updateKeyMapping(); reconfigure(); reset(); connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show())); - - XSetWindowAttributes attr; - attr.override_redirect = 1; - outline_left = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0, - CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr ); - outline_right = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0, - CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr ); - outline_top = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0, - CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr ); - outline_bottom = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0, - CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr ); } TabBox::~TabBox() { - XDestroyWindow( display(), outline_left ); - XDestroyWindow( display(), outline_right ); - XDestroyWindow( display(), outline_top ); - XDestroyWindow( display(), outline_bottom ); } @@ -102,7 +93,7 @@ void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client Client* start = c; if ( chain ) - c = workspace()->nextFocusChainClient(c); + c = workspace()->nextClientFocusChain(c); else c = workspace()->stackingOrder().first(); @@ -125,15 +116,11 @@ void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client list += c; else if( !list.contains( modal )) list += modal; - else - { - // nothing - } } } if ( chain ) - c = workspace()->nextFocusChainClient( c ); + c = workspace()->nextClientFocusChain( c ); else { if ( idx >= (workspace()->stackingOrder().size()-1) ) @@ -148,15 +135,39 @@ void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client } +/*! + Create list of desktops, starting with desktop start +*/ +void TabBox::createDesktopList(QList< int > &list, int start, SortOrder order) + { + list.clear(); + + int iDesktop = start; + + for( int i = 1; i <= workspace()->numberOfDesktops(); i++ ) + { + list.append( iDesktop ); + if ( order == StaticOrder ) + { + iDesktop = workspace()->nextDesktopStatic( iDesktop ); + } + else + { // MostRecentlyUsedOrder + iDesktop = workspace()->nextDesktopFocusChain( iDesktop ); + } + } + } + + /*! Resets the tab box to display the active client in WindowsMode, or the current desktop in DesktopListMode */ -void TabBox::reset() +void TabBox::reset( bool partial_reset ) { int w, h, cw = 0, wmax = 0; - QRect r = KGlobalSettings::desktopGeometry(QCursor::pos()); + QRect r = KGlobalSettings::desktopGeometry(cursorPos()); // calculate height of 1 line // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below @@ -164,10 +175,14 @@ void TabBox::reset() if ( mode() == WindowsMode ) { - setCurrentClient( workspace()->activeClient()); + Client* starting_client = 0; + if( partial_reset && clients.count() != 0 ) + starting_client = clients.first(); + else + client = starting_client = workspace()->activeClient(); // get all clients to show - createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), current_client, true); + createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), starting_client, true); // calculate maximum caption width cw = fontMetrics().width(no_tasks)+20; @@ -212,18 +227,32 @@ void TabBox::reset() } } else - { // DesktopListMode - showMiniIcon = false; - desk = workspace()->currentDesktop(); + { + int starting_desktop; + if( mode() == DesktopListMode ) + { + starting_desktop = 1; + createDesktopList(desktops, starting_desktop, StaticOrder ); + } + else + { // DesktopMode + starting_desktop = workspace()->currentDesktop(); + createDesktopList(desktops, starting_desktop, MostRecentlyUsedOrder ); + } - for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ ) + if( !partial_reset ) + desk = workspace()->currentDesktop(); + + showMiniIcon = false; + + foreach (int it, desktops) { - cw = fontMetrics().width( workspace()->desktopName(i) ); + cw = fontMetrics().width( workspace()->desktopName(it) ); if ( cw > wmax ) wmax = cw; } // calculate height for the popup (max. 16 desktops always fit in a 800x600 screen) - h = workspace()->numberOfDesktops() * lineHeight; + h = desktops.count() * lineHeight; } // height, width for the popup @@ -234,6 +263,9 @@ void TabBox::reset() setGeometry( (r.width()-w)/2 + r.x(), (r.height()-h)/2+ r.y(), w, h ); + + if( effects ) + static_cast(effects)->tabBoxUpdated(); } @@ -244,52 +276,42 @@ void TabBox::nextPrev( bool next) { if ( mode() == WindowsMode ) { - Client* firstClient = NULL; - Client* client = current_client; + Client* firstClient = 0; + Client* newClient = client; do { if ( next ) - client = workspace()->nextFocusChainClient(client); + newClient = workspace()->nextClientFocusChain(newClient); else - client = workspace()->previousFocusChainClient(client); + newClient = workspace()->previousClientFocusChain(newClient); if (!firstClient) { - // When we see our first client for the second time, - // it's time to stop. - firstClient = client; + // When we see our first client for the second time, + // it's time to stop. + firstClient = newClient; } - else if (client == firstClient) + else if (newClient == firstClient) { - // No candidates found. - client = 0; + // No candidates found. + newClient = 0; break; } - } while ( client && !clients.contains( client )); - setCurrentClient( client ); + } while ( newClient && !clients.contains( newClient )); + setCurrentClient( newClient ); } else if( mode() == DesktopMode ) { - if ( next ) - desk = workspace()->nextDesktopFocusChain( desk ); - else - desk = workspace()->previousDesktopFocusChain( desk ); + setCurrentDesktop ( next ? workspace()->nextDesktopFocusChain( desk ) + : workspace()->previousDesktopFocusChain( desk ) ); } else { // DesktopListMode - if ( next ) - { - desk++; - if ( desk > workspace()->numberOfDesktops() ) - desk = 1; - } - else - { - desk--; - if ( desk < 1 ) - desk = workspace()->numberOfDesktops(); - } + setCurrentDesktop ( next ? workspace()->nextDesktopStatic( desk ) + : workspace()->previousDesktopStatic( desk )) ; } + if( effects ) + static_cast(effects)->tabBoxUpdated(); update(); } @@ -303,20 +325,24 @@ Client* TabBox::currentClient() { if ( mode() != WindowsMode ) return 0; - if (!workspace()->hasClient( current_client )) + if (!workspace()->hasClient( client )) return 0; - return current_client; + return client; } -void TabBox::setCurrentClient( Client* c ) +/*! + Returns the list of clients potentially displayed ( only works in + WindowsMode ). + Returns an empty list if no clients are available. + */ +ClientList TabBox::currentClientList() { - if( current_client != c ) - { - current_client = c; - updateOutline(); - } + if( mode() != WindowsMode ) + return ClientList(); + return clients; } + /*! Returns the currently displayed virtual desktop ( only works in DesktopListMode ) @@ -326,21 +352,52 @@ int TabBox::currentDesktop() { if ( mode() == DesktopListMode || mode() == DesktopMode ) return desk; - else - return -1; + return -1; } +/*! + Returns the list of desktops potentially displayed ( only works in + DesktopListMode ) + Returns an empty list if no desktops are available. + */ +QList< int > TabBox::currentDesktopList() + { + if ( mode() == DesktopListMode || mode() == DesktopMode ) + return desktops; + return QList< int >(); + } + + +/*! + Change the currently selected client, and notify the effects. + + \sa setCurrentDesktop() + */ +void TabBox::setCurrentClient( Client* newClient ) + { + client = newClient; + if( effects ) + static_cast(effects)->tabBoxUpdated(); + } + +/*! + Change the currently selected desktop, and notify the effects. + + \sa setCurrentClient() + */ +void TabBox::setCurrentDesktop( int newDesktop ) + { + desk = newDesktop; + if( effects ) + static_cast(effects)->tabBoxUpdated(); + } + /*! Reimplemented to raise the tab box as well */ void TabBox::showEvent( QShowEvent* ) { - updateOutline(); - XRaiseWindow( display(), outline_left ); - XRaiseWindow( display(), outline_right ); - XRaiseWindow( display(), outline_top ); - XRaiseWindow( display(), outline_bottom ); raise(); } @@ -350,29 +407,23 @@ void TabBox::showEvent( QShowEvent* ) */ void TabBox::hideEvent( QHideEvent* ) { - XUnmapWindow( display(), outline_left ); - XUnmapWindow( display(), outline_right ); - XUnmapWindow( display(), outline_top ); - XUnmapWindow( display(), outline_bottom ); } /*! Paints the tab box */ -void TabBox::drawContents( QPainter * ) +void TabBox::paintEvent( QPaintEvent* e ) { - QRect r(contentsRect()); - QPixmap pix(r.size()); // do double buffering to avoid flickers - pix.fill(this, 0, 0); + QFrame::paintEvent( e ); - QPainter p; - p.begin(&pix); + QPainter p( this ); + QRect r( contentsRect()); QPixmap* menu_pix = kwin_get_menu_pix_hack(); int iconWidth = showMiniIcon ? 16 : 32; - int x = 0; - int y = 0; + int x = r.x(); + int y = r.y(); if ( mode () == WindowsMode ) { @@ -392,7 +443,7 @@ void TabBox::drawContents( QPainter * ) if ( workspace()->hasClient( *it ) ) // safety { // draw highlight background - if ( (*it) == current_client ) + if ( (*it) == currentClient() ) p.fillRect(x, y, r.width(), lineHeight, palette().brush( QPalette::Highlight )); // draw icon @@ -426,10 +477,10 @@ void TabBox::drawContents( QPainter * ) else s += (*it)->caption(); - s = fontMetrics().elidedText(s, Qt::ElideMiddle, r.width() - 5 - iconWidth - 8); + s = fontMetrics().elidedText( s, Qt::ElideMiddle, r.width() - 5 - iconWidth - 8 ); // draw text - if ( (*it) == current_client ) + if ( (*it) == currentClient() ) p.setPen(palette().color( QPalette::HighlightedText )); else if( (*it)->isMinimized()) { @@ -471,22 +522,19 @@ void TabBox::drawContents( QPainter * ) QFontMetrics fm(f); int wmax = 0; - for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ ) + foreach (int it, desktops) { - wmax = qMax(wmax, fontMetrics().width(workspace()->desktopName(i))); + wmax = qMax(wmax, fontMetrics().width(workspace()->desktopName(it))); // calculate max width of desktop-number text - QString num = QString::number(i); + QString num = QString::number(it); iconWidth = qMax(iconWidth - 4, fm.boundingRect(num).width()) + 4; } - // In DesktopMode, start at the current desktop - // In DesktopListMode, start at desktop #1 - int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1; - for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ ) + foreach (int it, desktops) { // draw highlight background - if ( iDesktop == desk ) // current desktop + if ( it == desk ) // current desktop p.fillRect(x, y, r.width(), lineHeight, palette().brush( QPalette::Highlight )); p.save(); @@ -498,28 +546,28 @@ void TabBox::drawContents( QPainter * ) // draw desktop-number p.setFont(f); - QString num = QString::number(iDesktop); + QString num = QString::number(it); p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num); p.restore(); // draw desktop name text - if ( iDesktop == desk ) + if ( it == desk ) p.setPen(palette().color( QPalette::HighlightedText )); else p.setPen(palette().color( QPalette::Text )); p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, - workspace()->desktopName(iDesktop)); + workspace()->desktopName(it)); // show mini icons from that desktop aligned to each other int x1 = x + 5 + iconWidth + 8 + wmax + 5; ClientList list; - createClientList(list, iDesktop, 0, false); + createClientList(list, it, 0, false); // clients are in reversed stacking order - for ( int i = list.size() - 1; i>=0; i-- ) + for ( int i = list.size() - 1; i>=0; i-- ) { if ( !list.at( i )->miniIcon().isNull() ) { @@ -534,107 +582,38 @@ void TabBox::drawContents( QPainter * ) // next desktop y += lineHeight; if ( y >= r.height() ) break; - - if( mode() == DesktopMode ) - iDesktop = workspace()->nextDesktopFocusChain( iDesktop ); - else - iDesktop++; } } - p.end(); - - QPainter localPainter( this ); - localPainter.drawImage( QPoint( r.x(), r.y() ), pix.toImage() ); } -void TabBox::updateOutline() + +/*! + Notify effects that the tab box is being shown, and only display the + default tab box QFrame if no effect has referenced the tab box. +*/ +void TabBox::show() { - Client* c = currentClient(); - if( c == NULL || this->isHidden() || !c->isShown( true ) || !c->isOnCurrentDesktop()) - { - XUnmapWindow( display(), outline_left ); - XUnmapWindow( display(), outline_right ); - XUnmapWindow( display(), outline_top ); - XUnmapWindow( display(), outline_bottom ); + if( effects ) + static_cast(effects)->tabBoxAdded( mode()); + if( isDisplayed()) return; - } - // left/right parts are between top/bottom, they don't reach as far as the corners - XMoveResizeWindow( display(), outline_left, c->x(), c->y() + 5, 5, c->height() - 10 ); - XMoveResizeWindow( display(), outline_right, c->x() + c->width() - 5, c->y() + 5, 5, c->height() - 10 ); - XMoveResizeWindow( display(), outline_top, c->x(), c->y(), c->width(), 5 ); - XMoveResizeWindow( display(), outline_bottom, c->x(), c->y() + c->height() - 5, c->width(), 5 ); - { - QPixmap pix( 5, c->height() - 10 ); - QPainter p( &pix ); - p.setPen( Qt::white ); - p.drawLine( 0, 0, 0, pix.height() - 1 ); - p.drawLine( 4, 0, 4, pix.height() - 1 ); - p.setPen( Qt::gray ); - p.drawLine( 1, 0, 1, pix.height() - 1 ); - p.drawLine( 3, 0, 3, pix.height() - 1 ); - p.setPen( Qt::black ); - p.drawLine( 2, 0, 2, pix.height() - 1 ); - p.end(); - XSetWindowBackgroundPixmap( display(), outline_left, pix.handle()); - XSetWindowBackgroundPixmap( display(), outline_right, pix.handle()); - } - { - QPixmap pix( c->width(), 5 ); - QPainter p( &pix ); - p.setPen( Qt::white ); - p.drawLine( 0, 0, pix.width() - 1 - 0, 0 ); - p.drawLine( 4, 4, pix.width() - 1 - 4, 4 ); - p.drawLine( 0, 0, 0, 4 ); - p.drawLine( pix.width() - 1 - 0, 0, pix.width() - 1 - 0, 4 ); - p.setPen( Qt::gray ); - p.drawLine( 1, 1, pix.width() - 1 - 1, 1 ); - p.drawLine( 3, 3, pix.width() - 1 - 3, 3 ); - p.drawLine( 1, 1, 1, 4 ); - p.drawLine( 3, 3, 3, 4 ); - p.drawLine( pix.width() - 1 - 1, 1, pix.width() - 1 - 1, 4 ); - p.drawLine( pix.width() - 1 - 3, 3, pix.width() - 1 - 3, 4 ); - p.setPen( Qt::black ); - p.drawLine( 2, 2, pix.width() - 1 - 2, 2 ); - p.drawLine( 2, 2, 2, 4 ); - p.drawLine( pix.width() - 1 - 2, 2, pix.width() - 1 - 2, 4 ); - p.end(); - XSetWindowBackgroundPixmap( display(), outline_top, pix.handle()); - } - { - QPixmap pix( c->width(), 5 ); - QPainter p( &pix ); - p.setPen( Qt::white ); - p.drawLine( 4, 0, pix.width() - 1 - 4, 0 ); - p.drawLine( 0, 4, pix.width() - 1 - 0, 4 ); - p.drawLine( 0, 4, 0, 0 ); - p.drawLine( pix.width() - 1 - 0, 4, pix.width() - 1 - 0, 0 ); - p.setPen( Qt::gray ); - p.drawLine( 3, 1, pix.width() - 1 - 3, 1 ); - p.drawLine( 1, 3, pix.width() - 1 - 1, 3 ); - p.drawLine( 3, 1, 3, 0 ); - p.drawLine( 1, 3, 1, 0 ); - p.drawLine( pix.width() - 1 - 3, 1, pix.width() - 1 - 3, 0 ); - p.drawLine( pix.width() - 1 - 1, 3, pix.width() - 1 - 1, 0 ); - p.setPen( Qt::black ); - p.drawLine( 2, 2, pix.width() - 1 - 2, 2 ); - p.drawLine( 2, 0, 2, 2 ); - p.drawLine( pix.width() - 1 - 2, 0, pix.width() - 1 - 2 , 2 ); - p.end(); - XSetWindowBackgroundPixmap( display(), outline_bottom, pix.handle()); - } - XClearWindow( display(), outline_left ); - XClearWindow( display(), outline_right ); - XClearWindow( display(), outline_top ); - XClearWindow( display(), outline_bottom ); - XMapWindow( display(), outline_left ); - XMapWindow( display(), outline_right ); - XMapWindow( display(), outline_top ); - XMapWindow( display(), outline_bottom ); + refDisplay(); + QWidget::show(); } + +/*! + Notify effects that the tab box is being hidden. +*/ void TabBox::hide() { delayedShowTimer.stop(); + if( isVisible()) + unrefDisplay(); + if( effects ) + static_cast(effects)->tabBoxClosed(); + if( isDisplayed()) + kDebug( 1212 ) << "Tab box was not properly closed by an effect" << endl; QWidget::hide(); QApplication::syncX(); XEvent otherEvent; @@ -643,6 +622,15 @@ void TabBox::hide() } +/*! + Decrease the reference count. Only when the reference count is 0 will + the default tab box be shown. + */ +void TabBox::unrefDisplay() + { + --display_refcount; + } + void TabBox::reconfigure() { KSharedConfigPtr c(KGlobal::config()); @@ -688,17 +676,24 @@ void TabBox::delayedShow() void TabBox::handleMouseEvent( XEvent* e ) { XAllowEvents( display(), AsyncPointer, xTime() ); + if( !isVisible() && isDisplayed()) + { // tabbox has been replaced, check effects + if( effects && static_cast(effects)->checkInputWindowEvent( e )) + return; + } if( e->type != ButtonPress ) return; QPoint pos( e->xbutton.x_root, e->xbutton.y_root ); - if( !geometry().contains( pos )) + QPoint widgetPos = mapFromGlobal( pos ); // inside tabbox + + if(( !isVisible() && isDisplayed()) + || !geometry().contains( pos )) { workspace()->closeTabBox(); // click outside closes tab return; } - pos.rx() -= x(); // pos is now inside tabbox - pos.ry() -= y(); - int num = (pos.y()-frameWidth()) / lineHeight; + + int num = (widgetPos.y()-frameWidth()) / lineHeight; if( mode() == WindowsMode ) { @@ -716,21 +711,14 @@ void TabBox::handleMouseEvent( XEvent* e ) } else { - int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1; - for( int i = 1; - i <= workspace()->numberOfDesktops(); - ++i ) + foreach( int it, desktops ) { if( num == 0 ) { - desk = iDesktop; + setCurrentDesktop( it ); break; } num--; - if( mode() == DesktopMode ) - iDesktop = workspace()->nextDesktopFocusChain( iDesktop ); - else - iDesktop++; } } update(); @@ -788,12 +776,16 @@ bool areKeySymXsDepressed( bool bAll, const uint keySyms[], int nKeySyms ) return bAll; } +static const int MAX_KEYSYMS = 4; +static uint alt_keysyms[ MAX_KEYSYMS ]; +static uint win_keysyms[ MAX_KEYSYMS ]; + static bool areModKeysDepressed( const QKeySequence& seq ) { uint rgKeySyms[10]; int nKeySyms = 0; if( seq.isEmpty()) - return false; + return false; int mod = seq[seq.count()-1] & Qt::KeyboardModifierMask; if ( mod & Qt::SHIFT ) @@ -808,18 +800,17 @@ static bool areModKeysDepressed( const QKeySequence& seq ) } if( mod & Qt::ALT ) { - rgKeySyms[nKeySyms++] = XK_Alt_L; - rgKeySyms[nKeySyms++] = XK_Alt_R; + for( int i = 0; + i < MAX_KEYSYMS && alt_keysyms[ i ] != NoSymbol; + ++i ) + rgKeySyms[nKeySyms++] = alt_keysyms[ i ]; } if( mod & Qt::META ) { - // It would take some code to determine whether the Win key - // is associated with Super or Meta, so check for both. - // See bug #140023 for details. - rgKeySyms[nKeySyms++] = XK_Super_L; - rgKeySyms[nKeySyms++] = XK_Super_R; - rgKeySyms[nKeySyms++] = XK_Meta_L; - rgKeySyms[nKeySyms++] = XK_Meta_R; + for( int i = 0; + i < MAX_KEYSYMS && win_keysyms[ i ] != NoSymbol; + ++i ) + rgKeySyms[nKeySyms++] = win_keysyms[ i ]; } return areKeySymXsDepressed( false, rgKeySyms, nKeySyms ); @@ -833,6 +824,44 @@ static bool areModKeysDepressed( const KShortcut& cut ) return false; } +void TabBox::updateKeyMapping() + { + const int size = 6; + uint keysyms[ size ] = { XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R, XK_Meta_L, XK_Meta_R }; + XModifierKeymap* map = XGetModifierMapping( display() ); + int altpos = 0; + int winpos = 0; + int winmodpos = -1; + int winmod = KKeyServer::modXMeta(); + while( winmod > 0 ) // get position of the set bit in winmod + { + winmod >>= 1; + ++winmodpos; + } + for( int i = 0; + i < MAX_KEYSYMS; + ++i ) + alt_keysyms[ i ] = win_keysyms[ i ] = NoSymbol; + for( int i = 0; + i < size; + ++i ) + { + KeyCode keycode = XKeysymToKeycode( display(), keysyms[ i ] ); + for( int j = 0; + j < map->max_keypermod; + ++j ) + { + if( map->modifiermap[ 3 * map->max_keypermod + j ] == keycode ) // Alt + if( altpos < MAX_KEYSYMS ) + alt_keysyms[ altpos++ ] = keysyms[ i ]; + if( winmodpos >= 0 && map->modifiermap[ winmodpos * map->max_keypermod + j ] == keycode ) + if( winpos < MAX_KEYSYMS ) + win_keysyms[ winpos++ ] = keysyms[ i ]; + } + } + XFreeModifiermap( map ); + } + void Workspace::slotWalkThroughWindows() { if ( root != rootWindow() ) @@ -956,7 +985,7 @@ bool Workspace::startKDEWalkThroughWindows() { if( !establishTabBoxGrab()) return false; - tab_grab = true; + tab_grab = true; keys->setEnabled( false ); disable_shortcuts_keys->setEnabled( false ); client_keys->setEnabled( false ); @@ -1030,7 +1059,7 @@ void Workspace::CDEWalkThroughWindows( bool forward ) Client* firstClient = 0; do { - nc = forward ? nextStaticClient(nc) : previousStaticClient(nc); + nc = forward ? nextClientStatic(nc) : previousClientStatic(nc); if (!firstClient) { // When we see our first client for the second time, @@ -1136,6 +1165,18 @@ void Workspace::tabBoxKeyPress( int keyQt ) } } +void Workspace::refTabBox() + { + if( tab_box ) + tab_box->refDisplay(); + } + +void Workspace::unrefTabBox() + { + if( tab_box ) + tab_box->unrefDisplay(); + } + void Workspace::closeTabBox() { removeTabBoxGrab(); @@ -1187,12 +1228,9 @@ void Workspace::tabBoxKeyRelease( const XKeyEvent& ev ) return; if (tab_grab) { - removeTabBoxGrab(); - tab_box->hide(); - keys->setEnabled( true ); - disable_shortcuts_keys->setEnabled( true ); - client_keys->setEnabled( true ); - tab_grab = false; + bool old_control_grab = control_grab; + closeTabBox(); + control_grab = old_control_grab; if( Client* c = tab_box->currentClient()) { activateClient( c ); @@ -1202,12 +1240,9 @@ void Workspace::tabBoxKeyRelease( const XKeyEvent& ev ) } if (control_grab) { - removeTabBoxGrab(); - tab_box->hide(); - keys->setEnabled( true ); - disable_shortcuts_keys->setEnabled( true ); - client_keys->setEnabled( true ); - control_grab = False; + bool old_tab_grab = tab_grab; + closeTabBox(); + tab_grab = old_tab_grab; if ( tab_box->currentDesktop() != -1 ) { setCurrentDesktop( tab_box->currentDesktop() ); @@ -1238,11 +1273,27 @@ int Workspace::previousDesktopFocusChain( int iDesktop ) const return numberOfDesktops(); } +int Workspace::nextDesktopStatic( int iDesktop ) const + { + int i = ++iDesktop; + if( i > numberOfDesktops()) + i = 1; + return i; + } + +int Workspace::previousDesktopStatic( int iDesktop ) const + { + int i = --iDesktop; + if( i < 1 ) + i = numberOfDesktops(); + return i; + } + /*! auxiliary functions to travers all clients according the focus order. Useful for kwms Alt-tab feature. */ -Client* Workspace::nextFocusChainClient( Client* c ) const +Client* Workspace::nextClientFocusChain( Client* c ) const { if ( global_focus_chain.isEmpty() ) return 0; @@ -1259,7 +1310,7 @@ Client* Workspace::nextFocusChainClient( Client* c ) const auxiliary functions to travers all clients according the focus order. Useful for kwms Alt-tab feature. */ -Client* Workspace::previousFocusChainClient( Client* c ) const +Client* Workspace::previousClientFocusChain( Client* c ) const { if ( global_focus_chain.isEmpty() ) return 0; @@ -1276,7 +1327,7 @@ Client* Workspace::previousFocusChainClient( Client* c ) const auxiliary functions to travers all clients according the static order. Useful for the CDE-style Alt-tab feature. */ -Client* Workspace::nextStaticClient( Client* c ) const +Client* Workspace::nextClientStatic( Client* c ) const { if ( !c || clients.isEmpty() ) return 0; @@ -1292,7 +1343,7 @@ Client* Workspace::nextStaticClient( Client* c ) const auxiliary functions to travers all clients according the static order. Useful for the CDE-style Alt-tab feature. */ -Client* Workspace::previousStaticClient( Client* c ) const +Client* Workspace::previousClientStatic( Client* c ) const { if ( !c || clients.isEmpty() ) return 0; @@ -1305,6 +1356,46 @@ Client* Workspace::previousStaticClient( Client* c ) const return clients[ pos ]; } +Client* Workspace::currentTabBoxClient() const + { + if( !tab_box ) + return 0; + return tab_box->currentClient(); + } + +ClientList Workspace::currentTabBoxClientList() const + { + if( !tab_box ) + return ClientList(); + return tab_box->currentClientList(); + } + +int Workspace::currentTabBoxDesktop() const + { + if( !tab_box ) + return -1; + return tab_box->currentDesktop(); + } + +QList< int > Workspace::currentTabBoxDesktopList() const + { + if( !tab_box ) + return QList< int >(); + return tab_box->currentDesktopList(); + } + +void Workspace::setTabBoxClient( Client* c ) + { + if( tab_box ) + tab_box->setCurrentClient( c ); + } + +void Workspace::setTabBoxDesktop( int iDesktop ) + { + if( tab_box ) + tab_box->setCurrentDesktop( iDesktop ); + } + bool Workspace::establishTabBoxGrab() { if( XGrabKeyboard( display(), root, false, diff --git a/toplevel.cpp b/toplevel.cpp index 894d782784..8dbc429511 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -304,7 +304,7 @@ void Toplevel::setOpacity( double new_opacity ) addRepaintFull(); scene->windowOpacityChanged( this ); if( effects ) - effects->windowOpacityChanged( effectWindow(), old_opacity ); + static_cast(effects)->windowOpacityChanged( effectWindow(), old_opacity ); } } diff --git a/unmanaged.cpp b/unmanaged.cpp index 8771bb5e80..e9d555d45a 100644 --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -63,7 +63,7 @@ bool Unmanaged::track( Window w ) setupCompositing(); ungrabXServer(); if( effects ) - effects->checkInputWindowStacking(); + static_cast(effects)->checkInputWindowStacking(); return true; } @@ -72,7 +72,7 @@ void Unmanaged::release() Deleted* del = Deleted::create( this ); if( effects ) { - effects->windowClosed( effectWindow()); + static_cast(effects)->windowClosed( effectWindow()); scene->windowClosed( this, del ); } finishCompositing(); diff --git a/useractions.cpp b/useractions.cpp index 06249705bb..4b98b4c4fb 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 ) + static_cast(effects)->loadEffect( name ); + } + +void Workspace::unloadEffect( const QString& name ) + { + if( effects ) + static_cast(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/workspace.cpp b/workspace.cpp index af9d6f87b2..cf55faf588 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -498,7 +498,7 @@ Client* Workspace::createClient( Window w, bool is_mapped ) if( scene ) scene->windowAdded( c ); if( effects ) - effects->windowAdded( c->effectWindow()); + static_cast(effects)->windowAdded( c->effectWindow()); return c; } @@ -516,7 +516,7 @@ Unmanaged* Workspace::createUnmanaged( Window w ) if( scene ) scene->windowAdded( c ); if( effects ) - effects->windowAdded( c->effectWindow()); + static_cast(effects)->windowAdded( c->effectWindow()); return c; } @@ -644,7 +644,7 @@ void Workspace::removeDeleted( Deleted* c, allowed_t ) if( scene ) scene->windowDeleted( c ); if( effects ) - effects->windowDeleted( c->effectWindow()); + static_cast(effects)->windowDeleted( c->effectWindow()); deleted.removeAll( c ); } @@ -1327,7 +1327,7 @@ bool Workspace::setCurrentDesktop( int new_desktop ) popupinfo->showInfo( desktopName(currentDesktop()) ); if( effects != NULL && old_desktop != 0 && old_desktop != new_desktop ) - effects->desktopChanged( old_desktop ); + static_cast(effects)->desktopChanged( old_desktop ); return true; } @@ -2187,7 +2187,7 @@ void Workspace::checkElectricBorder(const QPoint &pos, Time now) if (timestampDiff(electric_time_first, now) > treshold_set) { electric_current_border = ElectricNone; - if( effects && effects->borderActivated( border )) + if( effects && static_cast(effects)->borderActivated( border )) {} // handled by effects else electricBorderSwitchDesktop( border, pos );