• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • @topname@
  • Sitemap
  • Contact Us
 

kwin

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

kwin

Skip menu "kwin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

@topname@

Skip menu "@topname@"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for @topname@ by doxygen 1.5.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal