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

twin

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

twin

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

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.