• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kwin
 

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 <math.h>
00015 
00016 #include <tqapplication.h>
00017 #include <tqpainter.h>
00018 #include <tqdatetime.h>
00019 #include <tqimage.h>
00020 #include <kprocess.h>
00021 #include <unistd.h>
00022 #include <kstandarddirs.h>
00023 #include <tqwhatsthis.h>
00024 #include <kwin.h>
00025 #include <kiconloader.h>
00026 #include <stdlib.h>
00027 
00028 #include "bridge.h"
00029 #include "group.h"
00030 #include "workspace.h"
00031 #include "atoms.h"
00032 #include "notifications.h"
00033 #include "rules.h"
00034 
00035 #include <X11/extensions/shape.h>
00036 
00037 // put all externs before the namespace statement to allow the linker
00038 // to resolve them properly
00039 
00040 extern Atom qt_wm_state;
00041 extern Time qt_x_time;
00042 extern Atom qt_window_role;
00043 extern Atom qt_sm_client_id;
00044 
00045 // wait 200 ms before drawing shadow after move/resize
00046 static const int SHADOW_DELAY = 200;
00047 
00048 namespace KWinInternal
00049 {
00050 
00051 /* TODO: Remove this once X has real translucency.
00052  *
00053  * A list of the regions covered by all shadows and the Clients to which they
00054  * belong. Used to redraw shadows when a window overlapping or underlying a
00055  * shadow is moved, resized, or hidden.
00056  */
00057 struct ShadowRegion
00058     {
00059     TQRegion region;
00060     Client *client;
00061     };
00062 static TQValueList<ShadowRegion> shadowRegions;
00063 
00064 /*
00065 
00066  Creating a client:
00067      - only by calling Workspace::createClient()
00068          - it creates a new client and calls manage() for it
00069 
00070  Destroying a client:
00071      - destroyClient() - only when the window itself has been destroyed
00072      - releaseWindow() - the window is kept, only the client itself is destroyed
00073 
00074 */
00075 
00076 
00088 Client::Client( Workspace *ws )
00089     :   TQObject( NULL ),
00090         client( None ),
00091         wrapper( None ),
00092         frame( None ),
00093         decoration( NULL ),
00094         wspace( ws ),
00095         bridge( new Bridge( this )),
00096         move_faked_activity( false ),
00097         move_resize_grab_window( None ),
00098         transient_for( NULL ),
00099         transient_for_id( None ),
00100         original_transient_for_id( None ),
00101         in_group( NULL ),
00102         window_group( None ),
00103         in_layer( UnknownLayer ),
00104         ping_timer( NULL ),
00105         process_killer( NULL ),
00106         user_time( CurrentTime ), // not known yet
00107         allowed_actions( 0 ),
00108         postpone_geometry_updates( 0 ),
00109         pending_geometry_update( false ),
00110         shade_geometry_change( false ),
00111         border_left( 0 ),
00112         border_right( 0 ),
00113         border_top( 0 ),
00114         border_bottom( 0 ),
00115         opacity_( 0 ),
00116         demandAttentionKNotifyTimer( NULL )
00117 // SELI do all as initialization
00118     {
00119     autoRaiseTimer = 0;
00120     shadeHoverTimer = 0;
00121 
00122     shadowDelayTimer = new TQTimer(this);
00123     opacityCache = &activeOpacityCache;
00124     shadowAfterClient = NULL;
00125     shadowWidget = NULL;
00126     shadowMe = true;
00127     connect(shadowDelayTimer, TQT_SIGNAL(timeout()), TQT_SLOT(drawShadow()));
00128 
00129     // set the initial mapping state
00130     mapping_state = WithdrawnState;
00131     desk = 0; // no desktop yet
00132 
00133     mode = PositionCenter;
00134     buttonDown = FALSE;
00135     moveResizeMode = FALSE;
00136 
00137     info = NULL;
00138 
00139     shade_mode = ShadeNone;
00140     active = FALSE;
00141     deleting = false;
00142     keep_above = FALSE;
00143     keep_below = FALSE;
00144     is_shape = FALSE;
00145     motif_noborder = false;
00146     motif_may_move = TRUE;
00147     motif_may_resize = TRUE;
00148     motif_may_close = TRUE;
00149     fullscreen_mode = FullScreenNone;
00150     skip_taskbar = FALSE;
00151     original_skip_taskbar = false;
00152     minimized = false;
00153     hidden = false;
00154     modal = false;
00155     noborder = false;
00156     user_noborder = false;
00157     urgency = false;
00158     ignore_focus_stealing = false;
00159     demands_attention = false;
00160     check_active_modal = false;
00161 
00162     Pdeletewindow = 0;
00163     Ptakefocus = 0;
00164     Ptakeactivity = 0;
00165     Pcontexthelp = 0;
00166     Pping = 0;
00167     input = FALSE;
00168     skip_pager = FALSE;
00169 
00170     max_mode = MaximizeRestore;
00171     maxmode_restore = MaximizeRestore;
00172     
00173     cmap = None;
00174 
00175     frame_geometry = TQRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
00176     client_size = TQSize( 100, 100 );
00177     custom_opacity = false;
00178     rule_opacity_active = 0;; //translucency rules
00179     rule_opacity_inactive = 0; //dito.
00180 
00181     // SELI initialize xsizehints??
00182     }
00183 
00187 Client::~Client()
00188     {
00189     assert(!moveResizeMode);
00190     assert( client == None );
00191     assert( frame == None && wrapper == None );
00192     assert( decoration == NULL );
00193     assert( postpone_geometry_updates == 0 );
00194     assert( !check_active_modal );
00195     delete info;
00196     delete bridge;
00197     }
00198 
00199 // use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
00200 void Client::deleteClient( Client* c, allowed_t )
00201     {
00202     delete c;
00203     }
00204 
00208 void Client::releaseWindow( bool on_shutdown )
00209     {
00210     assert( !deleting );
00211     deleting = true;
00212     workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
00213     StackingUpdatesBlocker blocker( workspace());
00214     if (!custom_opacity) setOpacity(FALSE);
00215     if (moveResizeMode)
00216        leaveMoveResize();
00217     removeShadow();
00218     drawIntersectingShadows();
00219     finishWindowRules();
00220     ++postpone_geometry_updates;
00221     // grab X during the release to make removing of properties, setting to withdrawn state
00222     // and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2)
00223     grabXServer();
00224     setMappingState( WithdrawnState );
00225     setModal( false ); // otherwise its mainwindow wouldn't get focus
00226     hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
00227     if( !on_shutdown )
00228         workspace()->clientHidden( this );
00229     XUnmapWindow( qt_xdisplay(), frameId()); // destroying decoration would cause ugly visual effect
00230     destroyDecoration();
00231     cleanGrouping();
00232     if( !on_shutdown )
00233         {
00234         workspace()->removeClient( this, Allowed );
00235         // only when the window is being unmapped, not when closing down KWin
00236         // (NETWM sections 5.5,5.7)
00237         info->setDesktop( 0 );
00238         desk = 0;
00239         info->setState( 0, info->state()); // reset all state flags
00240         }
00241     XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
00242     XDeleteProperty( qt_xdisplay(), client, atoms->net_frame_extents );
00243     XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_frame_strut );
00244     XReparentWindow( qt_xdisplay(), client, workspace()->rootWin(), x(), y());
00245     XRemoveFromSaveSet( qt_xdisplay(), client );
00246     XSelectInput( qt_xdisplay(), client, NoEventMask );
00247     if( on_shutdown )
00248         { // map the window, so it can be found after another WM is started
00249         XMapWindow( qt_xdisplay(), client );
00250     // TODO preserve minimized, shaded etc. state?
00251         }
00252     else
00253         {
00254         // Make sure it's not mapped if the app unmapped it (#65279). The app
00255         // may do map+unmap before we initially map the window by calling rawShow() from manage().
00256         XUnmapWindow( qt_xdisplay(), client ); 
00257         }
00258     client = None;
00259     XDestroyWindow( qt_xdisplay(), wrapper );
00260     wrapper = None;
00261     XDestroyWindow( qt_xdisplay(), frame );
00262     frame = None;
00263     --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
00264     checkNonExistentClients();
00265     deleteClient( this, Allowed );
00266     ungrabXServer();
00267     }
00268 
00269 // like releaseWindow(), but this one is called when the window has been already destroyed
00270 // (e.g. the application closed it)
00271 void Client::destroyClient()
00272     {
00273     assert( !deleting );
00274     deleting = true;
00275     workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
00276     StackingUpdatesBlocker blocker( workspace());
00277     if (moveResizeMode)
00278        leaveMoveResize();
00279     removeShadow();
00280     drawIntersectingShadows();
00281     finishWindowRules();
00282     ++postpone_geometry_updates;
00283     setModal( false );
00284     hidden = true; // so that it's not considered visible anymore
00285     workspace()->clientHidden( this );
00286     destroyDecoration();
00287     cleanGrouping();
00288     workspace()->removeClient( this, Allowed );
00289     client = None; // invalidate
00290     XDestroyWindow( qt_xdisplay(), wrapper );
00291     wrapper = None;
00292     XDestroyWindow( qt_xdisplay(), frame );
00293     frame = None;
00294     --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
00295     checkNonExistentClients();
00296     deleteClient( this, Allowed );
00297     }
00298 
00299 void Client::updateDecoration( bool check_workspace_pos, bool force )
00300     {
00301     if( !force && (( decoration == NULL && noBorder())
00302                     || ( decoration != NULL && !noBorder())))
00303         return;
00304     bool do_show = false;
00305     postponeGeometryUpdates( true );
00306     if( force )
00307         destroyDecoration();
00308     if( !noBorder())
00309         {
00310         setMask( TQRegion()); // reset shape mask
00311         decoration = workspace()->createDecoration( bridge );
00312         // TODO check decoration's minimum size?
00313         decoration->init();
00314         decoration->widget()->installEventFilter( this );
00315         XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
00316         decoration->widget()->lower();
00317         decoration->borders( border_left, border_right, border_top, border_bottom );
00318         options->onlyDecoTranslucent ?
00319             setDecoHashProperty(border_top, border_right, border_bottom, border_left):
00320             unsetDecoHashProperty();
00321         int save_workarea_diff_x = workarea_diff_x;
00322         int save_workarea_diff_y = workarea_diff_y;
00323         move( calculateGravitation( false ));
00324         plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00325         workarea_diff_x = save_workarea_diff_x;
00326         workarea_diff_y = save_workarea_diff_y;
00327         do_show = true;
00328         }
00329     else
00330         destroyDecoration();
00331     if( check_workspace_pos )
00332         checkWorkspacePosition();
00333     postponeGeometryUpdates( false );
00334     if( do_show )
00335         decoration->widget()->show();
00336     updateFrameExtents();
00337     updateOpacityCache();
00338     }
00339 
00340 void Client::destroyDecoration()
00341     {
00342     if( decoration != NULL )
00343         {
00344         delete decoration;
00345         decoration = NULL;
00346         TQPoint grav = calculateGravitation( true );
00347         border_left = border_right = border_top = border_bottom = 0;
00348         setMask( TQRegion()); // reset shape mask
00349         int save_workarea_diff_x = workarea_diff_x;
00350         int save_workarea_diff_y = workarea_diff_y;
00351         plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00352         move( grav );
00353         workarea_diff_x = save_workarea_diff_x;
00354         workarea_diff_y = save_workarea_diff_y;
00355         }
00356     }
00357 
00358 void Client::checkBorderSizes()
00359     {
00360     if( decoration == NULL )
00361         return;
00362     int new_left, new_right, new_top, new_bottom;
00363     decoration->borders( new_left, new_right, new_top, new_bottom );
00364     if( new_left == border_left && new_right == border_right
00365         && new_top == border_top && new_bottom == border_bottom )
00366         return;
00367     GeometryUpdatesPostponer blocker( this );
00368     move( calculateGravitation( true ));
00369     border_left = new_left;
00370     border_right = new_right;
00371     border_top = new_top;
00372     border_bottom = new_bottom;
00373     if (border_left != new_left ||
00374         border_right != new_right ||
00375         border_top != new_top ||
00376         border_bottom != new_bottom)
00377     options->onlyDecoTranslucent ?
00378        setDecoHashProperty(new_top, new_right, new_bottom, new_left):
00379        unsetDecoHashProperty();
00380     move( calculateGravitation( false ));
00381     plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00382     checkWorkspacePosition();
00383     }
00384 
00385 void Client::detectNoBorder()
00386     {
00387     if( Shape::hasShape( window()))
00388         {
00389         noborder = true;
00390         return;
00391         }
00392     switch( windowType())
00393         {
00394         case NET::Desktop :
00395         case NET::Dock :
00396         case NET::TopMenu :
00397         case NET::Splash :
00398             noborder = true;
00399           break;
00400         case NET::Unknown :
00401         case NET::Normal :
00402         case NET::Toolbar :
00403         case NET::Menu :
00404         case NET::Dialog :
00405         case NET::Utility :
00406             noborder = false;
00407           break;
00408         default:
00409             assert( false );
00410         }
00411     // NET::Override is some strange beast without clear definition, usually
00412     // just meaning "noborder", so let's treat it only as such flag, and ignore it as
00413     // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
00414     if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
00415         noborder = true;
00416     }
00417 
00418 void Client::detectShapable()
00419     {
00420     if( Shape::hasShape( window()))
00421         return;
00422     switch( windowType())
00423         {
00424         case NET::Desktop :
00425         case NET::Dock :
00426         case NET::TopMenu :
00427         case NET::Splash :
00428           break;
00429         case NET::Unknown :
00430         case NET::Normal :
00431         case NET::Toolbar :
00432         case NET::Menu :
00433         case NET::Dialog :
00434         case NET::Utility :
00435             setShapable(FALSE);
00436           break;
00437         default:
00438             assert( false );
00439         }
00440     }
00441 
00442 void Client::updateFrameExtents()
00443     {
00444     NETStrut strut;
00445     strut.left = border_left;
00446     strut.right = border_right;
00447     strut.top = border_top;
00448     strut.bottom = border_bottom;
00449     info->setFrameExtents( strut );
00450     }
00451 
00452 // Resizes the decoration, and makes sure the decoration widget gets resize event
00453 // even if the size hasn't changed. This is needed to make sure the decoration
00454 // re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes,
00455 // the decoration may turn on/off some borders, but the actual size
00456 // of the decoration stays the same).
00457 void Client::resizeDecoration( const TQSize& s )
00458     {
00459     if( decoration == NULL )
00460         return;
00461     TQSize oldsize = decoration->widget()->size();
00462     decoration->resize( s );
00463     if( oldsize == s )
00464         {
00465         TQResizeEvent e( s, oldsize );
00466         TQApplication::sendEvent( decoration->widget(), &e );
00467         }
00468     if (!moveResizeMode && options->shadowEnabled(isActive()))
00469         {
00470         // If the user is manually resizing, let Client::leaveMoveResize()
00471         // decide when to redraw the shadow
00472         updateOpacityCache();
00473         }
00474     }
00475 
00476 bool Client::noBorder() const
00477     {
00478     return noborder || isFullScreen() || user_noborder || motif_noborder;
00479     }
00480 
00481 bool Client::userCanSetNoBorder() const
00482     {
00483     return !noborder && !isFullScreen() && !isShade();
00484     }
00485 
00486 bool Client::isUserNoBorder() const
00487     {
00488     return user_noborder;
00489     }
00490 
00491 void Client::setUserNoBorder( bool set )
00492     {
00493     if( !userCanSetNoBorder())
00494         return;
00495     set = rules()->checkNoBorder( set );
00496     if( user_noborder == set )
00497         return;
00498     user_noborder = set;
00499     updateDecoration( true, false );
00500     updateWindowRules();
00501     }
00502 
00503 void Client::updateShape()
00504     {
00505     // workaround for #19644 - shaped windows shouldn't have decoration
00506     if( shape() && !noBorder()) 
00507         {
00508         noborder = true;
00509         updateDecoration( true );
00510         }
00511     updateOpacityCache();
00512     if ( shape() )
00513         {
00514         XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
00515                            clientPos().x(), clientPos().y(),
00516                            window(), ShapeBounding, ShapeSet);
00517         setShapable(TRUE);
00518         }
00519     // !shape() mask setting is done in setMask() when the decoration
00520     // calls it or when the decoration is created/destroyed
00521 
00522     if( Shape::version() >= 0x11 ) // 1.1, has input shape support
00523         { // There appears to be no way to find out if a window has input
00524           // shape set or not, so always propagate the input shape
00525           // (it's the same like the bounding shape by default).
00526           // Also, build the shape using a helper window, not directly
00527           // in the frame window, because the sequence set-shape-to-frame,
00528           // remove-shape-of-client, add-input-shape-of-client has the problem
00529           // that after the second step there's a hole in the input shape
00530           // until the real shape of the client is added and that can make
00531           // the window lose focus (which is a problem with mouse focus policies)
00532         static Window helper_window = None;
00533         if( helper_window == None )
00534             helper_window = XCreateSimpleWindow( qt_xdisplay(), qt_xrootwin(),
00535                 0, 0, 1, 1, 0, 0, 0 );
00536         XResizeWindow( qt_xdisplay(), helper_window, width(), height());
00537         XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput, 0, 0,
00538                            frameId(), ShapeBounding, ShapeSet );
00539         XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
00540                            clientPos().x(), clientPos().y(),
00541                            window(), ShapeBounding, ShapeSubtract );
00542         XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
00543                            clientPos().x(), clientPos().y(),
00544                            window(), ShapeInput, ShapeUnion );
00545         XShapeCombineShape( qt_xdisplay(), frameId(), ShapeInput, 0, 0,
00546                            helper_window, ShapeInput, ShapeSet );
00547         }
00548     }
00549 
00550 void Client::setMask( const TQRegion& reg, int mode )
00551     {
00552     _mask = reg;
00553     if( reg.isNull())
00554         XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00555             None, ShapeSet );
00556     else if( mode == X::Unsorted )
00557         XShapeCombineRegion( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00558             reg.handle(), ShapeSet );
00559     else
00560         {
00561         TQMemArray< TQRect > rects = reg.rects();
00562         XRectangle* xrects = new XRectangle[ rects.count() ];
00563         for( unsigned int i = 0;
00564              i < rects.count();
00565              ++i )
00566             {
00567             xrects[ i ].x = rects[ i ].x();
00568             xrects[ i ].y = rects[ i ].y();
00569             xrects[ i ].width = rects[ i ].width();
00570             xrects[ i ].height = rects[ i ].height();
00571             }
00572         XShapeCombineRectangles( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00573             xrects, rects.count(), ShapeSet, mode );
00574         delete[] xrects;
00575         }
00576     updateShape();
00577     }
00578 
00579 TQRegion Client::mask() const
00580     {
00581     if( _mask.isEmpty())
00582         return TQRegion( 0, 0, width(), height());
00583     return _mask;
00584     }
00585     
00586 void Client::setShapable(bool b)
00587     {
00588     long tmp = b?1:0;
00589     XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
00590     }
00591 
00592 void Client::hideClient( bool hide )
00593     {
00594     if( hidden == hide )
00595         return;
00596     hidden = hide;
00597     updateVisibility();
00598     }
00599     
00600 /*
00601   Returns whether the window is minimizable or not
00602  */
00603 bool Client::isMinimizable() const
00604     {
00605     if( isSpecialWindow())
00606         return false;
00607     if( isTransient())
00608         { // #66868 - let other xmms windows be minimized when the mainwindow is minimized
00609         bool shown_mainwindow = false;
00610         ClientList mainclients = mainClients();
00611         for( ClientList::ConstIterator it = mainclients.begin();
00612              it != mainclients.end();
00613              ++it )
00614             {
00615             if( (*it)->isShown( true ))
00616                 shown_mainwindow = true;
00617             }
00618         if( !shown_mainwindow )
00619             return true;
00620         }
00621     // this is here because kicker's taskbar doesn't provide separate entries
00622     // for windows with an explicitly given parent
00623     // TODO perhaps this should be redone
00624     if( transientFor() != NULL )
00625         return false;
00626     if( !wantsTabFocus()) // SELI - NET::Utility? why wantsTabFocus() - skiptaskbar? ?
00627         return false;
00628     return true;
00629     }
00630 
00634 void Client::minimize( bool avoid_animation )
00635     {
00636     if ( !isMinimizable() || isMinimized())
00637         return;
00638 
00639     Notify::raise( Notify::Minimize );
00640 
00641     // SELI mainClients().isEmpty() ??? - and in unminimize() too
00642     if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
00643         animateMinimizeOrUnminimize( true ); // was visible or shaded
00644 
00645     minimized = true;
00646 
00647     updateVisibility();
00648     updateAllowedActions();
00649     workspace()->updateMinimizedOfTransients( this );
00650     updateWindowRules();
00651     workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
00652     }
00653 
00654 void Client::unminimize( bool avoid_animation )
00655     {
00656     if( !isMinimized())
00657         return;
00658 
00659     Notify::raise( Notify::UnMinimize );
00660     minimized = false;
00661     if( isOnCurrentDesktop() && isShown( true ))
00662         {
00663         if( mainClients().isEmpty() && !avoid_animation )
00664             animateMinimizeOrUnminimize( FALSE );
00665         }
00666     updateVisibility();
00667     updateAllowedActions();
00668     workspace()->updateMinimizedOfTransients( this );
00669     updateWindowRules();
00670     }
00671 
00672 extern bool         blockAnimation;
00673 
00674 void Client::animateMinimizeOrUnminimize( bool minimize )
00675     {
00676     if ( blockAnimation )
00677         return;
00678     if ( !options->animateMinimize )
00679         return;
00680 
00681     if( decoration != NULL && decoration->animateMinimize( minimize ))
00682         return; // decoration did it
00683 
00684     // the function is a bit tricky since it will ensure that an
00685     // animation action needs always the same time regardless of the
00686     // performance of the machine or the X-Server.
00687 
00688     float lf,rf,tf,bf,step;
00689 
00690     int speed = options->animateMinimizeSpeed;
00691     if ( speed > 10 )
00692         speed = 10;
00693     if ( speed < 0 )
00694         speed = 0;
00695 
00696     step = 40. * (11 - speed );
00697 
00698     NETRect r = info->iconGeometry();
00699     TQRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
00700     if ( !icongeom.isValid() )
00701         return;
00702 
00703     TQPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
00704 
00705     TQRect before, after;
00706     if ( minimize ) 
00707         {
00708         before = TQRect( x(), y(), width(), pm.height() );
00709         after = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00710         }
00711     else 
00712         {
00713         before = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00714         after = TQRect( x(), y(), width(), pm.height() );
00715         }
00716 
00717     lf = (after.left() - before.left())/step;
00718     rf = (after.right() - before.right())/step;
00719     tf = (after.top() - before.top())/step;
00720     bf = (after.bottom() - before.bottom())/step;
00721 
00722     grabXServer();
00723 
00724     TQRect area = before;
00725     TQRect area2;
00726     TQPixmap pm2;
00727 
00728     TQTime t;
00729     t.start();
00730     float diff;
00731 
00732     TQPainter p ( workspace()->desktopWidget() );
00733     bool need_to_clear = FALSE;
00734     TQPixmap pm3;
00735     do 
00736         {
00737         if (area2 != area)
00738             {
00739             pm = animationPixmap( area.width() );
00740             pm2 = TQPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
00741             p.drawPixmap( area.x(), area.y(), pm );
00742             if ( need_to_clear ) 
00743                 {
00744                 p.drawPixmap( area2.x(), area2.y(), pm3 );
00745                 need_to_clear = FALSE;
00746                 }
00747             area2 = area;
00748             }
00749         XFlush(qt_xdisplay());
00750         XSync( qt_xdisplay(), FALSE );
00751         diff = t.elapsed();
00752         if (diff > step)
00753             diff = step;
00754         area.setLeft(before.left() + int(diff*lf));
00755         area.setRight(before.right() + int(diff*rf));
00756         area.setTop(before.top() + int(diff*tf));
00757         area.setBottom(before.bottom() + int(diff*bf));
00758         if (area2 != area ) 
00759             {
00760             if ( area2.intersects( area ) )
00761                 p.drawPixmap( area2.x(), area2.y(), pm2 );
00762             else 
00763                 { // no overlap, we can clear later to avoid flicker
00764                 pm3 = pm2;
00765                 need_to_clear = TRUE;
00766                 }
00767             }
00768         } while ( t.elapsed() < step);
00769     if (area2 == area || need_to_clear )
00770         p.drawPixmap( area2.x(), area2.y(), pm2 );
00771 
00772     p.end();
00773     ungrabXServer();
00774     }
00775 
00776 
00780 TQPixmap Client::animationPixmap( int w )
00781     {
00782     TQFont font = options->font(isActive());
00783     TQFontMetrics fm( font );
00784     TQPixmap pm( w, fm.lineSpacing() );
00785     pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
00786     TQPainter p( &pm );
00787     p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
00788     p.setFont(options->font(isActive()));
00789     p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
00790     return pm;
00791     }
00792 
00793 
00794 bool Client::isShadeable() const
00795     {
00796     return !isSpecialWindow() && !noBorder();
00797     }
00798 
00799 void Client::setShade( ShadeMode mode )
00800     {
00801     if( !isShadeable())
00802         return;
00803     mode = rules()->checkShade( mode );
00804     if( shade_mode == mode )
00805         return;
00806     bool was_shade = isShade();
00807     ShadeMode was_shade_mode = shade_mode;
00808     shade_mode = mode;
00809     if( was_shade == isShade())
00810         {
00811         if( decoration != NULL ) // decoration may want to update after e.g. hover-shade changes
00812             decoration->shadeChange();
00813         return; // no real change in shaded state
00814         }
00815 
00816     if( shade_mode == ShadeNormal )
00817         {
00818         if ( isShown( true ) && isOnCurrentDesktop())
00819                 Notify::raise( Notify::ShadeUp );
00820         }
00821     else if( shade_mode == ShadeNone )
00822         {
00823         if( isShown( true ) && isOnCurrentDesktop())
00824                 Notify::raise( Notify::ShadeDown );
00825         }
00826 
00827     assert( decoration != NULL ); // noborder windows can't be shaded
00828     GeometryUpdatesPostponer blocker( this );
00829     // decorations may turn off some borders when shaded
00830     decoration->borders( border_left, border_right, border_top, border_bottom );
00831 
00832     int as = options->animateShade? 10 : 1;
00833 // TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
00834     if ( isShade()) 
00835         { // shade_mode == ShadeNormal
00836         // we're about to shade, texx xcompmgr to prepare
00837         long _shade = 1;
00838         XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
00839         // shade
00840         int h = height();
00841         shade_geometry_change = true;
00842         TQSize s( sizeForClientSize( TQSize( clientSize())));
00843         s.setHeight( border_top + border_bottom );
00844         XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
00845         XUnmapWindow( qt_xdisplay(), wrapper );
00846         XUnmapWindow( qt_xdisplay(), client );
00847         XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00848         //as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it        
00849         //done xcompmgr workaround
00850 // FRAME       repaint( FALSE );
00851 //        bool wasStaticContents = testWFlags( WStaticContents );
00852 //        setWFlags( WStaticContents );
00853         int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00854         do 
00855             {
00856             h -= step;
00857             XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00858             resizeDecoration( TQSize( s.width(), h ));
00859             TQApplication::syncX();
00860             } while ( h > s.height() + step );
00861 //        if ( !wasStaticContents )
00862 //            clearWFlags( WStaticContents );
00863         plainResize( s );
00864         shade_geometry_change = false;
00865         if( isActive())
00866             {
00867             if( was_shade_mode == ShadeHover )
00868                 workspace()->activateNextClient( this );
00869             else
00870                 workspace()->focusToNull();
00871             }
00872         // tell xcompmgr shade's done
00873         _shade = 2;
00874         XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);    
00875         }
00876     else 
00877         {
00878         int h = height();
00879         shade_geometry_change = true;
00880         TQSize s( sizeForClientSize( clientSize()));
00881 // FRAME       bool wasStaticContents = testWFlags( WStaticContents );
00882 //        setWFlags( WStaticContents );
00883         int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00884         do 
00885             {
00886             h += step;
00887             XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00888             resizeDecoration( TQSize( s.width(), h ));
00889             // assume a border
00890             // we do not have time to wait for X to send us paint events
00891 // FRAME           repaint( 0, h - step-5, width(), step+5, TRUE);
00892             TQApplication::syncX();
00893             } while ( h < s.height() - step );
00894 //        if ( !wasStaticContents )
00895 //            clearWFlags( WStaticContents );
00896         shade_geometry_change = false;
00897         plainResize( s );
00898         if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
00899             setActive( TRUE );
00900         XMapWindow( qt_xdisplay(), wrapperId());
00901         XMapWindow( qt_xdisplay(), window());
00902         XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade);
00903     if (options->shadowEnabled(false))
00904         {
00905             for (ClientList::ConstIterator it = transients().begin();
00906             it != transients().end(); ++it)
00907             {
00908                     (*it)->removeShadow();
00909                     (*it)->drawDelayedShadow();
00910                 }
00911         }
00912 
00913         if ( isActive() )
00914             workspace()->requestFocus( this );
00915         }
00916     checkMaximizeGeometry();
00917     info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
00918     info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
00919     updateVisibility();
00920     updateAllowedActions();
00921     workspace()->updateMinimizedOfTransients( this );
00922     decoration->shadeChange();
00923     updateWindowRules();
00924     }
00925 
00926 void Client::shadeHover()
00927     {
00928     setShade( ShadeHover );
00929     cancelShadeHover();
00930     }
00931 
00932 void Client::cancelShadeHover()
00933     {
00934     delete shadeHoverTimer;
00935     shadeHoverTimer = 0;
00936     }
00937 
00938 void Client::toggleShade()
00939     {
00940     // if the mode is ShadeHover or ShadeActive, cancel shade too
00941     setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
00942     }
00943 
00944 void Client::updateVisibility()
00945     {
00946     if( deleting )
00947         return;
00948     bool show = true;
00949     if( hidden )
00950         {
00951         setMappingState( IconicState );
00952         info->setState( NET::Hidden, NET::Hidden );
00953         setSkipTaskbar( true, false ); // also hide from taskbar
00954         rawHide();
00955         show = false;
00956         }
00957     else
00958         {
00959         setSkipTaskbar( original_skip_taskbar, false );
00960         }
00961     if( minimized )
00962         {
00963         setMappingState( IconicState );
00964         info->setState( NET::Hidden, NET::Hidden );
00965         rawHide();
00966         show = false;
00967         }
00968     if( show )
00969         info->setState( 0, NET::Hidden );
00970     if( !isOnCurrentDesktop())
00971         {
00972         setMappingState( IconicState );
00973         rawHide();
00974         show = false;
00975         }
00976     if( show )
00977         {
00978         bool belongs_to_desktop = false;
00979         for( ClientList::ConstIterator it = group()->members().begin();
00980              it != group()->members().end();
00981              ++it )
00982             if( (*it)->isDesktop())
00983                 {
00984                 belongs_to_desktop = true;
00985                 break;
00986                 }
00987         if( !belongs_to_desktop && workspace()->showingDesktop())
00988             workspace()->resetShowingDesktop( true );
00989         if( isShade())
00990             setMappingState( IconicState );
00991         else
00992             setMappingState( NormalState );
00993         rawShow();
00994         }
00995     }
00996 
00997 void Client::setShadowed(bool shadowed)
00998 {
00999     bool wasShadowed;
01000 
01001     wasShadowed = isShadowed();
01002     shadowMe = options->shadowEnabled(isActive()) ? shadowed : false;
01003 
01004     if (shadowMe) {
01005         if (!wasShadowed)
01006             drawShadow();
01007     }
01008     else {
01009         if (wasShadowed) {
01010             removeShadow();
01011 
01012             if (!activeOpacityCache.isNull())
01013                 activeOpacityCache.resize(0);
01014             if (!inactiveOpacityCache.isNull())
01015                 inactiveOpacityCache.resize(0);
01016         }
01017     }
01018 }
01019 
01020 void Client::updateOpacityCache()
01021 {
01022     if (!activeOpacityCache.isNull())
01023         activeOpacityCache.resize(0);
01024     if (!inactiveOpacityCache.isNull())
01025         inactiveOpacityCache.resize(0);
01026 
01027     if (!moveResizeMode) {
01028         // If the user is manually resizing, let Client::finishMoveResize()
01029         // decide when to redraw the shadow
01030         removeShadow();
01031         drawIntersectingShadows();
01032         if (options->shadowEnabled(isActive()))
01033             drawDelayedShadow();
01034     }
01035 }
01036 
01041 void Client::drawIntersectingShadows() {
01042     //Client *reshadowClient;
01043     TQRegion region;
01044     //TQPtrList<Client> reshadowClients;
01045     TQValueList<Client *> reshadowClients;
01046     TQValueListIterator<ShadowRegion> it;
01047     TQValueListIterator<Client *> it2;
01048 
01049     if (!options->shadowEnabled(false))
01050         // No point in redrawing overlapping/overlapped shadows if only the
01051         // active window has a shadow.
01052         return;
01053 
01054     region = shapeBoundingRegion;
01055 
01056     // Generate list of Clients whose shadows need to be redrawn. That is,
01057     // those that are currently intersecting or intersected by other windows or
01058     // shadows.
01059     for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
01060         if ((isOnAllDesktops() || (*it).client->isOnCurrentDesktop()) &&
01061                 !(*it).region.intersect(region).isEmpty())
01062             reshadowClients.append((*it).client);
01063 
01064     // Redraw shadows for each of the Clients in the list generated above
01065     for (it2 = reshadowClients.begin(); it2 != reshadowClients.end();
01066             ++it2) {
01067         (*it2)->removeShadow();
01068         (*it2)->drawDelayedShadow();
01069     }
01070 }
01071 
01077 void Client::drawOverlappingShadows(bool waitForMe)
01078 {
01079     Client *aClient;
01080     TQRegion region;
01081     TQValueList<Client *> reshadowClients;
01082     ClientList stacking_order;
01083     ClientList::ConstIterator it;
01084     TQValueListIterator<ShadowRegion> it2;
01085     TQValueListIterator<Client *> it3;
01086 
01087     if (!options->shadowEnabled(false))
01088         // No point in redrawing overlapping/overlapped shadows if only the
01089         // active window has a shadow.
01090         return;
01091 
01092     region = shapeBoundingRegion;
01093 
01094     stacking_order = workspace()->stackingOrder();
01095     for (it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
01096         // Find the position of this window in the stacking order.
01097         if ((*it) == this)
01098             break;
01099     }
01100     ++it;
01101     while (it != stacking_order.end()) {
01102         if ((*it)->windowType() == NET::Dock) {
01103             // This function is only interested in windows whose shadows don't
01104             // have weird stacking rules.
01105             ++it;
01106             continue;
01107         }
01108 
01109         // Generate list of Clients whose shadows need to be redrawn. That is,
01110         // those that are currently overlapping or overlapped by other windows
01111         // or shadows. The list should be in order from bottom to top in the
01112         // stacking order.
01113         for (it2 = shadowRegions.begin(); it2 != shadowRegions.end(); ++it2) {
01114             if ((*it2).client == (*it)) {
01115                 if ((isOnAllDesktops() || (*it2).client->isOnCurrentDesktop())
01116                         && !(*it2).region.intersect(region).isEmpty())
01117                     reshadowClients.append((*it2).client);
01118             }
01119         }
01120         ++it;
01121     }
01122 
01123     // Redraw shadows for each of the Clients in the list generated above
01124     for (it3 = reshadowClients.begin(); it3 != reshadowClients.end(); ++it3) {
01125         (*it3)->removeShadow();
01126         if (it3 == reshadowClients.begin()) {
01127             if (waitForMe)
01128                 (*it3)->drawShadowAfter(this);
01129             else
01130                 (*it3)->drawDelayedShadow();
01131         }
01132         else {
01133             --it3;
01134             aClient = (*it3);
01135             ++it3;
01136             (*it3)->drawShadowAfter(aClient);
01137         }
01138     }
01139 }
01140 
01145 void Client::drawDelayedShadow()
01146 {
01147     shadowDelayTimer->stop();
01148     shadowDelayTimer->start(SHADOW_DELAY, true);
01149 }
01150 
01154 void Client::drawShadowAfter(Client *after)
01155 {
01156     shadowAfterClient = after;
01157     connect(after, TQT_SIGNAL(shadowDrawn()), TQT_SLOT(drawShadow()));
01158 }
01159 
01163 void Client::drawShadow()
01164 {
01165     Window shadows[2];
01166     XRectangle *shapes;
01167     int i, count, ordering;
01168 
01169     // If we are waiting for another Client's shadow to be drawn, stop waiting now
01170     if (shadowAfterClient != NULL) {
01171         disconnect(shadowAfterClient, TQT_SIGNAL(shadowDrawn()), this, TQT_SLOT(drawShadow()));
01172         shadowAfterClient = NULL;
01173     }
01174 
01175     if (!isOnCurrentDesktop())
01176         return;
01177 
01178     /* Store this window's ShapeBoundingRegion even if shadows aren't drawn for
01179      * this type of window. Otherwise, drawIntersectingShadows() won't update
01180      * properly when this window is moved/resized/hidden/closed.
01181      */
01182     shapes = XShapeGetRectangles(qt_xdisplay(), frameId(), ShapeBounding,
01183             &count, &ordering);
01184     if (!shapes)
01185         // XShape extension not supported
01186         shapeBoundingRegion = TQRegion(x(), y(), width(), height());
01187     else {
01188         shapeBoundingRegion = TQRegion();
01189         for (i = 0; i < count; i++) {
01190             // Translate XShaped window into a TQRegion
01191             TQRegion shapeRectangle(shapes[i].x, shapes[i].y, shapes[i].width,
01192                     shapes[i].height);
01193             shapeBoundingRegion += shapeRectangle;
01194         }
01195         if (isShade())
01196             // Since XResize() doesn't change a window's XShape regions, ensure that
01197             // shapeBoundingRegion is not taller than the window's shaded height,
01198             // or the bottom shadow will appear to be missing
01199             shapeBoundingRegion &= TQRegion(0, 0, width(), height());
01200         shapeBoundingRegion.translate(x(), y());
01201     }
01202 
01203     if (!isShadowed() || hidden || isMinimized() ||
01204             maximizeMode() == MaximizeFull ||
01205             !options->shadowWindowType(windowType())) {
01206         XFree(shapes);
01207 
01208         // Tell whatever Clients are listening that this Client's shadow has been drawn.
01209         // It hasn't, but there's no sense waiting for something that won't happen.
01210         emit shadowDrawn();
01211 
01212         return;
01213     }
01214 
01215     removeShadow();
01216 
01217     TQMemArray<QRgb> pixelData;
01218     TQPixmap shadowPixmap;
01219     TQRect shadow;
01220     TQRegion exposedRegion;
01221     ShadowRegion shadowRegion;
01222     int thickness, xOffset, yOffset;
01223 
01224     thickness = options->shadowThickness(isActive());
01225     xOffset = options->shadowXOffset(isActive());
01226     yOffset = options->shadowYOffset(isActive());
01227     opacityCache = active? &activeOpacityCache : &inactiveOpacityCache;
01228 
01229     shadow.setRect(x() - thickness + xOffset, y() - thickness + yOffset,
01230             width() + thickness * 2, height() + thickness * 2);
01231     shadowPixmap.resize(shadow.size());
01232 
01233     // Create a fake drop-down shadow effect via blended Xwindows
01234     shadowWidget = new TQWidget(0, 0, WStyle_Customize | WX11BypassWM);
01235     shadowWidget->setGeometry(shadow);
01236     XSelectInput(qt_xdisplay(), shadowWidget->winId(),
01237             ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
01238     shadowWidget->installEventFilter(this);
01239 
01240     if (!shapes) {
01241         // XShape extension not supported
01242         exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
01243                 shadow.y(), shadow.width(), shadow.height(), thickness,
01244                 xOffset, yOffset);
01245         shadowRegion.region = exposedRegion;
01246         shadowRegion.client = this;
01247         shadowRegions.append(shadowRegion);
01248 
01249         if (opacityCache->isNull())
01250             imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
01251                     exposedRegion, thickness,
01252                     options->shadowOpacity(isActive()));
01253         else
01254             imposeCachedShadow(shadowPixmap, exposedRegion);
01255     }
01256     else {
01257         TQMemArray<TQRect> exposedRects;
01258         TQMemArray<TQRect>::Iterator it, itEnd;
01259         XRectangle *shadowShapes;
01260 
01261         exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
01262                 shadow.y(), shadow.width(), shadow.height(), thickness,
01263                 xOffset, yOffset);
01264         shadowRegion.region = exposedRegion;
01265         shadowRegion.client = this;
01266         shadowRegions.append(shadowRegion);
01267 
01268         // XShape the shadow
01269         exposedRects = exposedRegion.rects();
01270         i = 0;
01271         itEnd = exposedRects.end();
01272         shadowShapes = new XRectangle[exposedRects.count()];
01273         for (it = exposedRects.begin(); it != itEnd; ++it) {
01274             shadowShapes[i].x = (*it).x();
01275             shadowShapes[i].y = (*it).y();
01276             shadowShapes[i].width = (*it).width();
01277             shadowShapes[i].height = (*it).height();
01278             i++;
01279         }
01280         XShapeCombineRectangles(qt_xdisplay(), shadowWidget->winId(),
01281                 ShapeBounding, -x() + thickness - xOffset,
01282                 -y() + thickness - yOffset, shadowShapes, i, ShapeSet,
01283                 Unsorted);
01284         delete [] shadowShapes;
01285 
01286         if (opacityCache->isNull())
01287             imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
01288                     exposedRegion, thickness,
01289                     options->shadowOpacity(isActive()));
01290         else
01291             imposeCachedShadow(shadowPixmap, exposedRegion);
01292     }
01293 
01294     XFree(shapes);
01295 
01296     // Set the background pixmap
01297     //shadowPixmap.convertFromImage(shadowImage);
01298     shadowWidget->setErasePixmap(shadowPixmap);
01299 
01300     // Restack shadows under this window so that shadows drawn for a newly
01301     // focused (but not raised) window don't overlap any windows above it.
01302     if (isDock()) {
01303         ClientList stacking_order = workspace()->stackingOrder();
01304         for (ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
01305             if ((*it)->isDesktop())
01306                 {
01307                 ++it;
01308                 shadows[0] = (*it)->frameId();
01309                 shadows[1] = shadowWidget->winId();
01310                 }
01311     }
01312     else {
01313         shadows[0] = frameId();
01314         if (shadowWidget != NULL)
01315             shadows[1] = shadowWidget->winId();
01316     }
01317 
01318     XRestackWindows(qt_xdisplay(), shadows, 2);
01319 
01320     // Don't use TQWidget::show() so we don't confuse QEffects, thus causing
01321     // broken focus.
01322     XMapWindow(qt_xdisplay(), shadowWidget->winId());
01323 
01324     // Tell whatever Clients are listening that this Client's shadow has been drawn.
01325     emit shadowDrawn();
01326 }
01327 
01331 void Client::removeShadow()
01332 {
01333     TQValueList<ShadowRegion>::Iterator it;
01334 
01335     shadowDelayTimer->stop();
01336 
01337     if (shadowWidget != NULL) {
01338         for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
01339             if ((*it).client == this) {
01340                 shadowRegions.remove(it);
01341                 break;
01342             }
01343         delete shadowWidget;
01344         shadowWidget = NULL;
01345     }
01346 }
01347 
01352 TQRegion Client::getExposedRegion(TQRegion occludedRegion, int x, int y, int w,
01353         int h, int thickness, int xOffset, int yOffset)
01354 {
01355     TQRegion exposedRegion;
01356 
01357     exposedRegion = TQRegion(x, y, w, h);
01358     exposedRegion -= occludedRegion;
01359 
01360     if (thickness > 0) {
01361         // Limit exposedRegion to include only where a shadow of the specified
01362         // thickness will be drawn
01363         TQMemArray<TQRect> occludedRects;
01364         TQMemArray<TQRect>::Iterator it, itEnd;
01365         TQRegion shadowRegion;
01366 
01367         occludedRects = occludedRegion.rects();
01368         itEnd = occludedRects.end();
01369         for (it = occludedRects.begin(); it != itEnd; ++it) {
01370             // Expand each of the occluded region's shape rectangles to contain
01371             // where a shadow of the specified thickness will be drawn. Create
01372             // a new TQRegion that contains the expanded occluded region
01373             it->setTop(it->top() - thickness + yOffset);
01374             it->setLeft(it->left() - thickness + xOffset);
01375             it->setRight(it->right() + thickness + xOffset);
01376             it->setBottom(it->bottom() + thickness + yOffset);
01377             shadowRegion += TQRegion(*it);
01378         }
01379         exposedRegion -= exposedRegion - shadowRegion;
01380     }
01381 
01382     return exposedRegion;
01383 }
01384 
01388 void Client::imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed)
01389 {
01390     QRgb pixel;
01391     double opacity;
01392     int red, green, blue, pixelRed, pixelGreen, pixelBlue;
01393     int subW, subH, w, h, x, y, zeroX, zeroY;
01394     TQImage image;
01395     TQMemArray<TQRect>::Iterator it, itEnd;
01396     TQMemArray<TQRect> rectangles;
01397     TQPixmap subPixmap;
01398     Window rootWindow;
01399     int thickness, windowX, windowY, xOffset, yOffset;
01400 
01401     rectangles = exposed.rects();
01402     rootWindow = qt_xrootwin();
01403     thickness = options->shadowThickness(isActive());
01404     windowX = this->x();
01405     windowY = this->y();
01406     xOffset = options->shadowXOffset(isActive());
01407     yOffset = options->shadowYOffset(isActive());
01408     options->shadowColour(isActive()).rgb(&red, &green, &blue);
01409     w = pixmap.width();
01410     h = pixmap.height();
01411 
01412     itEnd = rectangles.end();
01413     for (it = rectangles.begin(); it != itEnd; ++it) {
01414         subW = (*it).width();
01415         subH = (*it).height();
01416         subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
01417                 subW, subH);
01418         zeroX = (*it).x() - windowX + thickness - xOffset;
01419         zeroY = (*it).y() - windowY + thickness - yOffset;
01420         image = subPixmap.convertToImage();
01421 
01422         for (x = 0; x < subW; x++) {
01423             for (y = 0; y < subH; y++) {
01424                 opacity = (*(opacityCache))[(zeroY + y) * w + zeroX + x];
01425                 pixel = image.pixel(x, y);
01426                 pixelRed = qRed(pixel);
01427                 pixelGreen = qGreen(pixel);
01428                 pixelBlue = qBlue(pixel);
01429                 image.setPixel(x, y,
01430                         qRgb((int)(pixelRed + (red - pixelRed) * opacity),
01431                             (int)(pixelGreen + (green - pixelGreen) * opacity),
01432                             (int)(pixelBlue + (blue - pixelBlue) * opacity)));
01433             }
01434         }
01435 
01436         subPixmap.convertFromImage(image);
01437         bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
01438     }
01439 }
01440 
01444 void Client::imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded,
01445         TQRegion exposed, int thickness, double maxOpacity)
01446 {
01447     register int distance, intersectCount, i, j, x, y;
01448     QRgb pixel;
01449     double decay, factor, opacity;
01450     int red, green, blue, pixelRed, pixelGreen, pixelBlue;
01451     int halfMaxIntersects, lineIntersects, maxIntersects, maxY;
01452     int irBottom, irLeft, irRight, irTop, yIncrement;
01453     int subW, subH, w, h, zeroX, zeroY;
01454     TQImage image;
01455     TQMemArray<TQRect>::Iterator it, itEnd;
01456     TQMemArray<TQRect> rectangles;
01457     TQPixmap subPixmap;
01458     Window rootWindow;
01459     int windowX, windowY, xOffset, yOffset;
01460 
01461     rectangles = exposed.rects();
01462     rootWindow = qt_xrootwin();
01463     windowX = this->x();
01464     windowY = this->y();
01465     xOffset = options->shadowXOffset(isActive());
01466     yOffset = options->shadowYOffset(isActive());
01467     options->shadowColour(isActive()).rgb(&red, &green, &blue);
01468     maxIntersects = thickness * thickness * 4 + (thickness * 4) + 1;
01469     halfMaxIntersects = maxIntersects / 2;
01470     lineIntersects = thickness * 2 + 1;
01471     factor = maxIntersects / maxOpacity;
01472     decay = (lineIntersects / 0.0125 - factor) / pow((double)maxIntersects, 3.0);
01473     w = pixmap.width();
01474     h = pixmap.height();
01475     xOffset = options->shadowXOffset(isActive());
01476     yOffset = options->shadowYOffset(isActive());
01477 
01478     opacityCache->resize(0);
01479     opacityCache->resize(w * h);
01480     occluded.translate(-windowX + thickness, -windowY + thickness);
01481 
01482     itEnd = rectangles.end();
01483     for (it = rectangles.begin(); it != itEnd; ++it) {
01484         subW = (*it).width();
01485         subH = (*it).height();
01486         subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
01487                 subW, subH);
01488         maxY = subH;
01489         zeroX = (*it).x() - windowX + thickness - xOffset;
01490         zeroY = (*it).y() - windowY + thickness - yOffset;
01491         image = subPixmap.convertToImage();
01492 
01493         intersectCount = 0;
01494         opacity = -1;
01495         y = 0;
01496         yIncrement = 1;
01497         for (x = 0; x < subW; x++) {
01498             irLeft = zeroX + x - thickness;
01499             irRight = zeroX + x + thickness;
01500 
01501             while (y != maxY) {
01502                 // horizontal row about to leave the intersect region, not
01503                 // necessarily the top row
01504                 irTop = zeroY + y - thickness * yIncrement;
01505                 // horizontal row that just came into the intersect region,
01506                 // not necessarily the bottom row
01507                 irBottom = zeroY + y + thickness * yIncrement;
01508 
01509                 if (opacity == -1) {
01510                     // If occluded pixels caused an intersect count to be
01511                     // skipped, recount it
01512                     intersectCount = 0;
01513 
01514                     for (j = irTop; j != irBottom; j += yIncrement) {
01515                         // irTop is not necessarily larger than irBottom and
01516                         // yIncrement isn't necessarily positive
01517                         for (i = irLeft; i <= irRight; i++) {
01518                             if (occluded.contains(TQPoint(i, j)))
01519                                 intersectCount++;
01520                         }
01521                     }
01522                 }
01523                 else {
01524                     if (intersectCount < 0)
01525                         intersectCount = 0;
01526 
01527                     for (i = irLeft; i <= irRight; i++) {
01528                         if (occluded.contains(TQPoint(i, irBottom)))
01529                             intersectCount++;
01530                     }
01531                 }
01532 
01533                 distance = maxIntersects - intersectCount;
01534                 opacity = intersectCount / (factor + pow((double)distance, 3.0) * decay);
01535 
01536                 (*(opacityCache))[(zeroY + y) * w + zeroX + x] = opacity;
01537                 pixel = image.pixel(x, y);
01538                 pixelRed = qRed(pixel);
01539                 pixelGreen = qGreen(pixel);
01540                 pixelBlue = qBlue(pixel);
01541                 image.setPixel(x, y,
01542                         qRgb((int)(pixelRed + (red - pixelRed) * opacity),
01543                             (int)(pixelGreen + (green - pixelGreen) * opacity),
01544                             (int)(pixelBlue + (blue - pixelBlue) * opacity)));
01545 
01546                 for (i = irLeft; i <= irRight; i++) {
01547                     if (occluded.contains(TQPoint(i, irTop)))
01548                         intersectCount--;
01549                 }
01550 
01551                 y += yIncrement;
01552             }
01553             y -= yIncrement;
01554 
01555             irTop += yIncrement;
01556             for (j = irTop; j != irBottom; j += yIncrement) {
01557                 if (occluded.contains(TQPoint(irLeft, j)))
01558                     intersectCount--;
01559             }
01560             irRight++;
01561             for (j = irTop; j != irBottom; j += yIncrement) {
01562                 if (occluded.contains(TQPoint(irRight, j)))
01563                     intersectCount++;
01564             }
01565 
01566             yIncrement *= -1;
01567             if (yIncrement < 0)
01568                 // Scan Y-axis bottom-up for next X-coordinate iteration
01569                 maxY = -1;
01570             else
01571                 // Scan Y-axis top-down for next X-coordinate iteration
01572                 maxY = subH;
01573         }
01574 
01575         subPixmap.convertFromImage(image);
01576         bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
01577     }
01578 }
01579 
01584 void Client::setMappingState(int s)
01585     {
01586     assert( client != None );
01587     assert( !deleting || s == WithdrawnState );
01588     if( mapping_state == s )
01589         return;
01590     bool was_unmanaged = ( mapping_state == WithdrawnState );
01591     mapping_state = s;
01592     if( mapping_state == WithdrawnState )
01593         {
01594         XDeleteProperty( qt_xdisplay(), window(), qt_wm_state );
01595         return;
01596         }
01597     assert( s == NormalState || s == IconicState );
01598 
01599     unsigned long data[2];
01600     data[0] = (unsigned long) s;
01601     data[1] = (unsigned long) None;
01602     XChangeProperty(qt_xdisplay(), window(), qt_wm_state, qt_wm_state, 32,
01603         PropModeReplace, (unsigned char *)data, 2);
01604 
01605     if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
01606         postponeGeometryUpdates( false );
01607     }
01608 
01613 void Client::rawShow()
01614     {
01615     if( decoration != NULL )
01616         decoration->widget()->show(); // not really necessary, but let it know the state
01617     XMapWindow( qt_xdisplay(), frame );
01618     if( !isShade())
01619         {
01620         XMapWindow( qt_xdisplay(), wrapper );
01621         XMapWindow( qt_xdisplay(), client );
01622         }
01623     if (options->shadowEnabled(isActive()))
01624         drawDelayedShadow();
01625     }
01626 
01632 void Client::rawHide()
01633     {
01634 // Here it may look like a race condition, as some other client might try to unmap
01635 // the window between these two XSelectInput() calls. However, they're supposed to
01636 // use XWithdrawWindow(), which also sends a synthetic event to the root window,
01637 // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
01638 // will be missed is also very minimal, so I don't think it's needed to grab the server
01639 // here.
01640     removeShadow();
01641     drawIntersectingShadows();
01642     XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
01643     XUnmapWindow( qt_xdisplay(), frame );
01644     XUnmapWindow( qt_xdisplay(), wrapper );
01645     XUnmapWindow( qt_xdisplay(), client );
01646     XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
01647     if( decoration != NULL )
01648         decoration->widget()->hide(); // not really necessary, but let it know the state
01649     workspace()->clientHidden( this );
01650     }
01651 
01652 void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
01653     {
01654     XEvent ev;
01655     long mask;
01656 
01657     memset(&ev, 0, sizeof(ev));
01658     ev.xclient.type = ClientMessage;
01659     ev.xclient.window = w;
01660     ev.xclient.message_type = a;
01661     ev.xclient.format = 32;
01662     ev.xclient.data.l[0] = protocol;
01663     ev.xclient.data.l[1] = qt_x_time;
01664     ev.xclient.data.l[2] = data1;
01665     ev.xclient.data.l[3] = data2;
01666     ev.xclient.data.l[4] = data3;
01667     mask = 0L;
01668     if (w == qt_xrootwin())
01669       mask = SubstructureRedirectMask;        /* magic! */
01670     XSendEvent(qt_xdisplay(), w, False, mask, &ev);
01671     }
01672 
01673 /*
01674   Returns whether the window may be closed (have a close button)
01675  */
01676 bool Client::isCloseable() const
01677     {
01678     return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
01679     }
01680 
01685 void Client::closeWindow()
01686     {
01687     if( !isCloseable())
01688         return;
01689     // Update user time, because the window may create a confirming dialog.
01690     updateUserTime(); 
01691     if ( Pdeletewindow )
01692         {
01693         Notify::raise( Notify::Close );
01694         sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
01695         pingWindow();
01696         }
01697     else 
01698         {
01699         // client will not react on wm_delete_window. We have not choice
01700         // but destroy his connection to the XServer.
01701         killWindow();
01702         }
01703     }
01704 
01705 
01709 void Client::killWindow()
01710     {
01711     kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
01712     // not sure if we need an Notify::Kill or not.. until then, use
01713     // Notify::Close
01714     Notify::raise( Notify::Close );
01715 
01716     if( isDialog())
01717         Notify::raise( Notify::TransDelete );
01718     if( isNormalWindow())
01719         Notify::raise( Notify::Delete );
01720     killProcess( false );
01721     // always kill this client at the server
01722     XKillClient(qt_xdisplay(), window() );
01723     destroyClient();
01724     }
01725 
01726 // send a ping to the window using _NET_WM_PING if possible
01727 // if it doesn't respond within a reasonable time, it will be
01728 // killed
01729 void Client::pingWindow()
01730     {
01731     if( !Pping )
01732         return; // can't ping :(
01733     if( options->killPingTimeout == 0 )
01734         return; // turned off
01735     if( ping_timer != NULL )
01736         return; // pinging already
01737     ping_timer = new TQTimer( this );
01738     connect( ping_timer, TQT_SIGNAL( timeout()), TQT_SLOT( pingTimeout()));
01739     ping_timer->start( options->killPingTimeout, true );
01740     ping_timestamp = qt_x_time;
01741     workspace()->sendPingToWindow( window(), ping_timestamp );
01742     }
01743 
01744 void Client::gotPing( Time timestamp )
01745     {
01746     // just plain compare is not good enough because of 64bit and truncating and whatnot
01747     if( NET::timestampCompare( timestamp, ping_timestamp ) != 0 )
01748         return;
01749     delete ping_timer;
01750     ping_timer = NULL;
01751     if( process_killer != NULL )
01752         {
01753         process_killer->kill();
01754         delete process_killer;
01755         process_killer = NULL;
01756         }
01757     }
01758 
01759 void Client::pingTimeout()
01760     {
01761     kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
01762     delete ping_timer;
01763     ping_timer = NULL;
01764     killProcess( true, ping_timestamp );
01765     }
01766 
01767 void Client::killProcess( bool ask, Time timestamp )
01768     {
01769     if( process_killer != NULL )
01770         return;
01771     Q_ASSERT( !ask || timestamp != CurrentTime );
01772     TQCString machine = wmClientMachine( true );
01773     pid_t pid = info->pid();
01774     if( pid <= 0 || machine.isEmpty()) // needed properties missing
01775         return;
01776     kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
01777     if( !ask )
01778         {
01779         if( machine != "localhost" )
01780             {
01781             KProcess proc;
01782             proc << "xon" << machine << "kill" << pid;
01783             proc.start( KProcess::DontCare );
01784             }
01785         else
01786             ::kill( pid, SIGTERM );
01787         }
01788     else
01789         { // SELI TODO handle the window created by handler specially (on top,urgent?)
01790         process_killer = new KProcess( this );
01791         *process_killer << KStandardDirs::findExe( "kwin_killer_helper" )
01792             << "--pid" << TQCString().setNum( pid ) << "--hostname" << machine
01793             << "--windowname" << caption().utf8()
01794             << "--applicationname" << resourceClass()
01795             << "--wid" << TQCString().setNum( window())
01796             << "--timestamp" << TQCString().setNum( timestamp );
01797         connect( process_killer, TQT_SIGNAL( processExited( KProcess* )),
01798             TQT_SLOT( processKillerExited()));
01799         if( !process_killer->start( KProcess::NotifyOnExit ))
01800             {
01801             delete process_killer;
01802             process_killer = NULL;
01803             return;
01804             }
01805         }
01806     }
01807 
01808 void Client::processKillerExited()
01809     {
01810     kdDebug( 1212 ) << "Killer exited" << endl;
01811     delete process_killer;
01812     process_killer = NULL;
01813     }
01814 
01815 void Client::setSkipTaskbar( bool b, bool from_outside )
01816     {
01817     int was_wants_tab_focus = wantsTabFocus();
01818     if( from_outside )
01819         {
01820         b = rules()->checkSkipTaskbar( b );
01821         original_skip_taskbar = b;
01822         }
01823     if ( b == skipTaskbar() )
01824         return;
01825     skip_taskbar = b;
01826     info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
01827     updateWindowRules();
01828     if( was_wants_tab_focus != wantsTabFocus())
01829         workspace()->updateFocusChains( this,
01830             isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
01831     }
01832 
01833 void Client::setSkipPager( bool b )
01834     {
01835     b = rules()->checkSkipPager( b );
01836     if ( b == skipPager() )
01837         return;
01838     skip_pager = b;
01839     info->setState( b?NET::SkipPager:0, NET::SkipPager );
01840     updateWindowRules();
01841     }
01842 
01843 void Client::setModal( bool m )
01844     { // Qt-3.2 can have even modal normal windows :(
01845     if( modal == m )
01846         return;
01847     modal = m;
01848     if( !modal )
01849         return;
01850     // changing modality for a mapped window is weird (?)
01851     // _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
01852     }
01853 
01854 void Client::setDesktop( int desktop )
01855     {
01856     if( desktop != NET::OnAllDesktops ) // do range check
01857         desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
01858     desktop = rules()->checkDesktop( desktop );
01859     if( desk == desktop )
01860         return;
01861     int was_desk = desk;
01862     desk = desktop;
01863     info->setDesktop( desktop );
01864     if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
01865         { // onAllDesktops changed
01866         if ( isShown( true ))
01867             Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
01868         workspace()->updateOnAllDesktopsOfTransients( this );
01869         }
01870     if( decoration != NULL )
01871         decoration->desktopChange();
01872     workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
01873     updateVisibility();
01874     updateWindowRules();
01875     }
01876 
01877 void Client::setOnAllDesktops( bool b )
01878     {
01879     if(( b && isOnAllDesktops())
01880         || ( !b && !isOnAllDesktops()))
01881         return;
01882     if( b )
01883         setDesktop( NET::OnAllDesktops );
01884     else
01885         setDesktop( workspace()->currentDesktop());
01886     }
01887 
01888 bool Client::isOnCurrentDesktop() const
01889     {
01890     return isOnDesktop( workspace()->currentDesktop());
01891     }
01892 
01893 int Client::screen() const
01894     {
01895     if( !options->xineramaEnabled )
01896         return 0;
01897     return workspace()->screenNumber( geometry().center());
01898     }
01899 
01900 bool Client::isOnScreen( int screen ) const
01901     {
01902     if( !options->xineramaEnabled )
01903         return screen == 0;
01904     return workspace()->screenGeometry( screen ).intersects( geometry());
01905     }
01906 
01907 // performs activation and/or raising of the window
01908 void Client::takeActivity( int flags, bool handled, allowed_t )
01909     {
01910     if( !handled || !Ptakeactivity )
01911         {
01912         if( flags & ActivityFocus )
01913             takeFocus( Allowed );
01914         if( flags & ActivityRaise )
01915             workspace()->raiseClient( this );
01916         return;
01917         }
01918 
01919 #ifndef NDEBUG
01920     static Time previous_activity_timestamp;
01921     static Client* previous_client;
01922     if( previous_activity_timestamp == qt_x_time && previous_client != this )
01923         {
01924         kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
01925         kdDebug( 1212 ) << kdBacktrace() << endl;
01926         }
01927     previous_activity_timestamp = qt_x_time;
01928     previous_client = this;
01929 #endif
01930     workspace()->sendTakeActivity( this, qt_x_time, flags );
01931     }
01932 
01933 // performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
01934 void Client::takeFocus( allowed_t )
01935     {
01936 #ifndef NDEBUG
01937     static Time previous_focus_timestamp;
01938     static Client* previous_client;
01939     if( previous_focus_timestamp == qt_x_time && previous_client != this )
01940         {
01941         kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
01942         kdDebug( 1212 ) << kdBacktrace() << endl;
01943         }
01944     previous_focus_timestamp = qt_x_time;
01945     previous_client = this;
01946 #endif
01947     if ( rules()->checkAcceptFocus( input ))
01948         {
01949         XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, qt_x_time );
01950         }
01951     if ( Ptakefocus )
01952         sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
01953     workspace()->setShouldGetFocus( this );
01954     }
01955 
01963 bool Client::providesContextHelp() const
01964     {
01965     return Pcontexthelp;
01966     }
01967 
01968 
01975 void Client::showContextHelp()
01976     {
01977     if ( Pcontexthelp ) 
01978         {
01979         sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
01980         TQWhatsThis::enterWhatsThisMode(); // SELI?
01981         }
01982     }
01983 
01984 
01989 void Client::fetchName()
01990     {
01991     setCaption( readName());
01992     }
01993 
01994 TQString Client::readName() const
01995     {
01996     if ( info->name() && info->name()[ 0 ] != '\0' ) 
01997         return TQString::fromUtf8( info->name() );
01998     else 
01999         return KWin::readNameProperty( window(), XA_WM_NAME );
02000     }
02001     
02002 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
02003 
02004 void Client::setCaption( const TQString& s, bool force )
02005     {
02006     if ( s != cap_normal || force ) 
02007         {
02008         bool reset_name = force;
02009         for( unsigned int i = 0;
02010              i < s.length();
02011              ++i )
02012             if( !s[ i ].isPrint())
02013                 s[ i ] = ' ';
02014         cap_normal = s;
02015         bool was_suffix = ( !cap_suffix.isEmpty());
02016         TQString machine_suffix;
02017         if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
02018             machine_suffix = " <@" + wmClientMachine( true ) + ">";
02019         TQString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
02020         cap_suffix = machine_suffix + shortcut_suffix;
02021         if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this ))) 
02022             {
02023             int i = 2;
02024             do 
02025                 {
02026                 cap_suffix = machine_suffix + " <" + TQString::number(i) + ">" + shortcut_suffix;
02027                 i++;
02028                 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
02029             info->setVisibleName( caption().utf8() );
02030             reset_name = false;
02031             }
02032         if(( was_suffix && cap_suffix.isEmpty()
02033             || reset_name )) // if it was new window, it may have old value still set, if the window is reused
02034             {
02035             info->setVisibleName( "" ); // remove
02036             info->setVisibleIconName( "" ); // remove
02037             }
02038         else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
02039             info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
02040 
02041         if( isManaged() && decoration != NULL )
02042                 decoration->captionChange();
02043         }
02044     }
02045 
02046 void Client::updateCaption()
02047     {
02048     setCaption( cap_normal, true );
02049     }
02050 
02051 void Client::fetchIconicName()
02052     {
02053     TQString s;
02054     if ( info->iconName() && info->iconName()[ 0 ] != '\0' ) 
02055         s = TQString::fromUtf8( info->iconName() );
02056     else 
02057         s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
02058     if ( s != cap_iconic ) 
02059         {
02060     bool was_set = !cap_iconic.isEmpty();
02061         cap_iconic = s;
02062         if( !cap_suffix.isEmpty())
02063         {
02064         if( !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
02065             info->setVisibleIconName( ( s + cap_suffix ).utf8() );
02066         else if( was_set )
02067         info->setVisibleIconName( "" ); //remove
02068         }
02069         }
02070     }
02071 
02074 TQString Client::caption( bool full ) const
02075     {
02076     return full ? cap_normal + cap_suffix : cap_normal;
02077     }
02078 
02079 void Client::getWMHints()
02080     {
02081     XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
02082     input = true;
02083     window_group = None;
02084     urgency = false;
02085     if ( hints )
02086         {
02087         if( hints->flags & InputHint )
02088             input = hints->input;
02089         if( hints->flags & WindowGroupHint )
02090             window_group = hints->window_group;
02091         urgency = ( hints->flags & UrgencyHint ) ? true : false; // true/false needed, it's uint bitfield
02092         XFree( (char*)hints );
02093         }
02094     checkGroup();
02095     updateUrgency();
02096     updateAllowedActions(); // group affects isMinimizable()
02097     }
02098 
02099 void Client::getMotifHints()
02100     {
02101     bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
02102     Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
02103     motif_noborder = mnoborder;
02104     if( !hasNETSupport()) // NETWM apps should set type and size constraints
02105         {
02106         motif_may_resize = mresize; // this should be set using minsize==maxsize, but oh well
02107         motif_may_move = mmove;
02108         }
02109     else
02110         motif_may_resize = motif_may_move = true;
02111     // mminimize; - ignore, bogus - e.g. shading or sending to another desktop is "minimizing" too
02112     // mmaximize; - ignore, bogus - maximizing is basically just resizing
02113     motif_may_close = mclose; // motif apps like to crash when they set this hint and WM closes them anyway
02114     if( isManaged())
02115         updateDecoration( true ); // check if noborder state has changed
02116     }
02117 
02118 void Client::readIcons( Window win, TQPixmap* icon, TQPixmap* miniicon )
02119     {    
02120     // get the icons, allow scaling
02121     if( icon != NULL )
02122         *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
02123     if( miniicon != NULL )
02124         if( icon == NULL || !icon->isNull())
02125             *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
02126         else
02127             *miniicon = TQPixmap();
02128     }
02129 
02130 void Client::getIcons()
02131     {
02132     // first read icons from the window itself
02133     readIcons( window(), &icon_pix, &miniicon_pix );
02134     if( icon_pix.isNull())
02135         { // then try window group
02136         icon_pix = group()->icon();
02137         miniicon_pix = group()->miniIcon();
02138         }
02139     if( icon_pix.isNull() && isTransient())
02140         { // then mainclients
02141         ClientList mainclients = mainClients();
02142         for( ClientList::ConstIterator it = mainclients.begin();
02143              it != mainclients.end() && icon_pix.isNull();
02144              ++it )
02145             {
02146             icon_pix = (*it)->icon();
02147             miniicon_pix = (*it)->miniIcon();
02148             }
02149         }
02150     if( icon_pix.isNull())
02151         { // and if nothing else, load icon from classhint or xapp icon
02152         icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
02153         miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
02154         }
02155     if( isManaged() && decoration != NULL )
02156         decoration->iconChange();
02157     }
02158 
02159 void Client::getWindowProtocols()
02160     {
02161     Atom *p;
02162     int i,n;
02163 
02164     Pdeletewindow = 0;
02165     Ptakefocus = 0;
02166     Ptakeactivity = 0;
02167     Pcontexthelp = 0;
02168     Pping = 0;
02169 
02170     if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
02171         {
02172         for (i = 0; i < n; i++)
02173             if (p[i] == atoms->wm_delete_window)
02174                 Pdeletewindow = 1;
02175             else if (p[i] == atoms->wm_take_focus)
02176                 Ptakefocus = 1;
02177             else if (p[i] == atoms->net_wm_take_activity)
02178                 Ptakeactivity = 1;
02179             else if (p[i] == atoms->net_wm_context_help)
02180                 Pcontexthelp = 1;
02181             else if (p[i] == atoms->net_wm_ping)
02182                 Pping = 1;
02183         if (n>0)
02184             XFree(p);
02185         }
02186     }
02187 
02188 static int nullErrorHandler(Display *, XErrorEvent *)
02189     {
02190     return 0;
02191     }
02192 
02196 TQCString Client::staticWindowRole(WId w)
02197     {
02198     return getStringProperty(w, qt_window_role).lower();
02199     }
02200 
02204 TQCString Client::staticSessionId(WId w)
02205     {
02206     return getStringProperty(w, qt_sm_client_id);
02207     }
02208 
02212 TQCString Client::staticWmCommand(WId w)
02213     {
02214     return getStringProperty(w, XA_WM_COMMAND, ' ');
02215     }
02216 
02220 Window Client::staticWmClientLeader(WId w)
02221     {
02222     Atom type;
02223     int format, status;
02224     unsigned long nitems = 0;
02225     unsigned long extra = 0;
02226     unsigned char *data = 0;
02227     Window result = w;
02228     XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
02229     status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
02230                                  FALSE, XA_WINDOW, &type, &format,
02231                                  &nitems, &extra, &data );
02232     XSetErrorHandler(oldHandler);
02233     if (status  == Success ) 
02234         {
02235         if (data && nitems > 0)
02236             result = *((Window*) data);
02237         XFree(data);
02238         }
02239     return result;
02240     }
02241 
02242 
02243 void Client::getWmClientLeader()
02244     {
02245     wmClientLeaderWin = staticWmClientLeader(window());
02246     }
02247 
02252 TQCString Client::sessionId()
02253     {
02254     TQCString result = staticSessionId(window());
02255     if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
02256         result = staticSessionId(wmClientLeaderWin);
02257     return result;
02258     }
02259 
02264 TQCString Client::wmCommand()
02265     {
02266     TQCString result = staticWmCommand(window());
02267     if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
02268         result = staticWmCommand(wmClientLeaderWin);
02269     return result;
02270     }
02271 
02272 void Client::getWmClientMachine()
02273     {
02274     client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
02275     if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
02276         client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
02277     if( client_machine.isEmpty())
02278         client_machine = "localhost";
02279     }
02280 
02285 TQCString Client::wmClientMachine( bool use_localhost ) const
02286     {
02287     TQCString result = client_machine;
02288     if( use_localhost )
02289         { // special name for the local machine (localhost)
02290         if( result != "localhost" && isLocalMachine( result ))
02291             result = "localhost";
02292         }
02293     return result;
02294     }
02295 
02300 Window Client::wmClientLeader() const
02301     {
02302     if (wmClientLeaderWin)
02303         return wmClientLeaderWin;
02304     return window();
02305     }
02306 
02307 bool Client::wantsTabFocus() const
02308     {
02309     return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
02310     }
02311 
02312 
02313 bool Client::wantsInput() const
02314     {
02315     return rules()->checkAcceptFocus( input || Ptakefocus );
02316     }
02317 
02318 bool Client::isDesktop() const
02319     {
02320     return windowType() == NET::Desktop;
02321     }
02322 
02323 bool Client::isDock() const
02324     {
02325     return windowType() == NET::Dock;
02326     }
02327 
02328 bool Client::isTopMenu() const
02329     {
02330     return windowType() == NET::TopMenu;
02331     }
02332 
02333 
02334 bool Client::isMenu() const
02335     {
02336     return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
02337     }
02338 
02339 bool Client::isToolbar() const
02340     {
02341     return windowType() == NET::Toolbar;
02342     }
02343 
02344 bool Client::isSplash() const
02345     {
02346     return windowType() == NET::Splash;
02347     }
02348 
02349 bool Client::isUtility() const
02350     {
02351     return windowType() == NET::Utility;
02352     }
02353 
02354 bool Client::isDialog() const
02355     {
02356     return windowType() == NET::Dialog;
02357     }
02358 
02359 bool Client::isNormalWindow() const
02360     {
02361     return windowType() == NET::Normal;
02362     }
02363 
02364 bool Client::isSpecialWindow() const
02365     {
02366     return isDesktop() || isDock() || isSplash() || isTopMenu()
02367         || isToolbar(); // TODO
02368     }
02369 
02370 NET::WindowType Client::windowType( bool direct, int supported_types ) const
02371     {
02372     NET::WindowType wt = info->windowType( supported_types );
02373     if( direct )
02374         return wt;
02375     NET::WindowType wt2 = rules()->checkType( wt );
02376     if( wt != wt2 )
02377         {
02378         wt = wt2;
02379         info->setWindowType( wt ); // force hint change
02380         }
02381     // hacks here
02382     if( wt == NET::Menu )
02383         {
02384         // ugly hack to support the times when NET::Menu meant NET::TopMenu
02385         // if it's as wide as the screen, not very high and has its upper-left
02386         // corner a bit above the screen's upper-left cornet, it's a topmenu
02387         if( x() == 0 && y() < 0 && y() > -10 && height() < 100
02388             && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
02389             wt = NET::TopMenu;
02390         }
02391     // TODO change this to rule
02392     const char* const oo_prefix = "openoffice.org"; // TQCString has no startsWith()
02393     // oo_prefix is lowercase, because resourceClass() is forced to be lowercase
02394     if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
02395         wt = NET::Normal; // see bug #66065
02396     if( wt == NET::Unknown ) // this is more or less suggested in NETWM spec
02397         wt = isTransient() ? NET::Dialog : NET::Normal;
02398     return wt;
02399     }
02400 
02405 void Client::setCursor( Position m )
02406     {
02407     if( !isResizable() || isShade())
02408         {
02409         m = PositionCenter;
02410         }
02411     switch ( m ) 
02412         {
02413         case PositionTopLeft:
02414         case PositionBottomRight:
02415             setCursor( sizeFDiagCursor );
02416             break;
02417         case PositionBottomLeft:
02418         case PositionTopRight:
02419             setCursor( sizeBDiagCursor );
02420             break;
02421         case PositionTop:
02422         case PositionBottom:
02423             setCursor( sizeVerCursor );
02424             break;
02425         case PositionLeft:
02426         case PositionRight:
02427             setCursor( sizeHorCursor );
02428             break;
02429         default:
02430             if( buttonDown && isMovable())
02431                 setCursor( sizeAllCursor );
02432             else
02433                 setCursor( arrowCursor );
02434             break;
02435         }
02436     }
02437 
02438 // TODO mit nejake checkCursor(), ktere se zavola v manage() a pri vecech, kdy by se kurzor mohl zmenit?
02439 void Client::setCursor( const TQCursor& c )
02440     {
02441     if( c.handle() == cursor.handle())
02442         return;
02443     cursor = c;
02444     if( decoration != NULL )
02445         decoration->widget()->setCursor( cursor );
02446     XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
02447     }
02448 
02449 Client::Position Client::mousePosition( const TQPoint& p ) const
02450     {
02451     if( decoration != NULL )
02452         return decoration->mousePosition( p );
02453     return PositionCenter;
02454     }
02455 
02456 void Client::updateAllowedActions( bool force )
02457     {
02458     if( !isManaged() && !force )
02459         return;
02460     unsigned long old_allowed_actions = allowed_actions;
02461     allowed_actions = 0;
02462     if( isMovable())
02463         allowed_actions |= NET::ActionMove;
02464     if( isResizable())
02465         allowed_actions |= NET::ActionResize;
02466     if( isMinimizable())
02467         allowed_actions |= NET::ActionMinimize;
02468     if( isShadeable())
02469         allowed_actions |= NET::ActionShade;
02470     // sticky state not supported
02471     if( isMaximizable())
02472         allowed_actions |= NET::ActionMax;
02473     if( userCanSetFullScreen())
02474         allowed_actions |= NET::ActionFullScreen;
02475     allowed_actions |= NET::ActionChangeDesktop; // always (pagers shouldn't show Docks etc.)
02476     if( isCloseable())
02477         allowed_actions |= NET::ActionClose;
02478     if( old_allowed_actions == allowed_actions )
02479         return;
02480     // TODO this could be delayed and compressed - it's only for pagers etc. anyway
02481     info->setAllowedActions( allowed_actions );
02482     // TODO this should also tell the decoration, so that it can update the buttons
02483     }
02484 
02485 void Client::autoRaise()
02486     {
02487     workspace()->raiseClient( this );
02488     cancelAutoRaise();
02489     }
02490     
02491 void Client::cancelAutoRaise()
02492     {
02493     delete autoRaiseTimer;
02494     autoRaiseTimer = 0;
02495     }
02496 
02497 void Client::setOpacity(bool translucent, uint opacity)
02498     {
02499     if (isDesktop())
02500         return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
02501 //     qWarning("setting opacity for %d",qt_xdisplay());
02502     //rule out activated translulcency with 100% opacity
02503     if (!translucent || opacity ==  0xFFFFFFFF)
02504         {
02505         opacity_ = 0xFFFFFFFF;
02506         XDeleteProperty (qt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
02507         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
02508         }
02509     else{
02510         if(opacity == opacity_)
02511             return;
02512         opacity_ = opacity;
02513         long data = opacity; // 32bit XChangeProperty needs long
02514         XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02515         XChangeProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02516         }
02517     }
02518     
02519 void Client::setShadowSize(uint shadowSize)
02520     {
02521     // ignoring all individual settings - if we control a window, we control it's shadow
02522     // TODO somehow handle individual settings for docks (besides custom sizes)
02523     long data = shadowSize;
02524     XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02525     }
02526         
02527 void Client::updateOpacity()
02528 // extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
02529     {
02530     if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
02531         return;
02532     if (isActive())
02533         {
02534         if( ruleOpacityActive() )
02535             setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
02536         else
02537             setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
02538         if (isBMP())
02539         // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
02540             {
02541             ClientList tmpGroupMembers = group()->members();
02542             ClientList activeGroupMembers;
02543             activeGroupMembers.append(this);
02544             tmpGroupMembers.remove(this);
02545             ClientList::Iterator it = tmpGroupMembers.begin();
02546             while (it != tmpGroupMembers.end())
02547             // search for next attached and not activated client and repeat if found
02548                 {
02549                 if ((*it) != this && (*it)->isBMP())
02550                 // potential "to activate" client found
02551                     {
02552 //                     qWarning("client found");
02553                     if ((*it)->touches(this)) // first test, if the new client touches the just activated one
02554                         {
02555 //                         qWarning("found client touches me");
02556                         if( ruleOpacityActive() )
02557                             (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
02558                         else
02559                             (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
02560 //                         qWarning("activated, search restarted (1)");
02561                         (*it)->setShadowSize(options->activeWindowShadowSize);
02562                         activeGroupMembers.append(*it);
02563                         tmpGroupMembers.remove(it);
02564                         it = tmpGroupMembers.begin(); // restart, search next client
02565                         continue;
02566                         }
02567                     else
02568                         { // pot. client does not touch c, so we have to search if it touches some other activated client
02569                         bool found = false;
02570                         for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
02571                             {
02572                             if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
02573                                 {
02574 //                                 qWarning("found client touches other active client");
02575                                 if( ruleOpacityActive() )
02576                                     (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
02577                                 else
02578                                     (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
02579                                 (*it)->setShadowSize(options->activeWindowShadowSize);
02580                                 activeGroupMembers.append(*it);
02581                                 tmpGroupMembers.remove(it);
02582                                 it = tmpGroupMembers.begin(); // reset potential client search
02583                                 found = true;
02584 //                                 qWarning("activated, search restarted (2)");
02585                                 break; // skip this loop
02586                                 }
02587                             }
02588                         if (found) continue;
02589                         }
02590                     }
02591                     it++;
02592                 }
02593             }
02594         else if (isNormalWindow())
02595         // activate dependend minor windows as well
02596             {
02597             for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
02598                 if ((*it)->isDialog() || (*it)->isUtility())
02599                     if( (*it)->ruleOpacityActive() )
02600                         (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
02601                     else
02602                         (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
02603             }
02604         }
02605     else
02606         {
02607         if( ruleOpacityInactive() )
02608             setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
02609         else
02610             setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
02611                     options->inactiveWindowOpacity);
02612         // deactivate dependend minor windows as well
02613         if (isBMP())
02614         // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
02615             {
02616             ClientList tmpGroupMembers = group()->members();
02617             ClientList inactiveGroupMembers;
02618             inactiveGroupMembers.append(this);
02619             tmpGroupMembers.remove(this);
02620             ClientList::Iterator it = tmpGroupMembers.begin();
02621             while ( it != tmpGroupMembers.end() )
02622             // search for next attached and not activated client and repeat if found
02623                 {
02624                 if ((*it) != this && (*it)->isBMP())
02625                 // potential "to activate" client found
02626                     {
02627 //                     qWarning("client found");
02628                     if ((*it)->touches(this)) // first test, if the new client touches the just activated one
02629                         {
02630 //                         qWarning("found client touches me");
02631                         if( (*it)->ruleOpacityInactive() )
02632                             (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02633                         else
02634                             (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02635                         (*it)->setShadowSize(options->inactiveWindowShadowSize);
02636 //                         qWarning("deactivated, search restarted (1)");
02637                         inactiveGroupMembers.append(*it);
02638                         tmpGroupMembers.remove(it);
02639                         it = tmpGroupMembers.begin(); // restart, search next client
02640                         continue;
02641                         }
02642                     else // pot. client does not touch c, so we have to search if it touches some other activated client
02643                         {
02644                         bool found = false;
02645                         for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
02646                             {
02647                             if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
02648                                 {
02649 //                                 qWarning("found client touches other inactive client");
02650                                 if( (*it)->ruleOpacityInactive() )
02651                                     (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02652                                 else
02653                                     (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02654                                 (*it)->setShadowSize(options->inactiveWindowShadowSize);
02655 //                                 qWarning("deactivated, search restarted (2)");
02656                                 inactiveGroupMembers.append(*it);
02657                                 tmpGroupMembers.remove(it);
02658                                 it = tmpGroupMembers.begin(); // reset potential client search
02659                                 found = true;
02660                                 break; // skip this loop
02661                                 }
02662                             }
02663                             if (found) continue;
02664                         }
02665                     }
02666                     it++;
02667                 }
02668             }
02669         else if (isNormalWindow())
02670             {
02671             for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
02672                 if ((*it)->isUtility()) //don't deactivate dialogs...
02673                     if( (*it)->ruleOpacityInactive() )
02674                         (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02675                     else
02676                         (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02677             }
02678         }
02679     }
02680     
02681 void Client::updateShadowSize()
02682 // extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
02683     {
02684     if (!(isNormalWindow() || isDialog() || isUtility() ))
02685         return;
02686     if (isActive())
02687         setShadowSize(options->activeWindowShadowSize);
02688     else
02689         setShadowSize(options->inactiveWindowShadowSize);
02690     }
02691 
02692 uint Client::ruleOpacityInactive()
02693     {
02694     return rule_opacity_inactive;// != 0 ;
02695     }
02696 
02697 uint Client::ruleOpacityActive()
02698     {
02699     return rule_opacity_active;// != 0;
02700     }
02701     
02702 bool Client::getWindowOpacity() //query translucency settings from X, returns true if window opacity is set
02703     {
02704     unsigned char *data = 0;
02705     Atom actual;
02706     int format, result;
02707     unsigned long n, left;
02708     result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
02709     if (result == Success && data != None && format == 32 )
02710         {
02711         opacity_ = *reinterpret_cast< long* >( data );
02712         custom_opacity = true;
02713 //         setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
02714         XFree ((char*)data);
02715         return TRUE;
02716         }
02717     return FALSE;
02718     }
02719     
02720 void Client::setCustomOpacityFlag(bool custom)
02721     {
02722     custom_opacity = custom;
02723     }
02724     
02725 uint Client::opacity()
02726     {
02727     return opacity_;
02728     }
02729 
02730 int Client::opacityPercentage()
02731     {
02732     return int(100*((double)opacity_/0xffffffff));
02733     }
02734     
02735 bool Client::touches(const Client* c)
02736 // checks if this client borders c, needed to test beep media player window state
02737     {
02738     if (y() == c->y() + c->height()) // this bottom to c
02739         return TRUE;
02740     if (y() + height() == c->y()) // this top to c
02741         return TRUE;
02742     if (x() == c->x() + c->width()) // this right to c
02743         return TRUE;
02744     if (x() + width() == c->x()) // this left to c
02745         return TRUE;
02746     return FALSE;
02747     }
02748     
02749 void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
02750 {
02751    long data = (topHeight < 255 ? topHeight : 255) << 24 |
02752                (rightWidth < 255 ? rightWidth : 255) << 16 |
02753                (bottomHeight < 255 ? bottomHeight : 255) << 8 |
02754                (leftWidth < 255 ? leftWidth : 255);
02755     XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02756 }
02757 
02758 void Client::unsetDecoHashProperty()
02759 {
02760    XDeleteProperty( qt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
02761 }
02762     
02763 #ifndef NDEBUG
02764 kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
02765     {
02766     if( cl == NULL )
02767         return stream << "\'NULL_CLIENT\'";
02768     return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
02769     }
02770 kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
02771     {
02772     stream << "LIST:(";
02773     bool first = true;
02774     for( ClientList::ConstIterator it = list.begin();
02775          it != list.end();
02776          ++it )
02777         {
02778         if( !first )
02779             stream << ":";
02780         first = false;
02781         stream << *it;
02782         }
02783     stream << ")";
02784     return stream;
02785     }
02786 kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
02787     {
02788     stream << "LIST:(";
02789     bool first = true;
02790     for( ConstClientList::ConstIterator it = list.begin();
02791          it != list.end();
02792          ++it )
02793         {
02794         if( !first )
02795             stream << ":";
02796         first = false;
02797         stream << *it;
02798         }
02799     stream << ")";
02800     return stream;
02801     }
02802 #endif
02803 
02804 TQPixmap * kwin_get_menu_pix_hack()
02805     {
02806     static TQPixmap p;
02807     if ( p.isNull() )
02808         p = SmallIcon( "bx2" );
02809     return &p;
02810     }
02811 
02812 } // namespace
02813 
02814 #include "client.moc"

kwin

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

kwin

Skip menu "kwin"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for kwin by doxygen 1.5.6
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |