client.cpp

00001 /*****************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
00007 
00008 You can Freely distribute this program under the GNU General Public
00009 License. See the file "COPYING" for the exact licensing terms.
00010 ******************************************************************/
00011 
00012 #include "client.h"
00013 
00014 #include <qapplication.h>
00015 #include <qpainter.h>
00016 #include <qdatetime.h>
00017 #include <kprocess.h>
00018 #include <unistd.h>
00019 #include <kstandarddirs.h>
00020 #include <qwhatsthis.h>
00021 #include <kwin.h>
00022 #include <kiconloader.h>
00023 #include <stdlib.h>
00024 
00025 #include "bridge.h"
00026 #include "group.h"
00027 #include "workspace.h"
00028 #include "atoms.h"
00029 #include "notifications.h"
00030 #include "rules.h"
00031 
00032 #include <X11/extensions/shape.h>
00033 
00034 // put all externs before the namespace statement to allow the linker
00035 // to resolve them properly
00036 
00037 extern Atom qt_wm_state;
00038 extern Time qt_x_time;
00039 extern Atom qt_window_role;
00040 extern Atom qt_sm_client_id;
00041 
00042 namespace KWinInternal
00043 {
00044 
00045 /*
00046 
00047  Creating a client:
00048      - only by calling Workspace::createClient()
00049          - it creates a new client and calls manage() for it
00050 
00051  Destroying a client:
00052      - destroyClient() - only when the window itself has been destroyed
00053      - releaseWindow() - the window is kept, only the client itself is destroyed
00054 
00055 */
00056 
00057 
00069 Client::Client( Workspace *ws )
00070     :   QObject( NULL ),
00071         client( None ),
00072         wrapper( None ),
00073         frame( None ),
00074         decoration( NULL ),
00075         wspace( ws ),
00076         bridge( new Bridge( this )),
00077         move_faked_activity( false ),
00078         move_resize_grab_window( None ),
00079         transient_for( NULL ),
00080         transient_for_id( None ),
00081         original_transient_for_id( None ),
00082         in_group( NULL ),
00083         window_group( None ),
00084         in_layer( UnknownLayer ),
00085         ping_timer( NULL ),
00086         process_killer( NULL ),
00087         user_time( CurrentTime ), // not known yet
00088         allowed_actions( 0 ),
00089         postpone_geometry_updates( 0 ),
00090         pending_geometry_update( false ),
00091         shade_geometry_change( false ),
00092         border_left( 0 ),
00093         border_right( 0 ),
00094         border_top( 0 ),
00095         border_bottom( 0 ),
00096         demandAttentionKNotifyTimer( NULL )
00097 // SELI do all as initialization
00098     {
00099     autoRaiseTimer = 0;
00100     shadeHoverTimer = 0;
00101 
00102     // set the initial mapping state
00103     mapping_state = WithdrawnState;
00104     desk = 0; // no desktop yet
00105 
00106     mode = PositionCenter;
00107     buttonDown = FALSE;
00108     moveResizeMode = FALSE;
00109 
00110     info = NULL;
00111 
00112     shade_mode = ShadeNone;
00113     active = FALSE;
00114     deleting = false;
00115     keep_above = FALSE;
00116     keep_below = FALSE;
00117     is_shape = FALSE;
00118     motif_noborder = false;
00119     motif_may_move = TRUE;
00120     motif_may_resize = TRUE;
00121     motif_may_close = TRUE;
00122     fullscreen_mode = FullScreenNone;
00123     skip_taskbar = FALSE;
00124     original_skip_taskbar = false;
00125     minimized = false;
00126     hidden = false;
00127     modal = false;
00128     noborder = false;
00129     user_noborder = false;
00130     not_obscured = false;
00131     urgency = false;
00132     ignore_focus_stealing = false;
00133     demands_attention = false;
00134     check_active_modal = false;
00135 
00136     Pdeletewindow = 0;
00137     Ptakefocus = 0;
00138     Ptakeactivity = 0;
00139     Pcontexthelp = 0;
00140     Pping = 0;
00141     input = FALSE;
00142     skip_pager = FALSE;
00143 
00144     max_mode = MaximizeRestore;
00145     maxmode_restore = MaximizeRestore;
00146     
00147     cmap = None;
00148     
00149     frame_geometry = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
00150     client_size = QSize( 100, 100 );
00151     custom_opacity = false;
00152     rule_opacity_active = 0;; //translucency rules
00153     rule_opacity_inactive = 0; //dito.
00154 
00155     // SELI initialize xsizehints??
00156     }
00157 
00161 Client::~Client()
00162     {
00163     assert(!moveResizeMode);
00164     assert( client == None );
00165     assert( frame == None && wrapper == None );
00166     assert( decoration == NULL );
00167     assert( postpone_geometry_updates == 0 );
00168     assert( !check_active_modal );
00169     delete info;
00170     delete bridge;
00171     }
00172 
00173 // use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
00174 void Client::deleteClient( Client* c, allowed_t )
00175     {
00176     delete c;
00177     }
00178 
00182 void Client::releaseWindow( bool on_shutdown )
00183     {
00184     assert( !deleting );
00185     deleting = true;
00186     workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
00187     StackingUpdatesBlocker blocker( workspace());
00188     if (!custom_opacity) setOpacity(FALSE);
00189     if (moveResizeMode)
00190        leaveMoveResize();
00191     finishWindowRules();
00192     ++postpone_geometry_updates;
00193     setMappingState( WithdrawnState );
00194     setModal( false ); // otherwise its mainwindow wouldn't get focus
00195     hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
00196     if( !on_shutdown )
00197         workspace()->clientHidden( this );
00198     XUnmapWindow( qt_xdisplay(), frameId()); // destroying decoration would cause ugly visual effect
00199     destroyDecoration();
00200     cleanGrouping();
00201     if( !on_shutdown )
00202         {
00203         workspace()->removeClient( this, Allowed );
00204         // only when the window is being unmapped, not when closing down KWin
00205         // (NETWM sections 5.5,5.7)
00206         info->setDesktop( 0 );
00207         desk = 0;
00208         info->setState( 0, info->state()); // reset all state flags
00209         }
00210     XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
00211     XDeleteProperty( qt_xdisplay(), client, atoms->net_frame_extents );
00212     XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_frame_strut );
00213     XReparentWindow( qt_xdisplay(), client, workspace()->rootWin(), x(), y());
00214     XRemoveFromSaveSet( qt_xdisplay(), client );
00215     XSelectInput( qt_xdisplay(), client, NoEventMask );
00216     if( on_shutdown )
00217         { // map the window, so it can be found after another WM is started
00218         XMapWindow( qt_xdisplay(), client );
00219     // TODO preserve minimized, shaded etc. state?
00220         }
00221     else
00222         {
00223         // Make sure it's not mapped if the app unmapped it (#65279). The app
00224         // may do map+unmap before we initially map the window by calling rawShow() from manage().
00225         XUnmapWindow( qt_xdisplay(), client ); 
00226         }
00227     client = None;
00228     XDestroyWindow( qt_xdisplay(), wrapper );
00229     wrapper = None;
00230     XDestroyWindow( qt_xdisplay(), frame );
00231     frame = None;
00232     --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
00233     deleteClient( this, Allowed );
00234     }
00235 
00236 // like releaseWindow(), but this one is called when the window has been already destroyed
00237 // (e.g. the application closed it)
00238 void Client::destroyClient()
00239     {
00240     assert( !deleting );
00241     deleting = true;
00242     workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
00243     StackingUpdatesBlocker blocker( workspace());
00244     if (moveResizeMode)
00245        leaveMoveResize();
00246     finishWindowRules();
00247     ++postpone_geometry_updates;
00248     setModal( false );
00249     hidden = true; // so that it's not considered visible anymore
00250     workspace()->clientHidden( this );
00251     destroyDecoration();
00252     cleanGrouping();
00253     workspace()->removeClient( this, Allowed );
00254     client = None; // invalidate
00255     XDestroyWindow( qt_xdisplay(), wrapper );
00256     wrapper = None;
00257     XDestroyWindow( qt_xdisplay(), frame );
00258     frame = None;
00259     --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
00260     deleteClient( this, Allowed );
00261     }
00262 
00263 void Client::updateDecoration( bool check_workspace_pos, bool force )
00264     {
00265     if( !force && (( decoration == NULL && noBorder())
00266                     || ( decoration != NULL && !noBorder())))
00267         return;
00268     bool do_show = false;
00269     postponeGeometryUpdates( true );
00270     if( force )
00271         destroyDecoration();
00272     if( !noBorder())
00273         {
00274         decoration = workspace()->createDecoration( bridge );
00275         // TODO check decoration's minimum size?
00276         decoration->init();
00277         decoration->widget()->installEventFilter( this );
00278         XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
00279         decoration->widget()->lower();
00280         decoration->borders( border_left, border_right, border_top, border_bottom );
00281         options->onlyDecoTranslucent ?
00282             setDecoHashProperty(border_top, border_right, border_bottom, border_left):
00283             unsetDecoHashProperty();
00284         int save_workarea_diff_x = workarea_diff_x;
00285         int save_workarea_diff_y = workarea_diff_y;
00286         move( calculateGravitation( false ));
00287         plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00288         workarea_diff_x = save_workarea_diff_x;
00289         workarea_diff_y = save_workarea_diff_y;
00290         do_show = true;
00291         }
00292     else
00293         destroyDecoration();
00294     if( check_workspace_pos )
00295         checkWorkspacePosition();
00296     postponeGeometryUpdates( false );
00297     if( do_show )
00298         decoration->widget()->show();
00299     updateFrameExtents();
00300     }
00301 
00302 void Client::destroyDecoration()
00303     {
00304     if( decoration != NULL )
00305         {
00306         delete decoration;
00307         decoration = NULL;
00308         QPoint grav = calculateGravitation( true );
00309         border_left = border_right = border_top = border_bottom = 0;
00310         setMask( QRegion()); // reset shape mask
00311         int save_workarea_diff_x = workarea_diff_x;
00312         int save_workarea_diff_y = workarea_diff_y;
00313         plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00314         move( grav );
00315         workarea_diff_x = save_workarea_diff_x;
00316         workarea_diff_y = save_workarea_diff_y;
00317         }
00318     }
00319 
00320 void Client::checkBorderSizes()
00321     {
00322     if( decoration == NULL )
00323         return;
00324     int new_left, new_right, new_top, new_bottom;
00325     decoration->borders( new_left, new_right, new_top, new_bottom );
00326     if( new_left == border_left && new_right == border_right
00327         && new_top == border_top && new_bottom == border_bottom )
00328         return;
00329     GeometryUpdatesPostponer blocker( this );
00330     move( calculateGravitation( true ));
00331     border_left = new_left;
00332     border_right = new_right;
00333     border_top = new_top;
00334     border_bottom = new_bottom;
00335     if (border_left != new_left ||
00336         border_right != new_right ||
00337         border_top != new_top ||
00338         border_bottom != new_bottom)
00339     options->onlyDecoTranslucent ?
00340        setDecoHashProperty(new_top, new_right, new_bottom, new_left):
00341        unsetDecoHashProperty();
00342     move( calculateGravitation( false ));
00343     plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00344     checkWorkspacePosition();
00345     }
00346 
00347 void Client::detectNoBorder()
00348     {
00349     if( Shape::hasShape( window()))
00350         {
00351         noborder = true;
00352         return;
00353         }
00354     switch( windowType())
00355         {
00356         case NET::Desktop :
00357         case NET::Dock :
00358         case NET::TopMenu :
00359         case NET::Splash :
00360             noborder = true;
00361           break;
00362         case NET::Unknown :
00363         case NET::Normal :
00364         case NET::Toolbar :
00365         case NET::Menu :
00366         case NET::Dialog :
00367         case NET::Utility :
00368             noborder = false;
00369           break;
00370         default:
00371             assert( false );
00372         }
00373     // NET::Override is some strange beast without clear definition, usually
00374     // just meaning "noborder", so let's treat it only as such flag, and ignore it as
00375     // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
00376     if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
00377         noborder = true;
00378     }
00379 
00380 void Client::detectShapable()
00381     {
00382     if( Shape::hasShape( window()))
00383         return;
00384     switch( windowType())
00385         {
00386         case NET::Desktop :
00387         case NET::Dock :
00388         case NET::TopMenu :
00389         case NET::Splash :
00390           break;
00391         case NET::Unknown :
00392         case NET::Normal :
00393         case NET::Toolbar :
00394         case NET::Menu :
00395         case NET::Dialog :
00396         case NET::Utility :
00397             setShapable(FALSE);
00398           break;
00399         default:
00400             assert( false );
00401         }
00402     }
00403 
00404 void Client::updateFrameExtents()
00405     {
00406     NETStrut strut;
00407     strut.left = border_left;
00408     strut.right = border_right;
00409     strut.top = border_top;
00410     strut.bottom = border_bottom;
00411     info->setFrameExtents( strut );
00412     }
00413 
00414 // Resizes the decoration, and makes sure the decoration widget gets resize event
00415 // even if the size hasn't changed. This is needed to make sure the decoration
00416 // re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes,
00417 // the decoration may turn on/off some borders, but the actual size
00418 // of the decoration stays the same).
00419 void Client::resizeDecoration( const QSize& s )
00420     {
00421     if( decoration == NULL )
00422         return;
00423     QSize oldsize = decoration->widget()->size();
00424     decoration->resize( s );
00425     if( oldsize == s )
00426         {
00427         QResizeEvent e( s, oldsize );
00428         QApplication::sendEvent( decoration->widget(), &e );
00429         }
00430     }
00431 
00432 bool Client::noBorder() const
00433     {
00434     return noborder || isFullScreen() || user_noborder || motif_noborder;
00435     }
00436 
00437 bool Client::userCanSetNoBorder() const
00438     {
00439     return !noborder && !isFullScreen() && !isShade();
00440     }
00441 
00442 bool Client::isUserNoBorder() const
00443     {
00444     return user_noborder;
00445     }
00446 
00447 void Client::setUserNoBorder( bool set )
00448     {
00449     if( !userCanSetNoBorder())
00450         return;
00451     set = rules()->checkNoBorder( set );
00452     if( user_noborder == set )
00453         return;
00454     user_noborder = set;
00455     updateDecoration( true, false );
00456     updateWindowRules();
00457     }
00458 
00459 void Client::updateShape()
00460     {
00461     // workaround for #19644 - shaped windows shouldn't have decoration
00462     if( shape() && !noBorder()) 
00463         {
00464         noborder = true;
00465         updateDecoration( true );
00466         }
00467     if ( shape() )
00468         {
00469         XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
00470                            clientPos().x(), clientPos().y(),
00471                            window(), ShapeBounding, ShapeSet);
00472         setShapable(TRUE);
00473         }
00474     else
00475         {
00476         XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00477                            None, ShapeSet);
00478         }
00479     if( Shape::version() >= 0x11 ) // 1.1, has input shape support
00480         { // there appears to be no way to find out if a window has input
00481           // shape set or not, so always set propagate the input shape
00482           // (it's the same like the bounding shape by default)
00483         XShapeCombineMask( qt_xdisplay(), frameId(), ShapeInput, 0, 0,
00484                            None, ShapeSet );
00485         XShapeCombineShape( qt_xdisplay(), frameId(), ShapeInput,
00486                            clientPos().x(), clientPos().y(),
00487                            window(), ShapeBounding, ShapeSubtract );
00488         XShapeCombineShape( qt_xdisplay(), frameId(), ShapeInput,
00489                            clientPos().x(), clientPos().y(),
00490                            window(), ShapeInput, ShapeUnion );
00491         }
00492     }
00493 
00494 void Client::setMask( const QRegion& reg, int mode )
00495     {
00496     _mask = reg;
00497     if( reg.isNull())
00498         XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00499             None, ShapeSet );
00500     else if( mode == X::Unsorted )
00501         XShapeCombineRegion( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00502             reg.handle(), ShapeSet );
00503     else
00504         {
00505         QMemArray< QRect > rects = reg.rects();
00506         XRectangle* xrects = new XRectangle[ rects.count() ];
00507         for( unsigned int i = 0;
00508              i < rects.count();
00509              ++i )
00510             {
00511             xrects[ i ].x = rects[ i ].x();
00512             xrects[ i ].y = rects[ i ].y();
00513             xrects[ i ].width = rects[ i ].width();
00514             xrects[ i ].height = rects[ i ].height();
00515             }
00516         XShapeCombineRectangles( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00517             xrects, rects.count(), ShapeSet, mode );
00518         delete[] xrects;
00519         }
00520     }
00521 
00522 QRegion Client::mask() const
00523     {
00524     if( _mask.isEmpty())
00525         return QRegion( 0, 0, width(), height());
00526     return _mask;
00527     }
00528     
00529 void Client::setShapable(bool b)
00530     {
00531     long tmp = b?1:0;
00532     XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
00533     }
00534 
00535 void Client::hideClient( bool hide )
00536     {
00537     if( hidden == hide )
00538         return;
00539     hidden = hide;
00540     updateVisibility();
00541     }
00542     
00543 /*
00544   Returns whether the window is minimizable or not
00545  */
00546 bool Client::isMinimizable() const
00547     {
00548     if( isSpecialWindow())
00549         return false;
00550     if( isTransient())
00551         { // #66868 - let other xmms windows be minimized when the mainwindow is minimized
00552         bool shown_mainwindow = false;
00553         ClientList mainclients = mainClients();
00554         for( ClientList::ConstIterator it = mainclients.begin();
00555              it != mainclients.end();
00556              ++it )
00557             {
00558             if( (*it)->isShown( true ))
00559                 shown_mainwindow = true;
00560             }
00561         if( !shown_mainwindow )
00562             return true;
00563         }
00564     // this is here because kicker's taskbar doesn't provide separate entries
00565     // for windows with an explicitly given parent
00566     // TODO perhaps this should be redone
00567     if( transientFor() != NULL )
00568         return false;
00569     if( !wantsTabFocus()) // SELI - NET::Utility? why wantsTabFocus() - skiptaskbar? ?
00570         return false;
00571     return true;
00572     }
00573 
00577 void Client::minimize( bool avoid_animation )
00578     {
00579     if ( !isMinimizable() || isMinimized())
00580         return;
00581 
00582     Notify::raise( Notify::Minimize );
00583 
00584     // SELI mainClients().isEmpty() ??? - and in unminimize() too
00585     if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
00586         animateMinimizeOrUnminimize( true ); // was visible or shaded
00587 
00588     minimized = true;
00589 
00590     updateVisibility();
00591     updateAllowedActions();
00592     workspace()->updateMinimizedOfTransients( this );
00593     updateWindowRules();
00594     workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
00595     }
00596 
00597 void Client::unminimize( bool avoid_animation )
00598     {
00599     if( !isMinimized())
00600         return;
00601 
00602     Notify::raise( Notify::UnMinimize );
00603     minimized = false;
00604     if( isOnCurrentDesktop() && isShown( true ))
00605         {
00606         if( mainClients().isEmpty() && !avoid_animation )
00607             animateMinimizeOrUnminimize( FALSE );
00608         }
00609     updateVisibility();
00610     updateAllowedActions();
00611     workspace()->updateMinimizedOfTransients( this );
00612     updateWindowRules();
00613     }
00614 
00615 extern bool         blockAnimation;
00616 
00617 void Client::animateMinimizeOrUnminimize( bool minimize )
00618     {
00619     if ( blockAnimation )
00620         return;
00621     if ( !options->animateMinimize )
00622         return;
00623 
00624     if( decoration != NULL && decoration->animateMinimize( minimize ))
00625         return; // decoration did it
00626 
00627     // the function is a bit tricky since it will ensure that an
00628     // animation action needs always the same time regardless of the
00629     // performance of the machine or the X-Server.
00630 
00631     float lf,rf,tf,bf,step;
00632 
00633     int speed = options->animateMinimizeSpeed;
00634     if ( speed > 10 )
00635         speed = 10;
00636     if ( speed < 0 )
00637         speed = 0;
00638 
00639     step = 40. * (11 - speed );
00640 
00641     NETRect r = info->iconGeometry();
00642     QRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
00643     if ( !icongeom.isValid() )
00644         return;
00645 
00646     QPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
00647 
00648     QRect before, after;
00649     if ( minimize ) 
00650         {
00651         before = QRect( x(), y(), width(), pm.height() );
00652         after = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00653         }
00654     else 
00655         {
00656         before = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00657         after = QRect( x(), y(), width(), pm.height() );
00658         }
00659 
00660     lf = (after.left() - before.left())/step;
00661     rf = (after.right() - before.right())/step;
00662     tf = (after.top() - before.top())/step;
00663     bf = (after.bottom() - before.bottom())/step;
00664 
00665     grabXServer();
00666 
00667     QRect area = before;
00668     QRect area2;
00669     QPixmap pm2;
00670 
00671     QTime t;
00672     t.start();
00673     float diff;
00674 
00675     QPainter p ( workspace()->desktopWidget() );
00676     bool need_to_clear = FALSE;
00677     QPixmap pm3;
00678     do 
00679         {
00680         if (area2 != area)
00681             {
00682             pm = animationPixmap( area.width() );
00683             pm2 = QPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
00684             p.drawPixmap( area.x(), area.y(), pm );
00685             if ( need_to_clear ) 
00686                 {
00687                 p.drawPixmap( area2.x(), area2.y(), pm3 );
00688                 need_to_clear = FALSE;
00689                 }
00690             area2 = area;
00691             }
00692         XFlush(qt_xdisplay());
00693         XSync( qt_xdisplay(), FALSE );
00694         diff = t.elapsed();
00695         if (diff > step)
00696             diff = step;
00697         area.setLeft(before.left() + int(diff*lf));
00698         area.setRight(before.right() + int(diff*rf));
00699         area.setTop(before.top() + int(diff*tf));
00700         area.setBottom(before.bottom() + int(diff*bf));
00701         if (area2 != area ) 
00702             {
00703             if ( area2.intersects( area ) )
00704                 p.drawPixmap( area2.x(), area2.y(), pm2 );
00705             else 
00706                 { // no overlap, we can clear later to avoid flicker
00707                 pm3 = pm2;
00708                 need_to_clear = TRUE;
00709                 }
00710             }
00711         } while ( t.elapsed() < step);
00712     if (area2 == area || need_to_clear )
00713         p.drawPixmap( area2.x(), area2.y(), pm2 );
00714 
00715     p.end();
00716     ungrabXServer();
00717     }
00718 
00719 
00723 QPixmap Client::animationPixmap( int w )
00724     {
00725     QFont font = options->font(isActive());
00726     QFontMetrics fm( font );
00727     QPixmap pm( w, fm.lineSpacing() );
00728     pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
00729     QPainter p( &pm );
00730     p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
00731     p.setFont(options->font(isActive()));
00732     p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
00733     return pm;
00734     }
00735 
00736 
00737 bool Client::isShadeable() const
00738     {
00739     return !isSpecialWindow() && !noBorder();
00740     }
00741 
00742 void Client::setShade( ShadeMode mode )
00743     {
00744     if( !isShadeable())
00745         return;
00746     mode = rules()->checkShade( mode );
00747     if( shade_mode == mode )
00748         return;
00749     bool was_shade = isShade();
00750     ShadeMode was_shade_mode = shade_mode;
00751     shade_mode = mode;
00752     if( was_shade == isShade())
00753         {
00754         if( decoration != NULL ) // decoration may want to update after e.g. hover-shade changes
00755             decoration->shadeChange();
00756         return; // no real change in shaded state
00757         }
00758 
00759     if( shade_mode == ShadeNormal )
00760         {
00761         if ( isShown( true ) && isOnCurrentDesktop())
00762                 Notify::raise( Notify::ShadeUp );
00763         }
00764     else if( shade_mode == ShadeNone )
00765         {
00766         if( isShown( true ) && isOnCurrentDesktop())
00767                 Notify::raise( Notify::ShadeDown );
00768         }
00769 
00770     assert( decoration != NULL ); // noborder windows can't be shaded
00771     GeometryUpdatesPostponer blocker( this );
00772     // decorations may turn off some borders when shaded
00773     decoration->borders( border_left, border_right, border_top, border_bottom );
00774 
00775     int as = options->animateShade? 10 : 1;
00776 // TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
00777     if ( isShade()) 
00778         { // shade_mode == ShadeNormal
00779         // we're about to shade, texx xcompmgr to prepare
00780         long _shade = 1;
00781         XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
00782         // shade
00783         int h = height();
00784         shade_geometry_change = true;
00785         QSize s( sizeForClientSize( QSize( clientSize())));
00786         s.setHeight( border_top + border_bottom );
00787         XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
00788         XUnmapWindow( qt_xdisplay(), wrapper );
00789         XUnmapWindow( qt_xdisplay(), client );
00790         XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00791         //as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it        
00792         //done xcompmgr workaround
00793 // FRAME       repaint( FALSE );
00794 //        bool wasStaticContents = testWFlags( WStaticContents );
00795 //        setWFlags( WStaticContents );
00796         int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00797         do 
00798             {
00799             h -= step;
00800             XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00801             resizeDecoration( QSize( s.width(), h ));
00802             QApplication::syncX();
00803             } while ( h > s.height() + step );
00804 //        if ( !wasStaticContents )
00805 //            clearWFlags( WStaticContents );
00806         plainResize( s );
00807         shade_geometry_change = false;
00808         if( isActive())
00809             {
00810             if( was_shade_mode == ShadeHover )
00811                 workspace()->activateNextClient( this );
00812             else
00813                 workspace()->focusToNull();
00814             }
00815         // tell xcompmgr shade's done
00816         _shade = 2;
00817         XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);    
00818         }
00819     else 
00820         {
00821         int h = height();
00822         shade_geometry_change = true;
00823         QSize s( sizeForClientSize( clientSize()));
00824 // FRAME       bool wasStaticContents = testWFlags( WStaticContents );
00825 //        setWFlags( WStaticContents );
00826         int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00827         do 
00828             {
00829             h += step;
00830             XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00831             resizeDecoration( QSize( s.width(), h ));
00832             // assume a border
00833             // we do not have time to wait for X to send us paint events
00834 // FRAME           repaint( 0, h - step-5, width(), step+5, TRUE);
00835             QApplication::syncX();
00836             } while ( h < s.height() - step );
00837 //        if ( !wasStaticContents )
00838 //            clearWFlags( WStaticContents );
00839         shade_geometry_change = false;
00840         plainResize( s );
00841         if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
00842             setActive( TRUE );
00843         XMapWindow( qt_xdisplay(), wrapperId());
00844         XMapWindow( qt_xdisplay(), window());
00845         XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade);
00846         if ( isActive() )
00847             workspace()->requestFocus( this );
00848         }
00849     checkMaximizeGeometry();
00850     info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
00851     info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
00852     updateVisibility();
00853     updateAllowedActions();
00854     workspace()->updateMinimizedOfTransients( this );
00855     decoration->shadeChange();
00856     updateWindowRules();
00857     }
00858 
00859 void Client::shadeHover()
00860     {
00861     setShade( ShadeHover );
00862     cancelShadeHover();
00863     }
00864 
00865 void Client::cancelShadeHover()
00866     {
00867     delete shadeHoverTimer;
00868     shadeHoverTimer = 0;
00869     }
00870 
00871 void Client::toggleShade()
00872     {
00873     // if the mode is ShadeHover or ShadeActive, cancel shade too
00874     setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
00875     }
00876 
00877 void Client::updateVisibility()
00878     {
00879     if( deleting )
00880         return;
00881     bool show = true;
00882     if( hidden )
00883         {
00884         setMappingState( IconicState );
00885         info->setState( NET::Hidden, NET::Hidden );
00886         setSkipTaskbar( true, false ); // also hide from taskbar
00887         rawHide();
00888         show = false;
00889         }
00890     else
00891         {
00892         setSkipTaskbar( original_skip_taskbar, false );
00893         }
00894     if( minimized )
00895         {
00896         setMappingState( IconicState );
00897         info->setState( NET::Hidden, NET::Hidden );
00898         rawHide();
00899         show = false;
00900         }
00901     if( show )
00902         info->setState( 0, NET::Hidden );
00903     if( !isOnCurrentDesktop())
00904         {
00905         setMappingState( IconicState );
00906         rawHide();
00907         show = false;
00908         }
00909     if( show )
00910         {
00911         bool belongs_to_desktop = false;
00912         for( ClientList::ConstIterator it = group()->members().begin();
00913              it != group()->members().end();
00914              ++it )
00915             if( (*it)->isDesktop())
00916                 {
00917                 belongs_to_desktop = true;
00918                 break;
00919                 }
00920         if( !belongs_to_desktop && workspace()->showingDesktop())
00921             workspace()->resetShowingDesktop( true );
00922         if( isShade())
00923             setMappingState( IconicState );
00924         else
00925             setMappingState( NormalState );
00926         rawShow();
00927         }
00928     }
00929 
00934 void Client::setMappingState(int s)
00935     {
00936     assert( client != None );
00937     assert( !deleting || s == WithdrawnState );
00938     if( mapping_state == s )
00939         return;
00940     bool was_unmanaged = ( mapping_state == WithdrawnState );
00941     mapping_state = s;
00942     if( mapping_state == WithdrawnState )
00943         {
00944         XDeleteProperty( qt_xdisplay(), window(), qt_wm_state );
00945         return;
00946         }
00947     assert( s == NormalState || s == IconicState );
00948 
00949     unsigned long data[2];
00950     data[0] = (unsigned long) s;
00951     data[1] = (unsigned long) None;
00952     XChangeProperty(qt_xdisplay(), window(), qt_wm_state, qt_wm_state, 32,
00953         PropModeReplace, (unsigned char *)data, 2);
00954 
00955     if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
00956         postponeGeometryUpdates( false );
00957     }
00958 
00963 void Client::rawShow()
00964     {
00965     if( decoration != NULL )
00966         decoration->widget()->show(); // not really necessary, but let it know the state
00967     XMapWindow( qt_xdisplay(), frame );
00968     if( !isShade())
00969         {
00970         XMapWindow( qt_xdisplay(), wrapper );
00971         XMapWindow( qt_xdisplay(), client );
00972         }
00973     }
00974 
00980 void Client::rawHide()
00981     {
00982 // Here it may look like a race condition, as some other client might try to unmap
00983 // the window between these two XSelectInput() calls. However, they're supposed to
00984 // use XWithdrawWindow(), which also sends a synthetic event to the root window,
00985 // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
00986 // will be missed is also very minimal, so I don't think it's needed to grab the server
00987 // here.
00988     XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
00989     XUnmapWindow( qt_xdisplay(), frame );
00990     XUnmapWindow( qt_xdisplay(), wrapper );
00991     XUnmapWindow( qt_xdisplay(), client );
00992     XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00993     if( decoration != NULL )
00994         decoration->widget()->hide(); // not really necessary, but let it know the state
00995     workspace()->clientHidden( this );
00996     }
00997 
00998 void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
00999     {
01000     XEvent ev;
01001     long mask;
01002 
01003     memset(&ev, 0, sizeof(ev));
01004     ev.xclient.type = ClientMessage;
01005     ev.xclient.window = w;
01006     ev.xclient.message_type = a;
01007     ev.xclient.format = 32;
01008     ev.xclient.data.l[0] = protocol;
01009     ev.xclient.data.l[1] = qt_x_time;
01010     ev.xclient.data.l[2] = data1;
01011     ev.xclient.data.l[3] = data2;
01012     ev.xclient.data.l[4] = data3;
01013     mask = 0L;
01014     if (w == qt_xrootwin())
01015       mask = SubstructureRedirectMask;        /* magic! */
01016     XSendEvent(qt_xdisplay(), w, False, mask, &ev);
01017     }
01018 
01019 /*
01020   Returns whether the window may be closed (have a close button)
01021  */
01022 bool Client::isCloseable() const
01023     {
01024     return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
01025     }
01026 
01031 void Client::closeWindow()
01032     {
01033     if( !isCloseable())
01034         return;
01035     // Update user time, because the window may create a confirming dialog.
01036     updateUserTime(); 
01037     if ( Pdeletewindow )
01038         {
01039         Notify::raise( Notify::Close );
01040         sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
01041         pingWindow();
01042         }
01043     else 
01044         {
01045         // client will not react on wm_delete_window. We have not choice
01046         // but destroy his connection to the XServer.
01047         killWindow();
01048         }
01049     }
01050 
01051 
01055 void Client::killWindow()
01056     {
01057     kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
01058     // not sure if we need an Notify::Kill or not.. until then, use
01059     // Notify::Close
01060     Notify::raise( Notify::Close );
01061 
01062     if( isDialog())
01063         Notify::raise( Notify::TransDelete );
01064     if( isNormalWindow())
01065         Notify::raise( Notify::Delete );
01066     killProcess( false );
01067     // always kill this client at the server
01068     XKillClient(qt_xdisplay(), window() );
01069     destroyClient();
01070     }
01071 
01072 // send a ping to the window using _NET_WM_PING if possible
01073 // if it doesn't respond within a reasonable time, it will be
01074 // killed
01075 void Client::pingWindow()
01076     {
01077     if( !Pping )
01078         return; // can't ping :(
01079     if( options->killPingTimeout == 0 )
01080         return; // turned off
01081     if( ping_timer != NULL )
01082         return; // pinging already
01083     ping_timer = new QTimer( this );
01084     connect( ping_timer, SIGNAL( timeout()), SLOT( pingTimeout()));
01085     ping_timer->start( options->killPingTimeout, true );
01086     ping_timestamp = qt_x_time;
01087     workspace()->sendPingToWindow( window(), ping_timestamp );
01088     }
01089 
01090 void Client::gotPing( Time timestamp )
01091     {
01092     if( timestamp != ping_timestamp )
01093         return;
01094     delete ping_timer;
01095     ping_timer = NULL;
01096     if( process_killer != NULL )
01097         {
01098         process_killer->kill();
01099         delete process_killer;
01100         process_killer = NULL;
01101         }
01102     }
01103 
01104 void Client::pingTimeout()
01105     {
01106     kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
01107     delete ping_timer;
01108     ping_timer = NULL;
01109     killProcess( true, ping_timestamp );
01110     }
01111 
01112 void Client::killProcess( bool ask, Time timestamp )
01113     {
01114     if( process_killer != NULL )
01115         return;
01116     Q_ASSERT( !ask || timestamp != CurrentTime );
01117     QCString machine = wmClientMachine( true );
01118     pid_t pid = info->pid();
01119     if( pid <= 0 || machine.isEmpty()) // needed properties missing
01120         return;
01121     kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
01122     if( !ask )
01123         {
01124         if( machine != "localhost" )
01125             {
01126             KProcess proc;
01127             proc << "xon" << machine << "kill" << pid;
01128             proc.start( KProcess::DontCare );
01129             }
01130         else
01131             ::kill( pid, SIGTERM );
01132         }
01133     else
01134         { // SELI TODO handle the window created by handler specially (on top,urgent?)
01135         process_killer = new KProcess( this );
01136         *process_killer << KStandardDirs::findExe( "kwin_killer_helper" )
01137             << "--pid" << QCString().setNum( pid ) << "--hostname" << machine
01138             << "--windowname" << caption().utf8()
01139             << "--applicationname" << resourceClass()
01140             << "--wid" << QCString().setNum( window())
01141             << "--timestamp" << QCString().setNum( timestamp );
01142         connect( process_killer, SIGNAL( processExited( KProcess* )),
01143             SLOT( processKillerExited()));
01144         if( !process_killer->start( KProcess::NotifyOnExit ))
01145             {
01146             delete process_killer;
01147             process_killer = NULL;
01148             return;
01149             }
01150         }
01151     }
01152 
01153 void Client::processKillerExited()
01154     {
01155     kdDebug( 1212 ) << "Killer exited" << endl;
01156     delete process_killer;
01157     process_killer = NULL;
01158     }
01159 
01160 void Client::setSkipTaskbar( bool b, bool from_outside )
01161     {
01162     int was_wants_tab_focus = wantsTabFocus();
01163     if( from_outside )
01164         {
01165         b = rules()->checkSkipTaskbar( b );
01166         original_skip_taskbar = b;
01167         }
01168     if ( b == skipTaskbar() )
01169         return;
01170     skip_taskbar = b;
01171     info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
01172     updateWindowRules();
01173     if( was_wants_tab_focus != wantsTabFocus())
01174         workspace()->updateFocusChains( this,
01175             isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
01176     }
01177 
01178 void Client::setSkipPager( bool b )
01179     {
01180     b = rules()->checkSkipPager( b );
01181     if ( b == skipPager() )
01182         return;
01183     skip_pager = b;
01184     info->setState( b?NET::SkipPager:0, NET::SkipPager );
01185     updateWindowRules();
01186     }
01187 
01188 void Client::setModal( bool m )
01189     { // Qt-3.2 can have even modal normal windows :(
01190     if( modal == m )
01191         return;
01192     modal = m;
01193     if( !modal )
01194         return;
01195     // changing modality for a mapped window is weird (?)
01196     // _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
01197     }
01198 
01199 void Client::setDesktop( int desktop )
01200     {
01201     if( desktop != NET::OnAllDesktops ) // do range check
01202         desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
01203     desktop = rules()->checkDesktop( desktop );
01204     if( desk == desktop )
01205         return;
01206     int was_desk = desk;
01207     desk = desktop;
01208     info->setDesktop( desktop );
01209     if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
01210         { // onAllDesktops changed
01211         if ( isShown( true ))
01212             Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
01213         workspace()->updateOnAllDesktopsOfTransients( this );
01214         }
01215     if( decoration != NULL )
01216         decoration->desktopChange();
01217     workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
01218     updateVisibility();
01219     updateWindowRules();
01220     }
01221 
01222 void Client::setOnAllDesktops( bool b )
01223     {
01224     if(( b && isOnAllDesktops())
01225         || ( !b && !isOnAllDesktops()))
01226         return;
01227     if( b )
01228         setDesktop( NET::OnAllDesktops );
01229     else
01230         setDesktop( workspace()->currentDesktop());
01231     }
01232 
01233 bool Client::isOnCurrentDesktop() const
01234     {
01235     return isOnDesktop( workspace()->currentDesktop());
01236     }
01237 
01238 // performs activation and/or raising of the window
01239 void Client::takeActivity( int flags, bool handled, allowed_t )
01240     {
01241     if( !handled || !Ptakeactivity )
01242         {
01243         if( flags & ActivityFocus )
01244             takeFocus( Allowed );
01245         if( flags & ActivityRaise )
01246             workspace()->raiseClient( this );
01247         return;
01248         }
01249 
01250 #ifndef NDEBUG
01251     static Time previous_activity_timestamp;
01252     static Client* previous_client;
01253     if( previous_activity_timestamp == qt_x_time && previous_client != this )
01254         {
01255         kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
01256         kdDebug( 1212 ) << kdBacktrace() << endl;
01257         }
01258     previous_activity_timestamp = qt_x_time;
01259     previous_client = this;
01260 #endif
01261     workspace()->sendTakeActivity( this, qt_x_time, flags );
01262     }
01263 
01264 // performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
01265 void Client::takeFocus( allowed_t )
01266     {
01267 #ifndef NDEBUG
01268     static Time previous_focus_timestamp;
01269     static Client* previous_client;
01270     if( previous_focus_timestamp == qt_x_time && previous_client != this )
01271         {
01272         kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
01273         kdDebug( 1212 ) << kdBacktrace() << endl;
01274         }
01275     previous_focus_timestamp = qt_x_time;
01276     previous_client = this;
01277 #endif
01278     if ( rules()->checkAcceptFocus( input ))
01279         {
01280         XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, qt_x_time );
01281         }
01282     if ( Ptakefocus )
01283         sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
01284     workspace()->setShouldGetFocus( this );
01285     }
01286 
01294 bool Client::providesContextHelp() const
01295     {
01296     return Pcontexthelp;
01297     }
01298 
01299 
01306 void Client::showContextHelp()
01307     {
01308     if ( Pcontexthelp ) 
01309         {
01310         sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
01311         QWhatsThis::enterWhatsThisMode(); // SELI?
01312         }
01313     }
01314 
01315 
01320 void Client::fetchName()
01321     {
01322     setCaption( readName());
01323     }
01324 
01325 QString Client::readName() const
01326     {
01327     if ( info->name() && info->name()[ 0 ] != '\0' ) 
01328         return QString::fromUtf8( info->name() );
01329     else 
01330         return KWin::readNameProperty( window(), XA_WM_NAME );
01331     }
01332     
01333 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
01334 
01335 void Client::setCaption( const QString& s, bool force )
01336     {
01337     if ( s != cap_normal || force ) 
01338         {
01339         bool reset_name = force;
01340         for( unsigned int i = 0;
01341              i < s.length();
01342              ++i )
01343             if( !s[ i ].isPrint())
01344                 s[ i ] = ' ';
01345         cap_normal = s;
01346         bool was_suffix = ( !cap_suffix.isEmpty());
01347         QString machine_suffix;
01348         if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
01349             machine_suffix = " <@" + wmClientMachine( true ) + ">";
01350         QString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
01351         cap_suffix = machine_suffix + shortcut_suffix;
01352         if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this ))) 
01353             {
01354             int i = 2;
01355             do 
01356                 {
01357                 cap_suffix = machine_suffix + " <" + QString::number(i) + ">" + shortcut_suffix;
01358                 i++;
01359                 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
01360             info->setVisibleName( caption().utf8() );
01361             reset_name = false;
01362             }
01363         if(( was_suffix && cap_suffix.isEmpty()
01364             || reset_name )) // if it was new window, it may have old value still set, if the window is reused
01365             {
01366             info->setVisibleName( "" ); // remove
01367             info->setVisibleIconName( "" ); // remove
01368             }
01369         else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
01370             info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
01371 
01372         if( isManaged() && decoration != NULL )
01373                 decoration->captionChange();
01374         }
01375     }
01376 
01377 void Client::updateCaption()
01378     {
01379     setCaption( cap_normal, true );
01380     }
01381 
01382 void Client::fetchIconicName()
01383     {
01384     QString s;
01385     if ( info->iconName() && info->iconName()[ 0 ] != '\0' ) 
01386         s = QString::fromUtf8( info->iconName() );
01387     else 
01388         s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
01389     if ( s != cap_iconic ) 
01390         {
01391     bool was_set = !cap_iconic.isEmpty();
01392         cap_iconic = s;
01393         if( !cap_suffix.isEmpty())
01394         {
01395         if( !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
01396             info->setVisibleIconName( ( s + cap_suffix ).utf8() );
01397         else if( was_set )
01398         info->setVisibleIconName( "" ); //remove
01399         }
01400         }
01401     }
01402 
01405 QString Client::caption( bool full ) const
01406     {
01407     return full ? cap_normal + cap_suffix : cap_normal;
01408     }
01409 
01410 void Client::getWMHints()
01411     {
01412     XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
01413     input = true;
01414     window_group = None;
01415     urgency = false;
01416     if ( hints )
01417         {
01418         if( hints->flags & InputHint )
01419             input = hints->input;
01420         if( hints->flags & WindowGroupHint )
01421             window_group = hints->window_group;
01422         urgency = ( hints->flags & UrgencyHint ) ? true : false; // true/false needed, it's uint bitfield
01423         XFree( (char*)hints );
01424         }
01425     checkGroup();
01426     updateUrgency();
01427     updateAllowedActions(); // group affects isMinimizable()
01428     }
01429 
01430 void Client::getMotifHints()
01431     {
01432     bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
01433     Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
01434     motif_noborder = mnoborder;
01435     if( !hasNETSupport()) // NETWM apps should set type and size constraints
01436         {
01437         motif_may_resize = mresize; // this should be set using minsize==maxsize, but oh well
01438         motif_may_move = mmove;
01439         }
01440     else
01441         motif_may_resize = motif_may_move = true;
01442     // mminimize; - ignore, bogus - e.g. shading or sending to another desktop is "minimizing" too
01443     // mmaximize; - ignore, bogus - maximizing is basically just resizing
01444     motif_may_close = mclose; // motif apps like to crash when they set this hint and WM closes them anyway
01445     if( isManaged())
01446         updateDecoration( true ); // check if noborder state has changed
01447     }
01448 
01449 void Client::readIcons( Window win, QPixmap* icon, QPixmap* miniicon )
01450     {    
01451     // get the icons, allow scaling
01452     if( icon != NULL )
01453         *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
01454     if( miniicon != NULL )
01455         if( icon == NULL || !icon->isNull())
01456             *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
01457         else
01458             *miniicon = QPixmap();
01459     }
01460 
01461 void Client::getIcons()
01462     {
01463     // first read icons from the window itself
01464     readIcons( window(), &icon_pix, &miniicon_pix );
01465     if( icon_pix.isNull())
01466         { // then try window group
01467         icon_pix = group()->icon();
01468         miniicon_pix = group()->miniIcon();
01469         }
01470     if( icon_pix.isNull() && isTransient())
01471         { // then mainclients
01472         ClientList mainclients = mainClients();
01473         for( ClientList::ConstIterator it = mainclients.begin();
01474              it != mainclients.end() && icon_pix.isNull();
01475              ++it )
01476             {
01477             icon_pix = (*it)->icon();
01478             miniicon_pix = (*it)->miniIcon();
01479             }
01480         }
01481     if( icon_pix.isNull())
01482         { // and if nothing else, load icon from classhint or xapp icon
01483         icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
01484         miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
01485         }
01486     if( isManaged() && decoration != NULL )
01487         decoration->iconChange();
01488     }
01489 
01490 void Client::getWindowProtocols()
01491     {
01492     Atom *p;
01493     int i,n;
01494 
01495     Pdeletewindow = 0;
01496     Ptakefocus = 0;
01497     Ptakeactivity = 0;
01498     Pcontexthelp = 0;
01499     Pping = 0;
01500 
01501     if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
01502         {
01503         for (i = 0; i < n; i++)
01504             if (p[i] == atoms->wm_delete_window)
01505                 Pdeletewindow = 1;
01506             else if (p[i] == atoms->wm_take_focus)
01507                 Ptakefocus = 1;
01508             else if (p[i] == atoms->net_wm_take_activity)
01509                 Ptakeactivity = 1;
01510             else if (p[i] == atoms->net_wm_context_help)
01511                 Pcontexthelp = 1;
01512             else if (p[i] == atoms->net_wm_ping)
01513                 Pping = 1;
01514         if (n>0)
01515             XFree(p);
01516         }
01517     }
01518 
01519 static int nullErrorHandler(Display *, XErrorEvent *)
01520     {
01521     return 0;
01522     }
01523 
01527 QCString Client::staticWindowRole(WId w)
01528     {
01529     return getStringProperty(w, qt_window_role).lower();
01530     }
01531 
01535 QCString Client::staticSessionId(WId w)
01536     {
01537     return getStringProperty(w, qt_sm_client_id);
01538     }
01539 
01543 QCString Client::staticWmCommand(WId w)
01544     {
01545     return getStringProperty(w, XA_WM_COMMAND, ' ');
01546     }
01547 
01551 Window Client::staticWmClientLeader(WId w)
01552     {
01553     Atom type;
01554     int format, status;
01555     unsigned long nitems = 0;
01556     unsigned long extra = 0;
01557     unsigned char *data = 0;
01558     Window result = w;
01559     XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
01560     status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
01561                                  FALSE, XA_WINDOW, &type, &format,
01562                                  &nitems, &extra, &data );
01563     XSetErrorHandler(oldHandler);
01564     if (status  == Success ) 
01565         {
01566         if (data && nitems > 0)
01567             result = *((Window*) data);
01568         XFree(data);
01569         }
01570     return result;
01571     }
01572 
01573 
01574 void Client::getWmClientLeader()
01575     {
01576     wmClientLeaderWin = staticWmClientLeader(window());
01577     }
01578 
01583 QCString Client::sessionId()
01584     {
01585     QCString result = staticSessionId(window());
01586     if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01587         result = staticSessionId(wmClientLeaderWin);
01588     return result;
01589     }
01590 
01595 QCString Client::wmCommand()
01596     {
01597     QCString result = staticWmCommand(window());
01598     if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01599         result = staticWmCommand(wmClientLeaderWin);
01600     return result;
01601     }
01602 
01603 void Client::getWmClientMachine()
01604     {
01605     client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
01606     if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01607         client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
01608     if( client_machine.isEmpty())
01609         client_machine = "localhost";
01610     }
01611 
01616 QCString Client::wmClientMachine( bool use_localhost ) const
01617     {
01618     QCString result = client_machine;
01619     if( use_localhost )
01620         { // special name for the local machine (localhost)
01621         if( result != "localhost" && isLocalMachine( result ))
01622             result = "localhost";
01623         }
01624     return result;
01625     }
01626 
01631 Window Client::wmClientLeader() const
01632     {
01633     if (wmClientLeaderWin)
01634         return wmClientLeaderWin;
01635     return window();
01636     }
01637 
01638 bool Client::wantsTabFocus() const
01639     {
01640     return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
01641     }
01642 
01643 
01644 bool Client::wantsInput() const
01645     {
01646     return rules()->checkAcceptFocus( input || Ptakefocus );
01647     }
01648 
01649 bool Client::isDesktop() const
01650     {
01651     return windowType() == NET::Desktop;
01652     }
01653 
01654 bool Client::isDock() const
01655     {
01656     return windowType() == NET::Dock;
01657     }
01658 
01659 bool Client::isTopMenu() const
01660     {
01661     return windowType() == NET::TopMenu;
01662     }
01663 
01664 
01665 bool Client::isMenu() const
01666     {
01667     return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
01668     }
01669 
01670 bool Client::isToolbar() const
01671     {
01672     return windowType() == NET::Toolbar;
01673     }
01674 
01675 bool Client::isSplash() const
01676     {
01677     return windowType() == NET::Splash;
01678     }
01679 
01680 bool Client::isUtility() const
01681     {
01682     return windowType() == NET::Utility;
01683     }
01684 
01685 bool Client::isDialog() const
01686     {
01687     return windowType() == NET::Dialog;
01688     }
01689 
01690 bool Client::isNormalWindow() const
01691     {
01692     return windowType() == NET::Normal;
01693     }
01694 
01695 bool Client::isSpecialWindow() const
01696     {
01697     return isDesktop() || isDock() || isSplash() || isTopMenu()
01698         || isToolbar(); // TODO
01699     }
01700 
01701 NET::WindowType Client::windowType( bool direct, int supported_types ) const
01702     {
01703     NET::WindowType wt = info->windowType( supported_types );
01704     if( direct )
01705         return wt;
01706     NET::WindowType wt2 = rules()->checkType( wt );
01707     if( wt != wt2 )
01708         {
01709         wt = wt2;
01710         info->setWindowType( wt ); // force hint change
01711         }
01712     // hacks here
01713     if( wt == NET::Menu )
01714         {
01715         // ugly hack to support the times when NET::Menu meant NET::TopMenu
01716         // if it's as wide as the screen, not very high and has its upper-left
01717         // corner a bit above the screen's upper-left cornet, it's a topmenu
01718         if( x() == 0 && y() < 0 && y() > -10 && height() < 100
01719             && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
01720             wt = NET::TopMenu;
01721         }
01722     // TODO change this to rule
01723     const char* const oo_prefix = "openoffice.org"; // QCString has no startsWith()
01724     // oo_prefix is lowercase, because resourceClass() is forced to be lowercase
01725     if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
01726         wt = NET::Normal; // see bug #66065
01727     if( wt == NET::Unknown ) // this is more or less suggested in NETWM spec
01728         wt = isTransient() ? NET::Dialog : NET::Normal;
01729     return wt;
01730     }
01731 
01736 void Client::setCursor( Position m )
01737     {
01738     if( !isResizable() || isShade())
01739         {
01740         m = PositionCenter;
01741         }
01742     switch ( m ) 
01743         {
01744         case PositionTopLeft:
01745         case PositionBottomRight:
01746             setCursor( sizeFDiagCursor );
01747             break;
01748         case PositionBottomLeft:
01749         case PositionTopRight:
01750             setCursor( sizeBDiagCursor );
01751             break;
01752         case PositionTop:
01753         case PositionBottom:
01754             setCursor( sizeVerCursor );
01755             break;
01756         case PositionLeft:
01757         case PositionRight:
01758             setCursor( sizeHorCursor );
01759             break;
01760         default:
01761             if( buttonDown && isMovable())
01762                 setCursor( sizeAllCursor );
01763             else
01764                 setCursor( arrowCursor );
01765             break;
01766         }
01767     }
01768 
01769 // TODO mit nejake checkCursor(), ktere se zavola v manage() a pri vecech, kdy by se kurzor mohl zmenit?
01770 void Client::setCursor( const QCursor& c )
01771     {
01772     if( c.handle() == cursor.handle())
01773         return;
01774     cursor = c;
01775     if( decoration != NULL )
01776         decoration->widget()->setCursor( cursor );
01777     XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
01778     }
01779 
01780 Client::Position Client::mousePosition( const QPoint& p ) const
01781     {
01782     if( decoration != NULL )
01783         return decoration->mousePosition( p );
01784     return PositionCenter;
01785     }
01786 
01787 void Client::updateAllowedActions( bool force )
01788     {
01789     if( !isManaged() && !force )
01790         return;
01791     unsigned long old_allowed_actions = allowed_actions;
01792     allowed_actions = 0;
01793     if( isMovable())
01794         allowed_actions |= NET::ActionMove;
01795     if( isResizable())
01796         allowed_actions |= NET::ActionResize;
01797     if( isMinimizable())
01798         allowed_actions |= NET::ActionMinimize;
01799     if( isShadeable())
01800         allowed_actions |= NET::ActionShade;
01801     // sticky state not supported
01802     if( isMaximizable())
01803         allowed_actions |= NET::ActionMax;
01804     if( userCanSetFullScreen())
01805         allowed_actions |= NET::ActionFullScreen;
01806     allowed_actions |= NET::ActionChangeDesktop; // always (pagers shouldn't show Docks etc.)
01807     if( isCloseable())
01808         allowed_actions |= NET::ActionClose;
01809     if( old_allowed_actions == allowed_actions )
01810         return;
01811     // TODO this could be delayed and compressed - it's only for pagers etc. anyway
01812     info->setAllowedActions( allowed_actions );
01813     // TODO this should also tell the decoration, so that it can update the buttons
01814     }
01815 
01816 void Client::autoRaise()
01817     {
01818     workspace()->raiseClient( this );
01819     cancelAutoRaise();
01820     }
01821     
01822 void Client::cancelAutoRaise()
01823     {
01824     delete autoRaiseTimer;
01825     autoRaiseTimer = 0;
01826     }
01827 
01828 void Client::setOpacity(bool translucent, uint opacity)
01829     {
01830     if (isDesktop())
01831         return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
01832 //     qWarning("setting opacity for %d",qt_xdisplay());
01833     //rule out activated translulcency with 100% opacity
01834     if (!translucent || opacity ==  0xFFFFFFFF)
01835         {
01836         opacity_ = 0xFFFFFFFF;
01837         XDeleteProperty (qt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
01838         XDeleteProperty (qt_xdisplay(), window(), atoms->net_wm_window_opacity); // ??? frameId() is necessary for visible changes, window() is the winId() that would be set by apps - we set both to be sure the app knows what's currently displayd
01839         }
01840     else{
01841         if(opacity == opacity_)
01842             return;
01843         opacity_ = opacity;
01844         long data = opacity; // 32bit XChangeProperty needs long
01845         XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01846         XChangeProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01847         }
01848     }
01849     
01850 void Client::setShadowSize(uint shadowSize)
01851     {
01852     // ignoring all individual settings - if we control a window, we control it's shadow
01853     // TODO somehow handle individual settings for docks (besides custom sizes)
01854     long data = shadowSize;
01855     XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01856     }
01857         
01858 void Client::updateOpacity()
01859 // extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
01860     {
01861     if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
01862         return;
01863     if (isActive())
01864         {
01865         if( ruleOpacityActive() )
01866             setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01867         else
01868             setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01869         if (isBMP())
01870         // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
01871             {
01872             ClientList tmpGroupMembers = group()->members();
01873             ClientList activeGroupMembers;
01874             activeGroupMembers.append(this);
01875             tmpGroupMembers.remove(this);
01876             ClientList::Iterator it = tmpGroupMembers.begin();
01877             while (it != tmpGroupMembers.end())
01878             // search for next attached and not activated client and repeat if found
01879                 {
01880                 if ((*it) != this && (*it)->isBMP())
01881                 // potential "to activate" client found
01882                     {
01883 //                     qWarning("client found");
01884                     if ((*it)->touches(this)) // first test, if the new client touches the just activated one
01885                         {
01886 //                         qWarning("found client touches me");
01887                         if( ruleOpacityActive() )
01888                             (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01889                         else
01890                             (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01891 //                         qWarning("activated, search restarted (1)");
01892                         (*it)->setShadowSize(options->activeWindowShadowSize);
01893                         activeGroupMembers.append(*it);
01894                         tmpGroupMembers.remove(it);
01895                         it = tmpGroupMembers.begin(); // restart, search next client
01896                         continue;
01897                         }
01898                     else
01899                         { // pot. client does not touch c, so we have to search if it touches some other activated client
01900                         bool found = false;
01901                         for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
01902                             {
01903                             if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
01904                                 {
01905 //                                 qWarning("found client touches other active client");
01906                                 if( ruleOpacityActive() )
01907                                     (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01908                                 else
01909                                     (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01910                                 (*it)->setShadowSize(options->activeWindowShadowSize);
01911                                 activeGroupMembers.append(*it);
01912                                 tmpGroupMembers.remove(it);
01913                                 it = tmpGroupMembers.begin(); // reset potential client search
01914                                 found = true;
01915 //                                 qWarning("activated, search restarted (2)");
01916                                 break; // skip this loop
01917                                 }
01918                             }
01919                         if (found) continue;
01920                         }
01921                     }
01922                     it++;
01923                 }
01924             }
01925         else if (isNormalWindow())
01926         // activate dependend minor windows as well
01927             {
01928             for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
01929                 if ((*it)->isDialog() || (*it)->isUtility())
01930                     if( (*it)->ruleOpacityActive() )
01931                         (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
01932                     else
01933                         (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01934             }
01935         }
01936     else
01937         {
01938         if( ruleOpacityInactive() )
01939             setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
01940         else
01941             setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
01942                     options->inactiveWindowOpacity);
01943         // deactivate dependend minor windows as well
01944         if (isBMP())
01945         // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
01946             {
01947             ClientList tmpGroupMembers = group()->members();
01948             ClientList inactiveGroupMembers;
01949             inactiveGroupMembers.append(this);
01950             tmpGroupMembers.remove(this);
01951             ClientList::Iterator it = tmpGroupMembers.begin();
01952             while ( it != tmpGroupMembers.end() )
01953             // search for next attached and not activated client and repeat if found
01954                 {
01955                 if ((*it) != this && (*it)->isBMP())
01956                 // potential "to activate" client found
01957                     {
01958 //                     qWarning("client found");
01959                     if ((*it)->touches(this)) // first test, if the new client touches the just activated one
01960                         {
01961 //                         qWarning("found client touches me");
01962                         if( (*it)->ruleOpacityInactive() )
01963                             (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
01964                         else
01965                             (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
01966                         (*it)->setShadowSize(options->inactiveWindowShadowSize);
01967 //                         qWarning("deactivated, search restarted (1)");
01968                         inactiveGroupMembers.append(*it);
01969                         tmpGroupMembers.remove(it);
01970                         it = tmpGroupMembers.begin(); // restart, search next client
01971                         continue;
01972                         }
01973                     else // pot. client does not touch c, so we have to search if it touches some other activated client
01974                         {
01975                         bool found = false;
01976                         for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
01977                             {
01978                             if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
01979                                 {
01980 //                                 qWarning("found client touches other inactive client");
01981                                 if( (*it)->ruleOpacityInactive() )
01982                                     (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
01983                                 else
01984                                     (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
01985                                 (*it)->setShadowSize(options->inactiveWindowShadowSize);
01986 //                                 qWarning("deactivated, search restarted (2)");
01987                                 inactiveGroupMembers.append(*it);
01988                                 tmpGroupMembers.remove(it);
01989                                 it = tmpGroupMembers.begin(); // reset potential client search
01990                                 found = true;
01991                                 break; // skip this loop
01992                                 }
01993                             }
01994                             if (found) continue;
01995                         }
01996                     }
01997                     it++;
01998                 }
01999             }
02000         else if (isNormalWindow())
02001             {
02002             for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
02003                 if ((*it)->isUtility()) //don't deactivate dialogs...
02004                     if( (*it)->ruleOpacityInactive() )
02005                         (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02006                     else
02007                         (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02008             }
02009         }
02010     }
02011     
02012 void Client::updateShadowSize()
02013 // extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
02014     {
02015     if (!(isNormalWindow() || isDialog() || isUtility() ))
02016         return;
02017     if (isActive())
02018         setShadowSize(options->activeWindowShadowSize);
02019     else
02020         setShadowSize(options->inactiveWindowShadowSize);
02021     }
02022 
02023 uint Client::ruleOpacityInactive()
02024     {
02025     return rule_opacity_inactive;// != 0 ;
02026     }
02027 
02028 uint Client::ruleOpacityActive()
02029     {
02030     return rule_opacity_active;// != 0;
02031     }
02032     
02033 bool Client::getWindowOpacity() //query translucency settings from X, returns true if window opacity is set
02034     {
02035     unsigned char *data = 0;
02036     Atom actual;
02037     int format, result;
02038     unsigned long n, left;
02039     result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
02040     if (result == Success && data != None && format == 32 )
02041         {
02042         opacity_ = *reinterpret_cast< long* >( data );
02043         custom_opacity = true;
02044 //         setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
02045         XFree ((char*)data);
02046         return TRUE;
02047         }
02048     return FALSE;
02049     }
02050     
02051 void Client::setCustomOpacityFlag(bool custom)
02052     {
02053     custom_opacity = custom;
02054     }
02055     
02056 uint Client::opacity()
02057     {
02058     return opacity_;
02059     }
02060 
02061 int Client::opacityPercentage()
02062     {
02063     return int(100*((double)opacity_/0xffffffff));
02064     }
02065     
02066 bool Client::touches(const Client* c)
02067 // checks if this client borders c, needed to test beep media player window state
02068     {
02069     if (y() == c->y() + c->height()) // this bottom to c
02070         return TRUE;
02071     if (y() + height() == c->y()) // this top to c
02072         return TRUE;
02073     if (x() == c->x() + c->width()) // this right to c
02074         return TRUE;
02075     if (x() + width() == c->x()) // this left to c
02076         return TRUE;
02077     return FALSE;
02078     }
02079     
02080 void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
02081 {
02082    long data = (topHeight < 255 ? topHeight : 255) << 24 |
02083                (rightWidth < 255 ? rightWidth : 255) << 16 |
02084                (bottomHeight < 255 ? bottomHeight : 255) << 8 |
02085                (leftWidth < 255 ? leftWidth : 255);
02086     XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02087 }
02088 
02089 void Client::unsetDecoHashProperty()
02090 {
02091    XDeleteProperty( qt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
02092 }
02093     
02094 #ifndef NDEBUG
02095 kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
02096     {
02097     if( cl == NULL )
02098         return stream << "\'NULL_CLIENT\'";
02099     return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
02100     }
02101 kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
02102     {
02103     stream << "LIST:(";
02104     bool first = true;
02105     for( ClientList::ConstIterator it = list.begin();
02106          it != list.end();
02107          ++it )
02108         {
02109         if( !first )
02110             stream << ":";
02111         first = false;
02112         stream << *it;
02113         }
02114     stream << ")";
02115     return stream;
02116     }
02117 kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
02118     {
02119     stream << "LIST:(";
02120     bool first = true;
02121     for( ConstClientList::ConstIterator it = list.begin();
02122          it != list.end();
02123          ++it )
02124         {
02125         if( !first )
02126             stream << ":";
02127         first = false;
02128         stream << *it;
02129         }
02130     stream << ")";
02131     return stream;
02132     }
02133 #endif
02134 
02135 QPixmap * kwin_get_menu_pix_hack()
02136     {
02137     static QPixmap p;
02138     if ( p.isNull() )
02139         p = SmallIcon( "bx2" );
02140     return &p;
02141     }
02142 
02143 } // namespace
02144 
02145 #include "client.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys