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