/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project .
Copyright ( C ) 1999 , 2000 Matthias Ettrich < ettrich @ kde . org >
Copyright ( C ) 2003 Lubos Lunak < l . lunak @ kde . org >
You can Freely distribute this program under the GNU General Public
License . See the file " COPYING " for the exact licensing terms .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "client.h"
# include <math.h>
# include <tqapplication.h>
# include <tqpainter.h>
# include <tqdatetime.h>
# include <tqimage.h>
# include <tqfile.h>
# include <kprocess.h>
# include <unistd.h>
# include <kstandarddirs.h>
# include <tqwhatsthis.h>
# include <twin.h>
# include <kiconloader.h>
# include <tdelocale.h>
# include <stdlib.h>
# ifdef Q_OS_SOLARIS
# include <procfs.h>
# include <libgen.h>
# endif /* SunOS */
# include "bridge.h"
# include "group.h"
# include "workspace.h"
# include "atoms.h"
# include "notifications.h"
# include "rules.h"
# include <X11/extensions/shape.h>
// put all externs before the namespace statement to allow the linker
// to resolve them properly
extern Atom tqt_wm_state ;
extern Atom tqt_window_role ;
extern Atom tqt_sm_client_id ;
// wait 200 ms before drawing shadow after move/resize
static const int SHADOW_DELAY = 200 ;
namespace KWinInternal
{
/* TODO: Remove this once X has real translucency.
*
* A list of the regions covered by all shadows and the Clients to which they
* belong . Used to redraw shadows when a window overlapping or underlying a
* shadow is moved , resized , or hidden .
*/
struct ShadowRegion
{
TQRegion region ;
Client * client ;
} ;
static TQValueList < ShadowRegion > shadowRegions ;
/*
Creating a client :
- only by calling Workspace : : createClient ( )
- it creates a new client and calls manage ( ) for it
Destroying a client :
- destroyClient ( ) - only when the window itself has been destroyed
- releaseWindow ( ) - the window is kept , only the client itself is destroyed
*/
/*!
\ class Client client . h
\ brief The Client class encapsulates a window decoration frame .
*/
/*!
This ctor is " dumb " - it only initializes data . All the real initialization
is done in manage ( ) .
*/
Client : : Client ( Workspace * ws )
: TQObject ( NULL ) ,
client ( None ) ,
wrapper ( None ) ,
frame ( None ) ,
decoration ( NULL ) ,
wspace ( ws ) ,
bridge ( new Bridge ( this ) ) ,
move_faked_activity ( false ) ,
move_resize_grab_window ( None ) ,
transient_for ( NULL ) ,
transient_for_id ( None ) ,
original_transient_for_id ( None ) ,
in_group ( NULL ) ,
window_group ( None ) ,
in_layer ( UnknownLayer ) ,
ping_timer ( NULL ) ,
process_killer ( NULL ) ,
process_resumer ( NULL ) ,
user_time ( CurrentTime ) , // not known yet
allowed_actions ( 0 ) ,
postpone_geometry_updates ( 0 ) ,
pending_geometry_update ( false ) ,
shade_geometry_change ( false ) ,
border_left ( 0 ) ,
border_right ( 0 ) ,
border_top ( 0 ) ,
border_bottom ( 0 ) ,
opacity_ ( 0 ) ,
demandAttentionKNotifyTimer ( NULL ) ,
activeMaximizing ( false ) ,
activeTiled ( false )
// SELI do all as initialization
{
autoRaiseTimer = 0 ;
shadeHoverTimer = 0 ;
shadowDelayTimer = new TQTimer ( this ) ;
opacityCache = & activeOpacityCache ;
shadowAfterClient = NULL ;
shadowWidget = NULL ;
shadowMe = true ;
connect ( shadowDelayTimer , TQT_SIGNAL ( timeout ( ) ) , TQT_SLOT ( drawShadow ( ) ) ) ;
// set the initial mapping state
mapping_state = WithdrawnState ;
desk = 0 ; // no desktop yet
mode = PositionCenter ;
buttonDown = FALSE ;
moveResizeMode = FALSE ;
info = NULL ;
shade_mode = ShadeNone ;
active = FALSE ;
deleting = false ;
keep_above = FALSE ;
keep_below = FALSE ;
is_shape = FALSE ;
motif_noborder = false ;
motif_may_move = TRUE ;
motif_may_resize = TRUE ;
motif_may_close = TRUE ;
fullscreen_mode = FullScreenNone ;
skip_taskbar = FALSE ;
original_skip_taskbar = false ;
minimized = false ;
hidden = false ;
modal = false ;
noborder = false ;
user_noborder = false ;
urgency = false ;
ignore_focus_stealing = false ;
demands_attention = false ;
check_active_modal = false ;
Pdeletewindow = 0 ;
Ptakefocus = 0 ;
Ptakeactivity = 0 ;
Pcontexthelp = 0 ;
Pping = 0 ;
input = FALSE ;
skip_pager = FALSE ;
max_mode = MaximizeRestore ;
maxmode_restore = MaximizeRestore ;
cmap = None ;
frame_geometry = TQRect ( 0 , 0 , 100 , 100 ) ; // so that decorations don't start with size being (0,0)
client_size = TQSize ( 100 , 100 ) ;
custom_opacity = false ;
rule_opacity_active = 0 ; //translucency rules
rule_opacity_inactive = 0 ; //dito.
// SELI initialize xsizehints??
}
/*!
" Dumb " destructor .
*/
Client : : ~ Client ( )
{
assert ( ! moveResizeMode ) ;
assert ( client = = None ) ;
assert ( frame = = None & & wrapper = = None ) ;
assert ( decoration = = NULL ) ;
assert ( postpone_geometry_updates = = 0 ) ;
assert ( ! check_active_modal ) ;
delete info ;
delete bridge ;
}
// use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
void Client : : deleteClient ( Client * c , allowed_t )
{
delete c ;
}
/*!
Releases the window . The client has done its job and the window is still existing .
*/
void Client : : releaseWindow ( bool on_shutdown )
{
assert ( ! deleting ) ;
deleting = true ;
workspace ( ) - > discardUsedWindowRules ( this , true ) ; // remove ForceTemporarily rules
StackingUpdatesBlocker blocker ( workspace ( ) ) ;
if ( ! custom_opacity ) setOpacity ( FALSE ) ;
if ( moveResizeMode )
leaveMoveResize ( ) ;
removeShadow ( ) ;
drawIntersectingShadows ( ) ;
finishWindowRules ( ) ;
+ + postpone_geometry_updates ;
// grab X during the release to make removing of properties, setting to withdrawn state
// and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2)
grabXServer ( ) ;
setMappingState ( WithdrawnState ) ;
setModal ( false ) ; // otherwise its mainwindow wouldn't get focus
hidden = true ; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
if ( ! on_shutdown )
workspace ( ) - > clientHidden ( this ) ;
XUnmapWindow ( tqt_xdisplay ( ) , frameId ( ) ) ; // destroying decoration would cause ugly visual effect
destroyDecoration ( ) ;
cleanGrouping ( ) ;
if ( ! on_shutdown )
{
workspace ( ) - > removeClient ( this , Allowed ) ;
// only when the window is being unmapped, not when closing down KWin
// (NETWM sections 5.5,5.7)
info - > setDesktop ( 0 ) ;
desk = 0 ;
info - > setState ( 0 , info - > state ( ) ) ; // reset all state flags
}
XDeleteProperty ( tqt_xdisplay ( ) , client , atoms - > kde_net_wm_user_creation_time ) ;
XDeleteProperty ( tqt_xdisplay ( ) , client , atoms - > net_frame_extents ) ;
XDeleteProperty ( tqt_xdisplay ( ) , client , atoms - > kde_net_wm_frame_strut ) ;
XReparentWindow ( tqt_xdisplay ( ) , client , workspace ( ) - > rootWin ( ) , x ( ) , y ( ) ) ;
XRemoveFromSaveSet ( tqt_xdisplay ( ) , client ) ;
XSelectInput ( tqt_xdisplay ( ) , client , NoEventMask ) ;
if ( on_shutdown )
{ // map the window, so it can be found after another WM is started
XMapWindow ( tqt_xdisplay ( ) , client ) ;
// TODO preserve minimized, shaded etc. state?
}
else
{
// Make sure it's not mapped if the app unmapped it (#65279). The app
// may do map+unmap before we initially map the window by calling rawShow() from manage().
XUnmapWindow ( tqt_xdisplay ( ) , client ) ;
}
client = None ;
XDestroyWindow ( tqt_xdisplay ( ) , wrapper ) ;
wrapper = None ;
XDestroyWindow ( tqt_xdisplay ( ) , frame ) ;
frame = None ;
- - postpone_geometry_updates ; // don't use GeometryUpdatesBlocker, it would now set the geometry
checkNonExistentClients ( ) ;
deleteClient ( this , Allowed ) ;
ungrabXServer ( ) ;
}
// like releaseWindow(), but this one is called when the window has been already destroyed
// (e.g. the application closed it)
void Client : : destroyClient ( )
{
assert ( ! deleting ) ;
deleting = true ;
workspace ( ) - > discardUsedWindowRules ( this , true ) ; // remove ForceTemporarily rules
StackingUpdatesBlocker blocker ( workspace ( ) ) ;
if ( moveResizeMode )
leaveMoveResize ( ) ;
removeShadow ( ) ;
drawIntersectingShadows ( ) ;
finishWindowRules ( ) ;
+ + postpone_geometry_updates ;
setModal ( false ) ;
hidden = true ; // so that it's not considered visible anymore
workspace ( ) - > clientHidden ( this ) ;
destroyDecoration ( ) ;
cleanGrouping ( ) ;
workspace ( ) - > removeClient ( this , Allowed ) ;
client = None ; // invalidate
XDestroyWindow ( tqt_xdisplay ( ) , wrapper ) ;
wrapper = None ;
XDestroyWindow ( tqt_xdisplay ( ) , frame ) ;
frame = None ;
- - postpone_geometry_updates ; // don't use GeometryUpdatesBlocker, it would now set the geometry
checkNonExistentClients ( ) ;
deleteClient ( this , Allowed ) ;
}
void Client : : updateDecoration ( bool check_workspace_pos , bool force )
{
if ( ! force & & ( ( decoration = = NULL & & noBorder ( ) )
| | ( decoration ! = NULL & & ! noBorder ( ) ) ) )
return ;
bool do_show = false ;
postponeGeometryUpdates ( true ) ;
if ( force )
destroyDecoration ( ) ;
if ( ! noBorder ( ) )
{
setMask ( TQRegion ( ) ) ; // reset shape mask
decoration = workspace ( ) - > createDecoration ( bridge ) ;
// TODO check decoration's minimum size?
decoration - > init ( ) ;
decoration - > widget ( ) - > installEventFilter ( this ) ;
XReparentWindow ( tqt_xdisplay ( ) , decoration - > widget ( ) - > winId ( ) , frameId ( ) , 0 , 0 ) ;
decoration - > widget ( ) - > lower ( ) ;
decoration - > borders ( border_left , border_right , border_top , border_bottom ) ;
options - > onlyDecoTranslucent ?
setDecoHashProperty ( border_top , border_right , border_bottom , border_left ) :
unsetDecoHashProperty ( ) ;
int save_workarea_diff_x = workarea_diff_x ;
int save_workarea_diff_y = workarea_diff_y ;
move ( calculateGravitation ( false ) ) ;
plainResize ( sizeForClientSize ( clientSize ( ) ) , ForceGeometrySet ) ;
workarea_diff_x = save_workarea_diff_x ;
workarea_diff_y = save_workarea_diff_y ;
do_show = true ;
}
else
destroyDecoration ( ) ;
if ( check_workspace_pos )
checkWorkspacePosition ( ) ;
postponeGeometryUpdates ( false ) ;
if ( do_show )
decoration - > widget ( ) - > show ( ) ;
updateFrameExtents ( ) ;
updateOpacityCache ( ) ;
}
void Client : : destroyDecoration ( )
{
if ( decoration ! = NULL )
{
delete decoration ;
decoration = NULL ;
TQPoint grav = calculateGravitation ( true ) ;
border_left = border_right = border_top = border_bottom = 0 ;
setMask ( TQRegion ( ) ) ; // reset shape mask
int save_workarea_diff_x = workarea_diff_x ;
int save_workarea_diff_y = workarea_diff_y ;
plainResize ( sizeForClientSize ( clientSize ( ) ) , ForceGeometrySet ) ;
move ( grav ) ;
workarea_diff_x = save_workarea_diff_x ;
workarea_diff_y = save_workarea_diff_y ;
}
}
void Client : : checkBorderSizes ( )
{
if ( decoration = = NULL )
return ;
int new_left , new_right , new_top , new_bottom ;
decoration - > borders ( new_left , new_right , new_top , new_bottom ) ;
if ( new_left = = border_left & & new_right = = border_right
& & new_top = = border_top & & new_bottom = = border_bottom )
return ;
GeometryUpdatesPostponer blocker ( this ) ;
move ( calculateGravitation ( true ) ) ;
border_left = new_left ;
border_right = new_right ;
border_top = new_top ;
border_bottom = new_bottom ;
if ( border_left ! = new_left | |
border_right ! = new_right | |
border_top ! = new_top | |
border_bottom ! = new_bottom )
options - > onlyDecoTranslucent ?
setDecoHashProperty ( new_top , new_right , new_bottom , new_left ) :
unsetDecoHashProperty ( ) ;
move ( calculateGravitation ( false ) ) ;
plainResize ( sizeForClientSize ( clientSize ( ) ) , ForceGeometrySet ) ;
checkWorkspacePosition ( ) ;
}
void Client : : detectNoBorder ( )
{
if ( Shape : : hasShape ( window ( ) ) )
{
noborder = true ;
return ;
}
switch ( windowType ( ) )
{
case NET : : Desktop :
case NET : : Dock :
case NET : : TopMenu :
case NET : : Splash :
noborder = true ;
break ;
case NET : : Unknown :
case NET : : Normal :
case NET : : Toolbar :
case NET : : Menu :
case NET : : Dialog :
case NET : : Utility :
noborder = false ;
break ;
default :
assert ( false ) ;
}
// NET::Override is some strange beast without clear definition, usually
// just meaning "noborder", so let's treat it only as such flag, and ignore it as
// a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
if ( info - > windowType ( SUPPORTED_WINDOW_TYPES_MASK | NET : : OverrideMask ) = = NET : : Override )
noborder = true ;
}
void Client : : detectShapable ( )
{
if ( Shape : : hasShape ( window ( ) ) )
return ;
switch ( windowType ( ) )
{
case NET : : Desktop :
case NET : : Dock :
case NET : : TopMenu :
case NET : : Splash :
break ;
case NET : : Unknown :
case NET : : Normal :
case NET : : Toolbar :
case NET : : Menu :
case NET : : Dialog :
case NET : : Utility :
setShapable ( FALSE ) ;
break ;
default :
assert ( false ) ;
}
}
void Client : : updateFrameExtents ( )
{
NETStrut strut ;
strut . left = border_left ;
strut . right = border_right ;
strut . top = border_top ;
strut . bottom = border_bottom ;
info - > setFrameExtents ( strut ) ;
}
// Resizes the decoration, and makes sure the decoration widget gets resize event
// even if the size hasn't changed. This is needed to make sure the decoration
// re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes,
// the decoration may turn on/off some borders, but the actual size
// of the decoration stays the same).
void Client : : resizeDecoration ( const TQSize & s )
{
if ( decoration = = NULL )
return ;
TQSize oldsize = decoration - > widget ( ) - > size ( ) ;
decoration - > resize ( s ) ;
if ( oldsize = = s )
{
TQResizeEvent e ( s , oldsize ) ;
TQApplication : : sendEvent ( decoration - > widget ( ) , & e ) ;
}
if ( ! moveResizeMode & & options - > shadowEnabled ( isActive ( ) ) )
{
// If the user is manually resizing, let Client::leaveMoveResize()
// decide when to redraw the shadow
updateOpacityCache ( ) ;
}
}
bool Client : : noBorder ( ) const
{
return noborder | | isFullScreen ( ) | | user_noborder | | motif_noborder ;
}
bool Client : : userCanSetNoBorder ( ) const
{
return ! noborder & & ! isFullScreen ( ) & & ! isShade ( ) ;
}
bool Client : : isUserNoBorder ( ) const
{
return user_noborder ;
}
void Client : : setUserNoBorder ( bool set )
{
if ( ! userCanSetNoBorder ( ) )
return ;
set = rules ( ) - > checkNoBorder ( set ) ;
if ( user_noborder = = set )
return ;
user_noborder = set ;
updateDecoration ( true , false ) ;
updateWindowRules ( ) ;
}
bool Client : : isModalSystemNotification ( ) const
{
unsigned char * data = 0 ;
Atom actual ;
int format , result ;
unsigned long n , left ;
result = XGetWindowProperty ( tqt_xdisplay ( ) , window ( ) , atoms - > net_wm_system_modal_notification , 0L , 1L , False , XA_CARDINAL , & actual , & format , & n , & left , /*(unsigned char **)*/ & data ) ;
if ( result = = Success & & data & & format = = 32 )
{
return TRUE ;
}
return FALSE ;
}
void Client : : updateShape ( )
{
// workaround for #19644 - shaped windows shouldn't have decoration
if ( shape ( ) & & ! noBorder ( ) )
{
noborder = true ;
updateDecoration ( true ) ;
}
updateOpacityCache ( ) ;
if ( shape ( ) )
{
XShapeCombineShape ( tqt_xdisplay ( ) , frameId ( ) , ShapeBounding ,
clientPos ( ) . x ( ) , clientPos ( ) . y ( ) ,
window ( ) , ShapeBounding , ShapeSet ) ;
setShapable ( TRUE ) ;
}
// !shape() mask setting is done in setMask() when the decoration
// calls it or when the decoration is created/destroyed
if ( Shape : : version ( ) > = 0x11 ) // 1.1, has input shape support
{ // There appears to be no way to find out if a window has input
// shape set or not, so always propagate the input shape
// (it's the same like the bounding shape by default).
// Also, build the shape using a helper window, not directly
// in the frame window, because the sequence set-shape-to-frame,
// remove-shape-of-client, add-input-shape-of-client has the problem
// that after the second step there's a hole in the input shape
// until the real shape of the client is added and that can make
// the window lose focus (which is a problem with mouse focus policies)
static Window helper_window = None ;
if ( helper_window = = None )
helper_window = XCreateSimpleWindow ( tqt_xdisplay ( ) , tqt_xrootwin ( ) ,
0 , 0 , 1 , 1 , 0 , 0 , 0 ) ;
XResizeWindow ( tqt_xdisplay ( ) , helper_window , width ( ) , height ( ) ) ;
XShapeCombineShape ( tqt_xdisplay ( ) , helper_window , ShapeInput , 0 , 0 ,
frameId ( ) , ShapeBounding , ShapeSet ) ;
XShapeCombineShape ( tqt_xdisplay ( ) , helper_window , ShapeInput ,
clientPos ( ) . x ( ) , clientPos ( ) . y ( ) ,
window ( ) , ShapeBounding , ShapeSubtract ) ;
XShapeCombineShape ( tqt_xdisplay ( ) , helper_window , ShapeInput ,
clientPos ( ) . x ( ) , clientPos ( ) . y ( ) ,
window ( ) , ShapeInput , ShapeUnion ) ;
XShapeCombineShape ( tqt_xdisplay ( ) , frameId ( ) , ShapeInput , 0 , 0 ,
helper_window , ShapeInput , ShapeSet ) ;
}
}
void Client : : setMask ( const TQRegion & reg , int mode )
{
_mask = reg ;
if ( reg . isNull ( ) )
XShapeCombineMask ( tqt_xdisplay ( ) , frameId ( ) , ShapeBounding , 0 , 0 ,
None , ShapeSet ) ;
else if ( mode = = X : : Unsorted )
XShapeCombineRegion ( tqt_xdisplay ( ) , frameId ( ) , ShapeBounding , 0 , 0 ,
reg . handle ( ) , ShapeSet ) ;
else
{
TQMemArray < TQRect > rects = reg . rects ( ) ;
XRectangle * xrects = new XRectangle [ rects . count ( ) ] ;
for ( unsigned int i = 0 ;
i < rects . count ( ) ;
+ + i )
{
xrects [ i ] . x = rects [ i ] . x ( ) ;
xrects [ i ] . y = rects [ i ] . y ( ) ;
xrects [ i ] . width = rects [ i ] . width ( ) ;
xrects [ i ] . height = rects [ i ] . height ( ) ;
}
XShapeCombineRectangles ( tqt_xdisplay ( ) , frameId ( ) , ShapeBounding , 0 , 0 ,
xrects , rects . count ( ) , ShapeSet , mode ) ;
delete [ ] xrects ;
}
updateShape ( ) ;
}
TQRegion Client : : mask ( ) const
{
if ( _mask . isEmpty ( ) )
return TQRegion ( 0 , 0 , width ( ) , height ( ) ) ;
return _mask ;
}
void Client : : setShapable ( bool b )
{
long tmp = b ? 1 : 0 ;
XChangeProperty ( tqt_xdisplay ( ) , frameId ( ) , atoms - > net_wm_window_shapable , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & tmp , 1L ) ;
}
void Client : : hideClient ( bool hide )
{
if ( hidden = = hide )
return ;
hidden = hide ;
updateVisibility ( ) ;
}
/*!
Returns whether the window is minimizable or not
*/
bool Client : : isMinimizable ( ) const
{
if ( isSpecialWindow ( ) )
return false ;
if ( isModalSystemNotification ( ) )
return false ;
if ( isTransient ( ) )
{ // #66868 - let other xmms windows be minimized when the mainwindow is minimized
bool shown_mainwindow = false ;
ClientList mainclients = mainClients ( ) ;
for ( ClientList : : ConstIterator it = mainclients . begin ( ) ;
it ! = mainclients . end ( ) ;
+ + it )
{
if ( ( * it ) - > isShown ( true ) )
shown_mainwindow = true ;
}
if ( ! shown_mainwindow )
return true ;
}
// this is here because kicker's taskbar doesn't provide separate entries
// for windows with an explicitly given parent
// TODO perhaps this should be redone
if ( transientFor ( ) ! = NULL )
return false ;
if ( ! wantsTabFocus ( ) ) // SELI - NET::Utility? why wantsTabFocus() - skiptaskbar? ?
return false ;
return true ;
}
/*!
Returns whether the window is kept above or not
*/
bool Client : : keepAbove ( ) const
{
if ( isModalSystemNotification ( ) )
return true ;
return keep_above ;
}
/*!
Minimizes this client plus its transients
*/
void Client : : minimize ( bool avoid_animation )
{
if ( ! isMinimizable ( ) | | isMinimized ( ) )
return ;
if ( isShade ( ) ) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
info - > setState ( 0 , NET : : Shaded ) ;
Notify : : raise ( Notify : : Minimize ) ;
// SELI mainClients().isEmpty() ??? - and in unminimize() too
if ( mainClients ( ) . isEmpty ( ) & & isOnCurrentDesktop ( ) & & isShown ( true ) & & ! avoid_animation )
animateMinimizeOrUnminimize ( true ) ; // was visible or shaded
minimized = true ;
updateVisibility ( ) ;
updateAllowedActions ( ) ;
workspace ( ) - > updateMinimizedOfTransients ( this ) ;
updateWindowRules ( ) ;
workspace ( ) - > updateFocusChains ( this , Workspace : : FocusChainMakeLast ) ;
}
void Client : : unminimize ( bool avoid_animation )
{
if ( ! queryUserSuspendedResume ( ) )
return ;
if ( ! isMinimized ( ) )
return ;
if ( isShade ( ) ) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
info - > setState ( NET : : Shaded , NET : : Shaded ) ;
Notify : : raise ( Notify : : UnMinimize ) ;
minimized = false ;
if ( isOnCurrentDesktop ( ) & & isShown ( true ) )
{
if ( mainClients ( ) . isEmpty ( ) & & ! avoid_animation )
animateMinimizeOrUnminimize ( FALSE ) ;
}
updateVisibility ( ) ;
updateAllowedActions ( ) ;
workspace ( ) - > updateMinimizedOfTransients ( this ) ;
updateWindowRules ( ) ;
}
extern bool blockAnimation ;
void Client : : animateMinimizeOrUnminimize ( bool minimize )
{
if ( blockAnimation )
return ;
if ( ! options - > animateMinimize )
return ;
if ( decoration ! = NULL & & decoration - > animateMinimize ( minimize ) )
return ; // decoration did it
// the function is a bit tricky since it will ensure that an
// animation action needs always the same time regardless of the
// performance of the machine or the X-Server.
float lf , rf , tf , bf , step ;
int speed = options - > animateMinimizeSpeed ;
if ( speed > 10 )
speed = 10 ;
if ( speed < 0 )
speed = 0 ;
step = 40. * ( 11 - speed ) ;
NETRect r = info - > iconGeometry ( ) ;
TQRect icongeom ( r . pos . x , r . pos . y , r . size . width , r . size . height ) ;
if ( ! icongeom . isValid ( ) )
return ;
TQPixmap pm = animationPixmap ( minimize ? width ( ) : icongeom . width ( ) ) ;
TQRect before , after ;
if ( minimize )
{
before = TQRect ( x ( ) , y ( ) , width ( ) , pm . height ( ) ) ;
after = TQRect ( icongeom . x ( ) , icongeom . y ( ) , icongeom . width ( ) , pm . height ( ) ) ;
}
else
{
before = TQRect ( icongeom . x ( ) , icongeom . y ( ) , icongeom . width ( ) , pm . height ( ) ) ;
after = TQRect ( x ( ) , y ( ) , width ( ) , pm . height ( ) ) ;
}
lf = ( after . left ( ) - before . left ( ) ) / step ;
rf = ( after . right ( ) - before . right ( ) ) / step ;
tf = ( after . top ( ) - before . top ( ) ) / step ;
bf = ( after . bottom ( ) - before . bottom ( ) ) / step ;
grabXServer ( ) ;
TQRect area = before ;
TQRect area2 ;
TQPixmap pm2 ;
TQTime t ;
t . start ( ) ;
float diff ;
TQPainter p ( workspace ( ) - > desktopWidget ( ) ) ;
bool need_to_clear = FALSE ;
TQPixmap pm3 ;
do
{
if ( area2 ! = area )
{
pm = animationPixmap ( area . width ( ) ) ;
pm2 = TQPixmap : : grabWindow ( tqt_xrootwin ( ) , area . x ( ) , area . y ( ) , area . width ( ) , area . height ( ) ) ;
p . drawPixmap ( area . x ( ) , area . y ( ) , pm ) ;
if ( need_to_clear )
{
p . drawPixmap ( area2 . x ( ) , area2 . y ( ) , pm3 ) ;
need_to_clear = FALSE ;
}
area2 = area ;
}
XFlush ( tqt_xdisplay ( ) ) ;
XSync ( tqt_xdisplay ( ) , FALSE ) ;
diff = t . elapsed ( ) ;
if ( diff > step )
diff = step ;
area . setLeft ( before . left ( ) + int ( diff * lf ) ) ;
area . setRight ( before . right ( ) + int ( diff * rf ) ) ;
area . setTop ( before . top ( ) + int ( diff * tf ) ) ;
area . setBottom ( before . bottom ( ) + int ( diff * bf ) ) ;
if ( area2 ! = area )
{
if ( area2 . intersects ( area ) )
p . drawPixmap ( area2 . x ( ) , area2 . y ( ) , pm2 ) ;
else
{ // no overlap, we can clear later to avoid flicker
pm3 = pm2 ;
need_to_clear = TRUE ;
}
}
} while ( t . elapsed ( ) < step ) ;
if ( area2 = = area | | need_to_clear )
p . drawPixmap ( area2 . x ( ) , area2 . y ( ) , pm2 ) ;
p . end ( ) ;
ungrabXServer ( ) ;
}
/*!
The pixmap shown during ( un ) minimalization animation
*/
TQPixmap Client : : animationPixmap ( int w )
{
TQFont font = options - > font ( isActive ( ) ) ;
TQFontMetrics fm ( font ) ;
TQPixmap pm ( w , fm . lineSpacing ( ) ) ;
pm . fill ( options - > color ( Options : : ColorTitleBar , isActive ( ) | | isMinimized ( ) ) ) ;
TQPainter p ( & pm ) ;
p . setPen ( options - > color ( Options : : ColorFont , isActive ( ) | | isMinimized ( ) ) ) ;
p . setFont ( options - > font ( isActive ( ) ) ) ;
p . drawText ( pm . rect ( ) , AlignLeft | AlignVCenter | SingleLine , caption ( ) ) ;
return pm ;
}
bool Client : : isShadeable ( ) const
{
return ! isSpecialWindow ( ) & & ! noBorder ( ) ;
}
void Client : : setShade ( ShadeMode mode )
{
if ( ! isShadeable ( ) )
return ;
if ( isModalSystemNotification ( ) )
return ;
mode = rules ( ) - > checkShade ( mode ) ;
if ( shade_mode = = mode )
return ;
bool was_shade = isShade ( ) ;
ShadeMode was_shade_mode = shade_mode ;
shade_mode = mode ;
if ( was_shade = = isShade ( ) )
{
if ( decoration ! = NULL ) // decoration may want to update after e.g. hover-shade changes
decoration - > shadeChange ( ) ;
return ; // no real change in shaded state
}
if ( shade_mode = = ShadeNormal )
{
if ( isShown ( true ) & & isOnCurrentDesktop ( ) )
Notify : : raise ( Notify : : ShadeUp ) ;
}
else if ( shade_mode = = ShadeNone )
{
if ( isShown ( true ) & & isOnCurrentDesktop ( ) )
Notify : : raise ( Notify : : ShadeDown ) ;
}
assert ( decoration ! = NULL ) ; // noborder windows can't be shaded
GeometryUpdatesPostponer blocker ( this ) ;
// decorations may turn off some borders when shaded
decoration - > borders ( border_left , border_right , border_top , border_bottom ) ;
int as = options - > animateShade ? 10 : 1 ;
// TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
if ( isShade ( ) )
{ // shade_mode == ShadeNormal
// we're about to shade, texx xcompmgr to prepare
long _shade = 1 ;
XChangeProperty ( tqt_xdisplay ( ) , frameId ( ) , atoms - > net_wm_window_shade , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & _shade , 1L ) ;
// shade
int h = height ( ) ;
shade_geometry_change = true ;
TQSize s ( sizeForClientSize ( TQSize ( clientSize ( ) ) ) ) ;
s . setHeight ( border_top + border_bottom ) ;
XSelectInput ( tqt_xdisplay ( ) , wrapper , ClientWinMask ) ; // avoid getting UnmapNotify
XUnmapWindow ( tqt_xdisplay ( ) , wrapper ) ;
XUnmapWindow ( tqt_xdisplay ( ) , client ) ;
XSelectInput ( tqt_xdisplay ( ) , wrapper , ClientWinMask | SubstructureNotifyMask ) ;
//as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it
//done xcompmgr workaround
// FRAME repaint( FALSE );
// bool wasStaticContents = testWFlags( WStaticContents );
// setWFlags( WStaticContents );
int step = TQMAX ( 4 , QABS ( h - s . height ( ) ) / as ) + 1 ;
do
{
h - = step ;
XResizeWindow ( tqt_xdisplay ( ) , frameId ( ) , s . width ( ) , h ) ;
resizeDecoration ( TQSize ( s . width ( ) , h ) ) ;
TQApplication : : syncX ( ) ;
} while ( h > s . height ( ) + step ) ;
// if ( !wasStaticContents )
// clearWFlags( WStaticContents );
plainResize ( s ) ;
shade_geometry_change = false ;
if ( isActive ( ) )
{
if ( was_shade_mode = = ShadeHover )
workspace ( ) - > activateNextClient ( this ) ;
else
workspace ( ) - > focusToNull ( ) ;
}
// tell xcompmgr shade's done
_shade = 2 ;
XChangeProperty ( tqt_xdisplay ( ) , frameId ( ) , atoms - > net_wm_window_shade , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & _shade , 1L ) ;
}
else
{
int h = height ( ) ;
shade_geometry_change = true ;
TQSize s ( sizeForClientSize ( clientSize ( ) ) ) ;
// FRAME bool wasStaticContents = testWFlags( WStaticContents );
// setWFlags( WStaticContents );
int step = TQMAX ( 4 , QABS ( h - s . height ( ) ) / as ) + 1 ;
do
{
h + = step ;
XResizeWindow ( tqt_xdisplay ( ) , frameId ( ) , s . width ( ) , h ) ;
resizeDecoration ( TQSize ( s . width ( ) , h ) ) ;
// assume a border
// we do not have time to wait for X to send us paint events
// FRAME repaint( 0, h - step-5, width(), step+5, TRUE);
TQApplication : : syncX ( ) ;
} while ( h < s . height ( ) - step ) ;
// if ( !wasStaticContents )
// clearWFlags( WStaticContents );
shade_geometry_change = false ;
plainResize ( s ) ;
if ( shade_mode = = ShadeHover | | shade_mode = = ShadeActivated )
setActive ( TRUE ) ;
XMapWindow ( tqt_xdisplay ( ) , wrapperId ( ) ) ;
XMapWindow ( tqt_xdisplay ( ) , window ( ) ) ;
XDeleteProperty ( tqt_xdisplay ( ) , client , atoms - > net_wm_window_shade ) ;
if ( options - > shadowEnabled ( false ) )
{
for ( ClientList : : ConstIterator it = transients ( ) . begin ( ) ;
it ! = transients ( ) . end ( ) ; + + it )
{
( * it ) - > removeShadow ( ) ;
( * it ) - > drawDelayedShadow ( ) ;
}
}
if ( isActive ( ) )
workspace ( ) - > requestFocus ( this ) ;
}
checkMaximizeGeometry ( ) ;
info - > setState ( ( isShade ( ) & & ! isMinimized ( ) ) ? NET : : Shaded : 0 , NET : : Shaded ) ;
info - > setState ( isShown ( false ) ? 0 : NET : : Hidden , NET : : Hidden ) ;
updateVisibility ( ) ;
updateAllowedActions ( ) ;
workspace ( ) - > updateMinimizedOfTransients ( this ) ;
decoration - > shadeChange ( ) ;
updateWindowRules ( ) ;
}
void Client : : shadeHover ( )
{
setShade ( ShadeHover ) ;
cancelShadeHover ( ) ;
}
void Client : : cancelShadeHover ( )
{
delete shadeHoverTimer ;
shadeHoverTimer = 0 ;
}
void Client : : toggleShade ( )
{
// if the mode is ShadeHover or ShadeActive, cancel shade too
setShade ( shade_mode = = ShadeNone ? ShadeNormal : ShadeNone ) ;
}
void Client : : updateVisibility ( )
{
if ( deleting )
return ;
bool show = true ;
if ( hidden )
{
setMappingState ( IconicState ) ;
info - > setState ( NET : : Hidden , NET : : Hidden ) ;
setSkipTaskbar ( true , false ) ; // also hide from taskbar
rawHide ( ) ;
show = false ;
}
else
{
setSkipTaskbar ( original_skip_taskbar , false ) ;
}
if ( minimized )
{
setMappingState ( IconicState ) ;
info - > setState ( NET : : Hidden , NET : : Hidden ) ;
rawHide ( ) ;
show = false ;
}
if ( show )
info - > setState ( 0 , NET : : Hidden ) ;
if ( ! isOnCurrentDesktop ( ) )
{
setMappingState ( IconicState ) ;
rawHide ( ) ;
show = false ;
}
if ( show )
{
bool belongs_to_desktop = false ;
for ( ClientList : : ConstIterator it = group ( ) - > members ( ) . begin ( ) ;
it ! = group ( ) - > members ( ) . end ( ) ;
+ + it )
if ( ( * it ) - > isDesktop ( ) )
{
belongs_to_desktop = true ;
break ;
}
if ( ! belongs_to_desktop & & workspace ( ) - > showingDesktop ( ) )
workspace ( ) - > resetShowingDesktop ( true ) ;
if ( isShade ( ) )
setMappingState ( IconicState ) ;
else
setMappingState ( NormalState ) ;
rawShow ( ) ;
}
}
void Client : : setShadowed ( bool shadowed )
{
bool wasShadowed ;
wasShadowed = isShadowed ( ) ;
shadowMe = options - > shadowEnabled ( isActive ( ) ) ? shadowed : false ;
if ( shadowMe ) {
if ( ! wasShadowed )
drawShadow ( ) ;
}
else {
if ( wasShadowed ) {
removeShadow ( ) ;
if ( ! activeOpacityCache . isNull ( ) )
activeOpacityCache . resize ( 0 ) ;
if ( ! inactiveOpacityCache . isNull ( ) )
inactiveOpacityCache . resize ( 0 ) ;
}
}
}
void Client : : updateOpacityCache ( )
{
if ( ! activeOpacityCache . isNull ( ) )
activeOpacityCache . resize ( 0 ) ;
if ( ! inactiveOpacityCache . isNull ( ) )
inactiveOpacityCache . resize ( 0 ) ;
if ( ! moveResizeMode ) {
// If the user is manually resizing, let Client::finishMoveResize()
// decide when to redraw the shadow
removeShadow ( ) ;
drawIntersectingShadows ( ) ;
if ( options - > shadowEnabled ( isActive ( ) ) )
drawDelayedShadow ( ) ;
}
}
/*!
Redraw shadows that were previously occluding or occluded by this window ,
to avoid visual glitches .
*/
void Client : : drawIntersectingShadows ( ) {
//Client *reshadowClient;
TQRegion region ;
//TQPtrList<Client> reshadowClients;
TQValueList < Client * > reshadowClients ;
TQValueListIterator < ShadowRegion > it ;
TQValueListIterator < Client * > it2 ;
if ( ! options - > shadowEnabled ( false ) )
// No point in redrawing overlapping/overlapped shadows if only the
// active window has a shadow.
return ;
region = shapeBoundingRegion ;
// Generate list of Clients whose shadows need to be redrawn. That is,
// those that are currently intersecting or intersected by other windows or
// shadows.
for ( it = shadowRegions . begin ( ) ; it ! = shadowRegions . end ( ) ; + + it )
if ( ( isOnAllDesktops ( ) | | ( * it ) . client - > isOnCurrentDesktop ( ) ) & &
! ( * it ) . region . intersect ( region ) . isEmpty ( ) )
reshadowClients . append ( ( * it ) . client ) ;
// Redraw shadows for each of the Clients in the list generated above
for ( it2 = reshadowClients . begin ( ) ; it2 ! = reshadowClients . end ( ) ;
+ + it2 ) {
( * it2 ) - > removeShadow ( ) ;
( * it2 ) - > drawDelayedShadow ( ) ;
}
}
/*!
Redraw shadows that are above the current window in the stacking order .
Furthermore , redraw them in the same order as they come in the stacking order
from bottom to top .
*/
void Client : : drawOverlappingShadows ( bool waitForMe )
{
Client * aClient ;
TQRegion region ;
TQValueList < Client * > reshadowClients ;
ClientList stacking_order ;
ClientList : : ConstIterator it ;
TQValueListIterator < ShadowRegion > it2 ;
TQValueListIterator < Client * > it3 ;
if ( ! options - > shadowEnabled ( false ) )
// No point in redrawing overlapping/overlapped shadows if only the
// active window has a shadow.
return ;
region = shapeBoundingRegion ;
stacking_order = workspace ( ) - > stackingOrder ( ) ;
for ( it = stacking_order . fromLast ( ) ; it ! = stacking_order . end ( ) ; - - it ) {
// Find the position of this window in the stacking order.
if ( ( * it ) = = this )
break ;
}
+ + it ;
while ( it ! = stacking_order . end ( ) ) {
if ( ( * it ) - > windowType ( ) = = NET : : Dock ) {
// This function is only interested in windows whose shadows don't
// have weird stacking rules.
+ + it ;
continue ;
}
// Generate list of Clients whose shadows need to be redrawn. That is,
// those that are currently overlapping or overlapped by other windows
// or shadows. The list should be in order from bottom to top in the
// stacking order.
for ( it2 = shadowRegions . begin ( ) ; it2 ! = shadowRegions . end ( ) ; + + it2 ) {
if ( ( * it2 ) . client = = ( * it ) ) {
if ( ( isOnAllDesktops ( ) | | ( * it2 ) . client - > isOnCurrentDesktop ( ) )
& & ! ( * it2 ) . region . intersect ( region ) . isEmpty ( ) )
reshadowClients . append ( ( * it2 ) . client ) ;
}
}
+ + it ;
}
// Redraw shadows for each of the Clients in the list generated above
for ( it3 = reshadowClients . begin ( ) ; it3 ! = reshadowClients . end ( ) ; + + it3 ) {
( * it3 ) - > removeShadow ( ) ;
if ( it3 = = reshadowClients . begin ( ) ) {
if ( waitForMe )
( * it3 ) - > drawShadowAfter ( this ) ;
else
( * it3 ) - > drawDelayedShadow ( ) ;
}
else {
- - it3 ;
aClient = ( * it3 ) ;
+ + it3 ;
( * it3 ) - > drawShadowAfter ( aClient ) ;
}
}
}
/*!
Draw shadow after some time has elapsed , to give recently exposed windows a
chance to repaint before a shadow gradient is drawn over them .
*/
void Client : : drawDelayedShadow ( )
{
shadowDelayTimer - > stop ( ) ;
shadowDelayTimer - > start ( SHADOW_DELAY , true ) ;
}
/*!
Draw shadow immediately after the specified Client ' s shadow finishes drawing .
*/
void Client : : drawShadowAfter ( Client * after )
{
shadowAfterClient = after ;
connect ( after , TQT_SIGNAL ( shadowDrawn ( ) ) , TQT_SLOT ( drawShadow ( ) ) ) ;
}
/*!
Draw a shadow under this window and XShape the shadow accordingly .
*/
void Client : : drawShadow ( )
{
Window shadows [ 2 ] ;
XRectangle * shapes ;
int i , count , ordering ;
// If we are waiting for another Client's shadow to be drawn, stop waiting now
if ( shadowAfterClient ! = NULL ) {
disconnect ( shadowAfterClient , TQT_SIGNAL ( shadowDrawn ( ) ) , this , TQT_SLOT ( drawShadow ( ) ) ) ;
shadowAfterClient = NULL ;
}
if ( ! isOnCurrentDesktop ( ) )
return ;
/* Store this window's ShapeBoundingRegion even if shadows aren't drawn for
* this type of window . Otherwise , drawIntersectingShadows ( ) won ' t update
* properly when this window is moved / resized / hidden / closed .
*/
shapes = XShapeGetRectangles ( tqt_xdisplay ( ) , frameId ( ) , ShapeBounding ,
& count , & ordering ) ;
if ( ! shapes )
// XShape extension not supported
shapeBoundingRegion = TQRegion ( x ( ) , y ( ) , width ( ) , height ( ) ) ;
else {
shapeBoundingRegion = TQRegion ( ) ;
for ( i = 0 ; i < count ; i + + ) {
// Translate XShaped window into a TQRegion
TQRegion shapeRectangle ( shapes [ i ] . x , shapes [ i ] . y , shapes [ i ] . width ,
shapes [ i ] . height ) ;
shapeBoundingRegion + = shapeRectangle ;
}
if ( isShade ( ) )
// Since XResize() doesn't change a window's XShape regions, ensure that
// shapeBoundingRegion is not taller than the window's shaded height,
// or the bottom shadow will appear to be missing
shapeBoundingRegion & = TQRegion ( 0 , 0 , width ( ) , height ( ) ) ;
shapeBoundingRegion . translate ( x ( ) , y ( ) ) ;
}
if ( ! isShadowed ( ) | | hidden | | isMinimized ( ) | |
maximizeMode ( ) = = MaximizeFull | |
! options - > shadowWindowType ( windowType ( ) ) ) {
XFree ( shapes ) ;
// Tell whatever Clients are listening that this Client's shadow has been drawn.
// It hasn't, but there's no sense waiting for something that won't happen.
emit shadowDrawn ( ) ;
return ;
}
removeShadow ( ) ;
TQMemArray < TQRgb > pixelData ;
TQPixmap shadowPixmap ;
TQRect shadow ;
TQRegion exposedRegion ;
ShadowRegion shadowRegion ;
int thickness , xOffset , yOffset ;
thickness = options - > shadowThickness ( isActive ( ) ) ;
xOffset = options - > shadowXOffset ( isActive ( ) ) ;
yOffset = options - > shadowYOffset ( isActive ( ) ) ;
opacityCache = active ? & activeOpacityCache : & inactiveOpacityCache ;
shadow . setRect ( x ( ) - thickness + xOffset , y ( ) - thickness + yOffset ,
width ( ) + thickness * 2 , height ( ) + thickness * 2 ) ;
shadowPixmap . resize ( shadow . size ( ) ) ;
// Create a fake drop-down shadow effect via blended Xwindows
shadowWidget = new TQWidget ( 0 , 0 , ( WFlags ) ( WStyle_Customize | WX11BypassWM ) ) ;
shadowWidget - > setGeometry ( shadow ) ;
XSelectInput ( tqt_xdisplay ( ) , shadowWidget - > winId ( ) ,
ButtonPressMask | ButtonReleaseMask | StructureNotifyMask ) ;
shadowWidget - > installEventFilter ( this ) ;
if ( ! shapes ) {
// XShape extension not supported
exposedRegion = getExposedRegion ( shapeBoundingRegion , shadow . x ( ) ,
shadow . y ( ) , shadow . width ( ) , shadow . height ( ) , thickness ,
xOffset , yOffset ) ;
shadowRegion . region = exposedRegion ;
shadowRegion . client = this ;
shadowRegions . append ( shadowRegion ) ;
if ( opacityCache - > isNull ( ) )
imposeRegionShadow ( shadowPixmap , shapeBoundingRegion ,
exposedRegion , thickness ,
options - > shadowOpacity ( isActive ( ) ) ) ;
else
imposeCachedShadow ( shadowPixmap , exposedRegion ) ;
}
else {
TQMemArray < TQRect > exposedRects ;
TQMemArray < TQRect > : : Iterator it , itEnd ;
XRectangle * shadowShapes ;
exposedRegion = getExposedRegion ( shapeBoundingRegion , shadow . x ( ) ,
shadow . y ( ) , shadow . width ( ) , shadow . height ( ) , thickness ,
xOffset , yOffset ) ;
shadowRegion . region = exposedRegion ;
shadowRegion . client = this ;
shadowRegions . append ( shadowRegion ) ;
// XShape the shadow
exposedRects = exposedRegion . rects ( ) ;
i = 0 ;
itEnd = exposedRects . end ( ) ;
shadowShapes = new XRectangle [ exposedRects . count ( ) ] ;
for ( it = exposedRects . begin ( ) ; it ! = itEnd ; + + it ) {
shadowShapes [ i ] . x = ( * it ) . x ( ) ;
shadowShapes [ i ] . y = ( * it ) . y ( ) ;
shadowShapes [ i ] . width = ( * it ) . width ( ) ;
shadowShapes [ i ] . height = ( * it ) . height ( ) ;
i + + ;
}
XShapeCombineRectangles ( tqt_xdisplay ( ) , shadowWidget - > winId ( ) ,
ShapeBounding , - x ( ) + thickness - xOffset ,
- y ( ) + thickness - yOffset , shadowShapes , i , ShapeSet ,
Unsorted ) ;
delete [ ] shadowShapes ;
if ( opacityCache - > isNull ( ) )
imposeRegionShadow ( shadowPixmap , shapeBoundingRegion ,
exposedRegion , thickness ,
options - > shadowOpacity ( isActive ( ) ) ) ;
else
imposeCachedShadow ( shadowPixmap , exposedRegion ) ;
}
XFree ( shapes ) ;
// Set the background pixmap
//shadowPixmap.convertFromImage(shadowImage);
shadowWidget - > setErasePixmap ( shadowPixmap ) ;
// Restack shadows under this window so that shadows drawn for a newly
// focused (but not raised) window don't overlap any windows above it.
if ( isDock ( ) ) {
ClientList stacking_order = workspace ( ) - > stackingOrder ( ) ;
for ( ClientList : : ConstIterator it = stacking_order . begin ( ) ; it ! = stacking_order . end ( ) ; + + it )
if ( ( * it ) - > isDesktop ( ) )
{
+ + it ;
shadows [ 0 ] = ( * it ) - > frameId ( ) ;
shadows [ 1 ] = shadowWidget - > winId ( ) ;
}
}
else {
shadows [ 0 ] = frameId ( ) ;
if ( shadowWidget ! = NULL )
shadows [ 1 ] = shadowWidget - > winId ( ) ;
}
XRestackWindows ( tqt_xdisplay ( ) , shadows , 2 ) ;
// Don't use TQWidget::show() so we don't confuse QEffects, thus causing
// broken focus.
XMapWindow ( tqt_xdisplay ( ) , shadowWidget - > winId ( ) ) ;
// Tell whatever Clients are listening that this Client's shadow has been drawn.
emit shadowDrawn ( ) ;
}
/*!
Remove shadow under this window .
*/
void Client : : removeShadow ( )
{
TQValueList < ShadowRegion > : : Iterator it ;
shadowDelayTimer - > stop ( ) ;
if ( shadowWidget ! = NULL ) {
for ( it = shadowRegions . begin ( ) ; it ! = shadowRegions . end ( ) ; + + it )
if ( ( * it ) . client = = this ) {
shadowRegions . remove ( it ) ;
break ;
}
delete shadowWidget ;
shadowWidget = NULL ;
}
}
/*!
Calculate regions in which the shadow will be visible given the window ' s
origin , height and width and the shadow ' s thickness , and X - and Y - offsets .
*/
TQRegion Client : : getExposedRegion ( TQRegion occludedRegion , int x , int y , int w ,
int h , int thickness , int xOffset , int yOffset )
{
TQRegion exposedRegion ;
exposedRegion = TQRegion ( x , y , w , h ) ;
exposedRegion - = occludedRegion ;
if ( thickness > 0 ) {
// Limit exposedRegion to include only where a shadow of the specified
// thickness will be drawn
TQMemArray < TQRect > occludedRects ;
TQMemArray < TQRect > : : Iterator it , itEnd ;
TQRegion shadowRegion ;
occludedRects = occludedRegion . rects ( ) ;
itEnd = occludedRects . end ( ) ;
for ( it = occludedRects . begin ( ) ; it ! = itEnd ; + + it ) {
// Expand each of the occluded region's shape rectangles to contain
// where a shadow of the specified thickness will be drawn. Create
// a new TQRegion that contains the expanded occluded region
it - > setTop ( it - > top ( ) - thickness + yOffset ) ;
it - > setLeft ( it - > left ( ) - thickness + xOffset ) ;
it - > setRight ( it - > right ( ) + thickness + xOffset ) ;
it - > setBottom ( it - > bottom ( ) + thickness + yOffset ) ;
shadowRegion + = TQRegion ( * it ) ;
}
exposedRegion - = exposedRegion - shadowRegion ;
}
return exposedRegion ;
}
/*!
Draw shadow gradient around this window using cached opacity values .
*/
void Client : : imposeCachedShadow ( TQPixmap & pixmap , TQRegion exposed )
{
TQRgb pixel ;
double opacity ;
int red , green , blue , pixelRed , pixelGreen , pixelBlue ;
int subW , subH , w , x , y , zeroX , zeroY ;
TQImage image ;
TQMemArray < TQRect > : : Iterator it , itEnd ;
TQMemArray < TQRect > rectangles ;
TQPixmap subPixmap ;
Window rootWindow ;
int thickness , windowX , windowY , xOffset , yOffset ;
rectangles = exposed . rects ( ) ;
rootWindow = tqt_xrootwin ( ) ;
thickness = options - > shadowThickness ( isActive ( ) ) ;
windowX = this - > x ( ) ;
windowY = this - > y ( ) ;
xOffset = options - > shadowXOffset ( isActive ( ) ) ;
yOffset = options - > shadowYOffset ( isActive ( ) ) ;
options - > shadowColour ( isActive ( ) ) . rgb ( & red , & green , & blue ) ;
w = pixmap . width ( ) ;
itEnd = rectangles . end ( ) ;
for ( it = rectangles . begin ( ) ; it ! = itEnd ; + + it ) {
subW = ( * it ) . width ( ) ;
subH = ( * it ) . height ( ) ;
subPixmap = TQPixmap : : grabWindow ( rootWindow , ( * it ) . x ( ) , ( * it ) . y ( ) ,
subW , subH ) ;
zeroX = ( * it ) . x ( ) - windowX + thickness - xOffset ;
zeroY = ( * it ) . y ( ) - windowY + thickness - yOffset ;
image = subPixmap . convertToImage ( ) ;
for ( x = 0 ; x < subW ; x + + ) {
for ( y = 0 ; y < subH ; y + + ) {
opacity = ( * ( opacityCache ) ) [ ( zeroY + y ) * w + zeroX + x ] ;
pixel = image . pixel ( x , y ) ;
pixelRed = tqRed ( pixel ) ;
pixelGreen = tqGreen ( pixel ) ;
pixelBlue = tqBlue ( pixel ) ;
image . setPixel ( x , y ,
tqRgb ( ( int ) ( pixelRed + ( red - pixelRed ) * opacity ) ,
( int ) ( pixelGreen + ( green - pixelGreen ) * opacity ) ,
( int ) ( pixelBlue + ( blue - pixelBlue ) * opacity ) ) ) ;
}
}
subPixmap . convertFromImage ( image ) ;
bitBlt ( & pixmap , zeroX , zeroY , & subPixmap ) ;
}
}
/*!
Draw shadow around this window using calculated opacity values .
*/
void Client : : imposeRegionShadow ( TQPixmap & pixmap , TQRegion occluded ,
TQRegion exposed , int thickness , double maxOpacity )
{
int distance , intersectCount , i , j , x , y ;
TQRgb pixel ;
double decay , factor , opacity ;
int red , green , blue , pixelRed , pixelGreen , pixelBlue ;
int lineIntersects , maxIntersects , maxY ;
int irBottom , irLeft , irRight , irTop , yIncrement ;
int subW , subH , w , h , zeroX , zeroY ;
TQImage image ;
TQMemArray < TQRect > : : Iterator it , itEnd ;
TQMemArray < TQRect > rectangles ;
TQPixmap subPixmap ;
Window rootWindow ;
int windowX , windowY , xOffset , yOffset ;
rectangles = exposed . rects ( ) ;
rootWindow = tqt_xrootwin ( ) ;
windowX = this - > x ( ) ;
windowY = this - > y ( ) ;
xOffset = options - > shadowXOffset ( isActive ( ) ) ;
yOffset = options - > shadowYOffset ( isActive ( ) ) ;
options - > shadowColour ( isActive ( ) ) . rgb ( & red , & green , & blue ) ;
maxIntersects = thickness * thickness * 4 + ( thickness * 4 ) + 1 ;
lineIntersects = thickness * 2 + 1 ;
factor = maxIntersects / maxOpacity ;
decay = ( lineIntersects / 0.0125 - factor ) / pow ( ( double ) maxIntersects , 3.0 ) ;
w = pixmap . width ( ) ;
h = pixmap . height ( ) ;
xOffset = options - > shadowXOffset ( isActive ( ) ) ;
yOffset = options - > shadowYOffset ( isActive ( ) ) ;
opacityCache - > resize ( 0 ) ;
opacityCache - > resize ( w * h ) ;
occluded . translate ( - windowX + thickness , - windowY + thickness ) ;
itEnd = rectangles . end ( ) ;
for ( it = rectangles . begin ( ) ; it ! = itEnd ; + + it ) {
subW = ( * it ) . width ( ) ;
subH = ( * it ) . height ( ) ;
subPixmap = TQPixmap : : grabWindow ( rootWindow , ( * it ) . x ( ) , ( * it ) . y ( ) ,
subW , subH ) ;
maxY = subH ;
zeroX = ( * it ) . x ( ) - windowX + thickness - xOffset ;
zeroY = ( * it ) . y ( ) - windowY + thickness - yOffset ;
image = subPixmap . convertToImage ( ) ;
intersectCount = 0 ;
opacity = - 1 ;
y = 0 ;
yIncrement = 1 ;
for ( x = 0 ; x < subW ; x + + ) {
irLeft = zeroX + x - thickness ;
irRight = zeroX + x + thickness ;
while ( y ! = maxY ) {
// horizontal row about to leave the intersect region, not
// necessarily the top row
irTop = zeroY + y - thickness * yIncrement ;
// horizontal row that just came into the intersect region,
// not necessarily the bottom row
irBottom = zeroY + y + thickness * yIncrement ;
if ( opacity = = - 1 ) {
// If occluded pixels caused an intersect count to be
// skipped, recount it
intersectCount = 0 ;
for ( j = irTop ; j ! = irBottom ; j + = yIncrement ) {
// irTop is not necessarily larger than irBottom and
// yIncrement isn't necessarily positive
for ( i = irLeft ; i < = irRight ; i + + ) {
if ( occluded . contains ( TQPoint ( i , j ) ) )
intersectCount + + ;
}
}
}
else {
if ( intersectCount < 0 )
intersectCount = 0 ;
for ( i = irLeft ; i < = irRight ; i + + ) {
if ( occluded . contains ( TQPoint ( i , irBottom ) ) )
intersectCount + + ;
}
}
distance = maxIntersects - intersectCount ;
opacity = intersectCount / ( factor + pow ( ( double ) distance , 3.0 ) * decay ) ;
( * ( opacityCache ) ) [ ( zeroY + y ) * w + zeroX + x ] = opacity ;
pixel = image . pixel ( x , y ) ;
pixelRed = tqRed ( pixel ) ;
pixelGreen = tqGreen ( pixel ) ;
pixelBlue = tqBlue ( pixel ) ;
image . setPixel ( x , y ,
tqRgb ( ( int ) ( pixelRed + ( red - pixelRed ) * opacity ) ,
( int ) ( pixelGreen + ( green - pixelGreen ) * opacity ) ,
( int ) ( pixelBlue + ( blue - pixelBlue ) * opacity ) ) ) ;
for ( i = irLeft ; i < = irRight ; i + + ) {
if ( occluded . contains ( TQPoint ( i , irTop ) ) )
intersectCount - - ;
}
y + = yIncrement ;
}
y - = yIncrement ;
irTop + = yIncrement ;
for ( j = irTop ; j ! = irBottom ; j + = yIncrement ) {
if ( occluded . contains ( TQPoint ( irLeft , j ) ) )
intersectCount - - ;
}
irRight + + ;
for ( j = irTop ; j ! = irBottom ; j + = yIncrement ) {
if ( occluded . contains ( TQPoint ( irRight , j ) ) )
intersectCount + + ;
}
yIncrement * = - 1 ;
if ( yIncrement < 0 )
// Scan Y-axis bottom-up for next X-coordinate iteration
maxY = - 1 ;
else
// Scan Y-axis top-down for next X-coordinate iteration
maxY = subH ;
}
subPixmap . convertFromImage ( image ) ;
bitBlt ( & pixmap , zeroX , zeroY , & subPixmap ) ;
}
}
/*!
Sets the client window ' s mapping state . Possible values are
WithdrawnState , IconicState , NormalState .
*/
void Client : : setMappingState ( int s )
{
assert ( client ! = None ) ;
assert ( ! deleting | | s = = WithdrawnState ) ;
if ( mapping_state = = s )
return ;
bool was_unmanaged = ( mapping_state = = WithdrawnState ) ;
mapping_state = s ;
if ( mapping_state = = WithdrawnState )
{
XDeleteProperty ( tqt_xdisplay ( ) , window ( ) , tqt_wm_state ) ;
return ;
}
assert ( s = = NormalState | | s = = IconicState ) ;
unsigned long data [ 2 ] ;
data [ 0 ] = ( unsigned long ) s ;
data [ 1 ] = ( unsigned long ) None ;
XChangeProperty ( tqt_xdisplay ( ) , window ( ) , tqt_wm_state , tqt_wm_state , 32 ,
PropModeReplace , ( unsigned char * ) data , 2 ) ;
if ( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
postponeGeometryUpdates ( false ) ;
}
/*!
Reimplemented to map the managed window in the window wrapper .
Proper mapping state should be set before showing the client .
*/
void Client : : rawShow ( )
{
if ( decoration ! = NULL )
decoration - > widget ( ) - > show ( ) ; // not really necessary, but let it know the state
XMapWindow ( tqt_xdisplay ( ) , frame ) ;
if ( ! isShade ( ) )
{
XMapWindow ( tqt_xdisplay ( ) , wrapper ) ;
XMapWindow ( tqt_xdisplay ( ) , client ) ;
}
if ( options - > shadowEnabled ( isActive ( ) ) )
drawDelayedShadow ( ) ;
}
/*!
Reimplemented to unmap the managed window in the window wrapper .
Also informs the workspace .
Proper mapping state should be set before hiding the client .
*/
void Client : : rawHide ( )
{
// Here it may look like a race condition, as some other client might try to unmap
// the window between these two XSelectInput() calls. However, they're supposed to
// use XWithdrawWindow(), which also sends a synthetic event to the root window,
// which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
// will be missed is also very minimal, so I don't think it's needed to grab the server
// here.
removeShadow ( ) ;
drawIntersectingShadows ( ) ;
XSelectInput ( tqt_xdisplay ( ) , wrapper , ClientWinMask ) ; // avoid getting UnmapNotify
XUnmapWindow ( tqt_xdisplay ( ) , frame ) ;
XUnmapWindow ( tqt_xdisplay ( ) , wrapper ) ;
XUnmapWindow ( tqt_xdisplay ( ) , client ) ;
XSelectInput ( tqt_xdisplay ( ) , wrapper , ClientWinMask | SubstructureNotifyMask ) ;
if ( decoration ! = NULL )
decoration - > widget ( ) - > hide ( ) ; // not really necessary, but let it know the state
workspace ( ) - > clientHidden ( this ) ;
}
void Client : : sendClientMessage ( Window w , Atom a , Atom protocol , long data1 , long data2 , long data3 )
{
XEvent ev ;
long mask ;
memset ( & ev , 0 , sizeof ( ev ) ) ;
ev . xclient . type = ClientMessage ;
ev . xclient . window = w ;
ev . xclient . message_type = a ;
ev . xclient . format = 32 ;
ev . xclient . data . l [ 0 ] = protocol ;
ev . xclient . data . l [ 1 ] = GET_QT_X_TIME ( ) ;
ev . xclient . data . l [ 2 ] = data1 ;
ev . xclient . data . l [ 3 ] = data2 ;
ev . xclient . data . l [ 4 ] = data3 ;
mask = 0L ;
if ( w = = tqt_xrootwin ( ) )
mask = SubstructureRedirectMask ; /* magic! */
XSendEvent ( tqt_xdisplay ( ) , w , False , mask , & ev ) ;
}
/*
Returns whether the window may be closed ( have a close button )
*/
bool Client : : isCloseable ( ) const
{
if ( isModalSystemNotification ( ) )
return false ;
return rules ( ) - > checkCloseable ( motif_may_close & & ! isSpecialWindow ( ) ) ;
}
/*!
Closes the window by either sending a delete_window message or
using XKill .
*/
void Client : : closeWindow ( )
{
if ( ! isCloseable ( ) )
return ;
// Update user time, because the window may create a confirming dialog.
updateUserTime ( ) ;
if ( Pdeletewindow )
{
Notify : : raise ( Notify : : Close ) ;
sendClientMessage ( window ( ) , atoms - > wm_protocols , atoms - > wm_delete_window ) ;
pingWindow ( ) ;
}
else
{
// client will not react on wm_delete_window. We have not choice
// but destroy his connection to the XServer.
killWindow ( ) ;
}
}
/*!
Kills the window via XKill
*/
void Client : : killWindow ( )
{
kdDebug ( 1212 ) < < " Client::killWindow(): " < < caption ( ) < < endl ;
// not sure if we need an Notify::Kill or not.. until then, use
// Notify::Close
Notify : : raise ( Notify : : Close ) ;
if ( isDialog ( ) )
Notify : : raise ( Notify : : TransDelete ) ;
if ( isNormalWindow ( ) )
Notify : : raise ( Notify : : Delete ) ;
killProcess ( false ) ;
// always kill this client at the server
XKillClient ( tqt_xdisplay ( ) , window ( ) ) ;
destroyClient ( ) ;
}
// send a ping to the window using _NET_WM_PING if possible
// if it doesn't respond within a reasonable time, it will be
// killed
void Client : : pingWindow ( )
{
if ( ! Pping )
return ; // can't ping :(
if ( options - > killPingTimeout = = 0 )
return ; // turned off
if ( ping_timer ! = NULL )
return ; // pinging already
ping_timer = new TQTimer ( this ) ;
connect ( ping_timer , TQT_SIGNAL ( timeout ( ) ) , TQT_SLOT ( pingTimeout ( ) ) ) ;
ping_timer - > start ( options - > killPingTimeout , true ) ;
ping_timestamp = GET_QT_X_TIME ( ) ;
workspace ( ) - > sendPingToWindow ( window ( ) , ping_timestamp ) ;
}
void Client : : gotPing ( Time timestamp )
{
// just plain compare is not good enough because of 64bit and truncating and whatnot
if ( NET : : timestampCompare ( timestamp , ping_timestamp ) ! = 0 )
return ;
delete ping_timer ;
ping_timer = NULL ;
if ( process_killer ! = NULL )
{
process_killer - > kill ( ) ;
delete process_killer ;
process_killer = NULL ;
}
}
void Client : : pingTimeout ( )
{
kdDebug ( 1212 ) < < " Ping timeout: " < < caption ( ) < < endl ;
delete ping_timer ;
ping_timer = NULL ;
killProcess ( true , ping_timestamp ) ;
}
void Client : : killProcess ( bool ask , Time timestamp )
{
if ( process_killer ! = NULL )
return ;
Q_ASSERT ( ! ask | | timestamp ! = CurrentTime ) ;
TQCString machine = wmClientMachine ( true ) ;
pid_t pid = info - > pid ( ) ;
if ( pid < = 0 | | machine . isEmpty ( ) ) // needed properties missing
return ;
kdDebug ( 1212 ) < < " Kill process: " < < pid < < " ( " < < machine < < " ) " < < endl ;
if ( ! ask )
{
if ( machine ! = " localhost " )
{
TDEProcess proc ;
proc < < " xon " < < machine < < " kill " < < pid ;
proc . start ( TDEProcess : : DontCare ) ;
}
else
: : kill ( pid , SIGTERM ) ;
}
else
{ // SELI TODO handle the window created by handler specially (on top,urgent?)
process_killer = new TDEProcess ( this ) ;
* process_killer < < TDEStandardDirs : : findExe ( " twin_killer_helper " )
< < " --pid " < < TQCString ( ) . setNum ( pid ) < < " --hostname " < < machine
< < " --windowname " < < caption ( ) . utf8 ( )
< < " --applicationname " < < resourceClass ( )
< < " --wid " < < TQCString ( ) . setNum ( window ( ) )
< < " --timestamp " < < TQCString ( ) . setNum ( timestamp ) ;
connect ( process_killer , TQT_SIGNAL ( processExited ( TDEProcess * ) ) ,
TQT_SLOT ( processKillerExited ( ) ) ) ;
if ( ! process_killer - > start ( TDEProcess : : NotifyOnExit ) )
{
delete process_killer ;
process_killer = NULL ;
return ;
}
}
}
bool Client : : isSuspendable ( ) const
{
bool cansuspend = true ;
if ( skipTaskbar ( ) | | skipPager ( ) )
return false ;
TQCString machine = wmClientMachine ( true ) ;
pid_t pid = info - > pid ( ) ;
if ( pid < = 0 | | machine . isEmpty ( ) ) // needed properties missing
return false ;
kdDebug ( 1212 ) < < " Check suspendable process: " < < pid < < " ( " < < machine < < " ) " < < endl ;
if ( machine ! = " localhost " )
{
return false ;
}
else
{
# ifdef Q_OS_SOLARIS
TQFile procStatFile ( TQString ( " /proc/%1/lwp/1/lwpsinfo " ) . arg ( pid ) ) ;
# else /* default */
TQFile procStatFile ( TQString ( " /proc/%1/stat " ) . arg ( pid ) ) ;
# endif
if ( procStatFile . open ( IO_ReadOnly ) )
{
TQByteArray statRaw = procStatFile . readAll ( ) ;
procStatFile . close ( ) ;
# ifdef Q_OS_SOLARIS
lwpsinfo_t * inf = ( lwpsinfo_t * ) statRaw . data ( ) ;
char tbuf [ PATH_MAX ] ;
TQString tcomm ;
TQString state ( TQChar ( inf - > pr_sname ) ) ;
readlink ( TQString ( " /proc/%1/path/a.out " ) . arg ( pid ) . latin1 ( ) ,
tbuf , sizeof ( tbuf ) ) ;
tcomm = basename ( tbuf ) ;
# else /* default */
TQString statString ( statRaw ) ;
TQStringList statFields = TQStringList : : split ( " " , statString , TRUE ) ;
TQString tcomm = statFields [ 1 ] ;
TQString state = statFields [ 2 ] ;
# endif /* default */
if ( state ! = " T " )
{
// Make sure no windows of this process are special
for ( ClientList : : ConstIterator it = workspace ( ) - > clients . begin ( ) ; it ! = workspace ( ) - > clients . end ( ) ; + + it )
{
Client * nextclient = * it ;
pid_t nextpid = nextclient - > info - > pid ( ) ;
TQCString nextmachine = nextclient - > wmClientMachine ( true ) ;
if ( nextpid > 0 & & ( ! nextmachine . isEmpty ( ) ) )
{
if ( ( nextmachine = = " localhost " ) & & ( pid = = nextpid ) )
{
if ( nextclient - > skipTaskbar ( ) | | nextclient - > skipPager ( ) )
cansuspend = false ;
}
}
}
// Process exception list
TQString execname ( tcomm ) ;
execname . truncate ( execname . length ( ) - 1 ) ;
execname = execname . remove ( 0 , 1 ) ;
// FIXME This list should not be hardcoded
if ( ( execname = = " kdesktop " ) | | ( execname = = " kicker " ) )
return false ;
else
return cansuspend ;
}
else
{
return false ;
}
}
else
{
return false ;
}
}
}
bool Client : : isResumeable ( ) const
{
TQCString machine = wmClientMachine ( true ) ;
pid_t pid = info - > pid ( ) ;
if ( pid < = 0 | | machine . isEmpty ( ) ) // needed properties missing
return false ;
kdDebug ( 1212 ) < < " Check resumeable process: " < < pid < < " ( " < < machine < < " ) " < < endl ;
if ( machine ! = " localhost " )
{
return false ;
}
else
{
# ifdef Q_OS_SOLARIS
TQFile procStatFile ( TQString ( " /proc/%1/lwp/1/lwpsinfo " ) . arg ( pid ) ) ;
# else /* default */
TQFile procStatFile ( TQString ( " /proc/%1/stat " ) . arg ( pid ) ) ;
# endif
if ( procStatFile . open ( IO_ReadOnly ) )
{
TQByteArray statRaw = procStatFile . readAll ( ) ;
procStatFile . close ( ) ;
# ifdef Q_OS_SOLARIS
lwpsinfo_t * inf = ( lwpsinfo_t * ) statRaw . data ( ) ;
TQString state ( TQChar ( inf - > pr_sname ) ) ;
# else /* default */
TQString statString ( statRaw ) ;
TQStringList statFields = TQStringList : : split ( " " , statString , TRUE ) ;
TQString tcomm = statFields [ 1 ] ;
TQString state = statFields [ 2 ] ;
# endif /* default */
if ( state = = " T " )
{
return true ;
}
else
{
return false ;
}
}
else
{
return false ;
}
}
}
bool Client : : queryUserSuspendedResume ( )
{
if ( isResumeable ( ) )
{
if ( process_resumer ! = NULL )
{
return false ;
}
// FIXME We should display a busy cursor until twin_resumer_helper loads
process_resumer = new TDEProcess ( this ) ;
* process_resumer < < TDEStandardDirs : : findExe ( " twin_resumer_helper " )
< < " --pid " < < TQCString ( ) . setNum ( info - > pid ( ) ) < < " --hostname " < < wmClientMachine ( true )
< < " --windowname " < < caption ( ) . utf8 ( )
< < " --applicationname " < < resourceClass ( )
< < " --wid " < < TQCString ( ) . setNum ( window ( ) ) ;
connect ( process_resumer , TQT_SIGNAL ( processExited ( TDEProcess * ) ) ,
TQT_SLOT ( processResumerExited ( ) ) ) ;
if ( ! process_resumer - > start ( TDEProcess : : NotifyOnExit ) )
{
delete process_resumer ;
process_resumer = NULL ;
return true ;
}
return false ;
}
else
{
return true ;
}
}
void Client : : suspendWindow ( )
{
TQCString machine = wmClientMachine ( true ) ;
pid_t pid = info - > pid ( ) ;
if ( pid < = 0 | | machine . isEmpty ( ) ) // needed properties missing
return ;
kdDebug ( 1212 ) < < " Suspend process: " < < pid < < " ( " < < machine < < " ) " < < endl ;
if ( machine ! = " localhost " )
{
return ;
}
else
{
for ( ClientList : : ConstIterator it = workspace ( ) - > clients . begin ( ) ; it ! = workspace ( ) - > clients . end ( ) ; + + it )
{
Client * nextclient = * it ;
pid_t nextpid = nextclient - > info - > pid ( ) ;
TQCString nextmachine = nextclient - > wmClientMachine ( true ) ;
if ( nextpid > 0 & & ( ! nextmachine . isEmpty ( ) ) )
{
if ( ( nextmachine = = " localhost " ) & & ( pid = = nextpid ) )
{
TQString newCaption = TQString ( readName ( ) ) . append ( " < " ) . append ( i18n ( " Suspended " ) ) . append ( " > " ) ;
nextclient - > info - > setVisibleName ( newCaption . utf8 ( ) ) ;
nextclient - > info - > setVisibleIconName ( newCaption . utf8 ( ) ) ;
nextclient - > minimized_before_suspend = nextclient - > isMinimized ( ) ;
nextclient - > minimize ( true ) ;
}
}
}
: : kill ( pid , SIGSTOP ) ;
}
}
void Client : : resumeWindow ( )
{
TQCString machine = wmClientMachine ( true ) ;
pid_t pid = info - > pid ( ) ;
if ( pid < = 0 | | machine . isEmpty ( ) ) // needed properties missing
return ;
kdDebug ( 1212 ) < < " Resume process: " < < pid < < " ( " < < machine < < " ) " < < endl ;
if ( machine ! = " localhost " )
{
return ;
}
else
{
: : kill ( pid , SIGCONT ) ;
for ( ClientList : : ConstIterator it = workspace ( ) - > clients . begin ( ) ; it ! = workspace ( ) - > clients . end ( ) ; + + it )
{
Client * nextclient = * it ;
pid_t nextpid = nextclient - > info - > pid ( ) ;
TQCString nextmachine = nextclient - > wmClientMachine ( true ) ;
if ( nextpid > 0 & & ( ! nextmachine . isEmpty ( ) ) )
{
if ( ( nextmachine = = " localhost " ) & & ( pid = = nextpid ) )
{
if ( ! nextclient - > minimized_before_suspend )
{
nextclient - > unminimize ( true ) ;
}
nextclient - > updateCaption ( ) ;
}
}
}
}
}
void Client : : processKillerExited ( )
{
kdDebug ( 1212 ) < < " Killer exited " < < endl ;
delete process_killer ;
process_killer = NULL ;
}
void Client : : processResumerExited ( )
{
kdDebug ( 1212 ) < < " Resumer exited " < < endl ;
// 0 means the user clicked Resume; 2 means that the resumer dialog failed to launch somehow
if ( ( process_resumer - > exitStatus ( ) = = 0 ) | | ( process_resumer - > exitStatus ( ) = = 2 ) )
{
resumeWindow ( ) ;
takeFocus ( Allowed ) ;
}
delete process_resumer ;
process_resumer = NULL ;
}
void Client : : setSkipTaskbar ( bool b , bool from_outside )
{
int was_wants_tab_focus = wantsTabFocus ( ) ;
if ( from_outside )
{
b = rules ( ) - > checkSkipTaskbar ( b ) ;
original_skip_taskbar = b ;
}
if ( b = = skipTaskbar ( ) )
return ;
skip_taskbar = b ;
info - > setState ( b ? NET : : SkipTaskbar : 0 , NET : : SkipTaskbar ) ;
updateWindowRules ( ) ;
if ( was_wants_tab_focus ! = wantsTabFocus ( ) )
workspace ( ) - > updateFocusChains ( this ,
isActive ( ) ? Workspace : : FocusChainMakeFirst : Workspace : : FocusChainUpdate ) ;
}
void Client : : setSkipPager ( bool b )
{
b = rules ( ) - > checkSkipPager ( b ) ;
if ( b = = skipPager ( ) )
return ;
skip_pager = b ;
info - > setState ( b ? NET : : SkipPager : 0 , NET : : SkipPager ) ;
updateWindowRules ( ) ;
}
void Client : : setModal ( bool m )
{ // Qt-3.2 can have even modal normal windows :(
if ( modal = = m )
return ;
modal = m ;
if ( ! modal )
return ;
// changing modality for a mapped window is weird (?)
// _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
}
void Client : : setDesktop ( int desktop )
{
if ( desktop ! = NET : : OnAllDesktops ) // do range check
desktop = KMAX ( 1 , KMIN ( workspace ( ) - > numberOfDesktops ( ) , desktop ) ) ;
desktop = rules ( ) - > checkDesktop ( desktop ) ;
if ( desk = = desktop )
return ;
int was_desk = desk ;
desk = desktop ;
info - > setDesktop ( desktop ) ;
if ( ( was_desk = = NET : : OnAllDesktops ) ! = ( desktop = = NET : : OnAllDesktops ) )
{ // onAllDesktops changed
if ( isShown ( true ) )
Notify : : raise ( isOnAllDesktops ( ) ? Notify : : OnAllDesktops : Notify : : NotOnAllDesktops ) ;
workspace ( ) - > updateOnAllDesktopsOfTransients ( this ) ;
}
if ( decoration ! = NULL )
decoration - > desktopChange ( ) ;
workspace ( ) - > updateFocusChains ( this , Workspace : : FocusChainMakeFirst ) ;
updateVisibility ( ) ;
updateWindowRules ( ) ;
}
void Client : : setOnAllDesktops ( bool b )
{
if ( ( b & & isOnAllDesktops ( ) )
| | ( ! b & & ! isOnAllDesktops ( ) ) )
return ;
if ( b )
setDesktop ( NET : : OnAllDesktops ) ;
else
setDesktop ( workspace ( ) - > currentDesktop ( ) ) ;
}
bool Client : : isOnCurrentDesktop ( ) const
{
return isOnDesktop ( workspace ( ) - > currentDesktop ( ) ) ;
}
int Client : : screen ( ) const
{
if ( ! options - > xineramaEnabled )
return 0 ;
return workspace ( ) - > screenNumber ( geometry ( ) . center ( ) ) ;
}
bool Client : : isOnScreen ( int screen ) const
{
if ( ! options - > xineramaEnabled )
return screen = = 0 ;
return workspace ( ) - > screenGeometry ( screen ) . intersects ( geometry ( ) ) ;
}
// performs activation and/or raising of the window
void Client : : takeActivity ( int flags , bool handled , allowed_t )
{
if ( ! handled | | ! Ptakeactivity )
{
if ( flags & ActivityFocus )
takeFocus ( Allowed ) ;
if ( flags & ActivityRaise )
workspace ( ) - > raiseClient ( this ) ;
return ;
}
# ifndef NDEBUG
static Time previous_activity_timestamp ;
static Client * previous_client ;
if ( previous_activity_timestamp = = GET_QT_X_TIME ( ) & & previous_client ! = this )
{
kdDebug ( 1212 ) < < " Repeated use of the same X timestamp for activity " < < endl ;
kdDebug ( 1212 ) < < kdBacktrace ( ) < < endl ;
}
previous_activity_timestamp = GET_QT_X_TIME ( ) ;
previous_client = this ;
# endif
workspace ( ) - > sendTakeActivity ( this , GET_QT_X_TIME ( ) , flags ) ;
}
// performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
void Client : : takeFocus ( allowed_t )
{
# ifndef NDEBUG
static Time previous_focus_timestamp ;
static Client * previous_client ;
if ( previous_focus_timestamp = = GET_QT_X_TIME ( ) & & previous_client ! = this )
{
kdDebug ( 1212 ) < < " Repeated use of the same X timestamp for focus " < < endl ;
kdDebug ( 1212 ) < < kdBacktrace ( ) < < endl ;
}
previous_focus_timestamp = GET_QT_X_TIME ( ) ;
previous_client = this ;
# endif
if ( rules ( ) - > checkAcceptFocus ( input ) )
{
XSetInputFocus ( tqt_xdisplay ( ) , window ( ) , RevertToPointerRoot , GET_QT_X_TIME ( ) ) ;
// Work around opacity bug
bool activePrev = active ;
active = true ;
updateOpacity ( ) ;
active = activePrev ;
}
if ( Ptakefocus )
{
sendClientMessage ( window ( ) , atoms - > wm_protocols , atoms - > wm_take_focus ) ;
}
workspace ( ) - > setShouldGetFocus ( this ) ;
}
/*!
Returns whether the window provides context help or not . If it does ,
you should show a help menu item or a help button like ' ? ' and call
contextHelp ( ) if this is invoked .
\ sa contextHelp ( )
*/
bool Client : : providesContextHelp ( ) const
{
if ( isModalSystemNotification ( ) )
return false ;
return Pcontexthelp ;
}
/*!
Invokes context help on the window . Only works if the window
actually provides context help .
\ sa providesContextHelp ( )
*/
void Client : : showContextHelp ( )
{
if ( Pcontexthelp )
{
sendClientMessage ( window ( ) , atoms - > wm_protocols , atoms - > net_wm_context_help ) ;
TQWhatsThis : : enterWhatsThisMode ( ) ; // SELI?
}
}
/*!
Fetches the window ' s caption ( WM_NAME property ) . It will be
stored in the client ' s caption ( ) .
*/
void Client : : fetchName ( )
{
setCaption ( readName ( ) ) ;
}
TQString Client : : readName ( ) const
{
if ( info - > name ( ) & & info - > name ( ) [ 0 ] ! = ' \0 ' )
return TQString : : fromUtf8 ( info - > name ( ) ) ;
else
return KWin : : readNameProperty ( window ( ) , XA_WM_NAME ) ;
}
KWIN_COMPARE_PREDICATE ( FetchNameInternalPredicate , const Client * , ( ! cl - > isSpecialWindow ( ) | | cl - > isToolbar ( ) ) & & cl ! = value & & cl - > caption ( ) = = value - > caption ( ) ) ;
void Client : : setCaption ( const TQString & s , bool force )
{
if ( s ! = cap_normal | | force )
{
bool reset_name = force ;
for ( unsigned int i = 0 ;
i < s . length ( ) ;
+ + i )
if ( ! s [ i ] . isPrint ( ) )
s [ i ] = ' ' ;
cap_normal = s ;
bool was_suffix = ( ! cap_suffix . isEmpty ( ) ) ;
TQString machine_suffix ;
if ( wmClientMachine ( false ) ! = " localhost " & & ! isLocalMachine ( wmClientMachine ( false ) ) )
machine_suffix = " <@ " + wmClientMachine ( true ) + " > " ;
TQString shortcut_suffix = ! shortcut ( ) . isNull ( ) ? ( " { " + shortcut ( ) . toString ( ) + " } " ) : " " ;
cap_suffix = machine_suffix + shortcut_suffix ;
if ( ( ! isSpecialWindow ( ) | | isToolbar ( ) ) & & workspace ( ) - > findClient ( FetchNameInternalPredicate ( this ) ) )
{
int i = 2 ;
do
{
cap_suffix = machine_suffix + " < " + TQString : : number ( i ) + " > " + shortcut_suffix ;
i + + ;
} while ( workspace ( ) - > findClient ( FetchNameInternalPredicate ( this ) ) ) ;
info - > setVisibleName ( caption ( ) . utf8 ( ) ) ;
reset_name = false ;
}
if ( ( ( was_suffix & & cap_suffix . isEmpty ( ) )
| | reset_name ) ) // if it was new window, it may have old value still set, if the window is reused
{
info - > setVisibleName ( " " ) ; // remove
info - > setVisibleIconName ( " " ) ; // remove
}
else if ( ! cap_suffix . isEmpty ( ) & & ! cap_iconic . isEmpty ( ) ) // keep the same suffix in iconic name if it's set
info - > setVisibleIconName ( ( cap_iconic + cap_suffix ) . utf8 ( ) ) ;
if ( isManaged ( ) & & decoration ! = NULL )
decoration - > captionChange ( ) ;
}
}
void Client : : updateCaption ( )
{
setCaption ( cap_normal , true ) ;
}
void Client : : fetchIconicName ( )
{
TQString s ;
if ( info - > iconName ( ) & & info - > iconName ( ) [ 0 ] ! = ' \0 ' )
s = TQString : : fromUtf8 ( info - > iconName ( ) ) ;
else
s = KWin : : readNameProperty ( window ( ) , XA_WM_ICON_NAME ) ;
if ( s ! = cap_iconic )
{
bool was_set = ! cap_iconic . isEmpty ( ) ;
cap_iconic = s ;
if ( ! cap_suffix . isEmpty ( ) )
{
if ( ! cap_iconic . isEmpty ( ) ) // keep the same suffix in iconic name if it's set
info - > setVisibleIconName ( ( s + cap_suffix ) . utf8 ( ) ) ;
else if ( was_set )
info - > setVisibleIconName ( " " ) ; //remove
}
}
}
/*!\reimp
*/
TQString Client : : caption ( bool full ) const
{
return full ? cap_normal + cap_suffix : cap_normal ;
}
void Client : : getWMHints ( )
{
XWMHints * hints = XGetWMHints ( tqt_xdisplay ( ) , window ( ) ) ;
input = true ;
window_group = None ;
urgency = false ;
if ( hints )
{
if ( hints - > flags & InputHint )
input = hints - > input ;
if ( hints - > flags & WindowGroupHint )
window_group = hints - > window_group ;
urgency = ( hints - > flags & UrgencyHint ) ? true : false ; // true/false needed, it's uint bitfield
XFree ( ( char * ) hints ) ;
}
checkGroup ( ) ;
updateUrgency ( ) ;
updateAllowedActions ( ) ; // group affects isMinimizable()
}
void Client : : getMotifHints ( )
{
bool mnoborder , mresize , mmove , mminimize , mmaximize , mclose ;
Motif : : readFlags ( client , mnoborder , mresize , mmove , mminimize , mmaximize , mclose ) ;
motif_noborder = mnoborder ;
if ( ! hasNETSupport ( ) ) // NETWM apps should set type and size constraints
{
motif_may_resize = mresize ; // this should be set using minsize==maxsize, but oh well
motif_may_move = mmove ;
}
else
motif_may_resize = motif_may_move = true ;
// mminimize; - ignore, bogus - e.g. shading or sending to another desktop is "minimizing" too
// mmaximize; - ignore, bogus - maximizing is basically just resizing
motif_may_close = mclose ; // motif apps like to crash when they set this hint and WM closes them anyway
if ( isManaged ( ) )
updateDecoration ( true ) ; // check if noborder state has changed
}
void Client : : readIcons ( Window win , TQPixmap * icon , TQPixmap * miniicon )
{
// get the icons, allow scaling
if ( icon ! = NULL )
* icon = KWin : : icon ( win , 32 , 32 , TRUE , KWin : : NETWM | KWin : : WMHints ) ;
if ( miniicon ! = NULL )
{
if ( icon = = NULL | | ! icon - > isNull ( ) )
* miniicon = KWin : : icon ( win , 16 , 16 , TRUE , KWin : : NETWM | KWin : : WMHints ) ;
else
* miniicon = TQPixmap ( ) ;
}
}
void Client : : getIcons ( )
{
// first read icons from the window itself
readIcons ( window ( ) , & icon_pix , & miniicon_pix ) ;
if ( icon_pix . isNull ( ) )
{ // then try window group
icon_pix = group ( ) - > icon ( ) ;
miniicon_pix = group ( ) - > miniIcon ( ) ;
}
if ( icon_pix . isNull ( ) & & isTransient ( ) )
{ // then mainclients
ClientList mainclients = mainClients ( ) ;
for ( ClientList : : ConstIterator it = mainclients . begin ( ) ;
it ! = mainclients . end ( ) & & icon_pix . isNull ( ) ;
+ + it )
{
icon_pix = ( * it ) - > icon ( ) ;
miniicon_pix = ( * it ) - > miniIcon ( ) ;
}
}
if ( icon_pix . isNull ( ) )
{ // and if nothing else, load icon from classhint or xapp icon
icon_pix = KWin : : icon ( window ( ) , 32 , 32 , TRUE , KWin : : ClassHint | KWin : : XApp ) ;
miniicon_pix = KWin : : icon ( window ( ) , 16 , 16 , TRUE , KWin : : ClassHint | KWin : : XApp ) ;
}
if ( isManaged ( ) & & decoration ! = NULL )
decoration - > iconChange ( ) ;
}
void Client : : getWindowProtocols ( )
{
Atom * p ;
int i , n ;
Pdeletewindow = 0 ;
Ptakefocus = 0 ;
Ptakeactivity = 0 ;
Pcontexthelp = 0 ;
Pping = 0 ;
if ( XGetWMProtocols ( tqt_xdisplay ( ) , window ( ) , & p , & n ) )
{
for ( i = 0 ; i < n ; i + + )
if ( p [ i ] = = atoms - > wm_delete_window )
Pdeletewindow = 1 ;
else if ( p [ i ] = = atoms - > wm_take_focus )
Ptakefocus = 1 ;
else if ( p [ i ] = = atoms - > net_wm_take_activity )
Ptakeactivity = 1 ;
else if ( p [ i ] = = atoms - > net_wm_context_help )
Pcontexthelp = 1 ;
else if ( p [ i ] = = atoms - > net_wm_ping )
Pping = 1 ;
if ( n > 0 )
XFree ( p ) ;
}
}
static int nullErrorHandler ( Display * , XErrorEvent * )
{
return 0 ;
}
/*!
Returns WM_WINDOW_ROLE property for a given window .
*/
TQCString Client : : staticWindowRole ( WId w )
{
return getStringProperty ( w , tqt_window_role ) . lower ( ) ;
}
/*!
Returns SM_CLIENT_ID property for a given window .
*/
TQCString Client : : staticSessionId ( WId w )
{
return getStringProperty ( w , tqt_sm_client_id ) ;
}
/*!
Returns WM_COMMAND property for a given window .
*/
TQCString Client : : staticWmCommand ( WId w )
{
return getStringProperty ( w , XA_WM_COMMAND , ' ' ) ;
}
/*!
Returns WM_CLIENT_LEADER property for a given window .
*/
Window Client : : staticWmClientLeader ( WId w )
{
Atom type ;
int format , status ;
unsigned long nitems = 0 ;
unsigned long extra = 0 ;
unsigned char * data = 0 ;
Window result = w ;
XErrorHandler oldHandler = XSetErrorHandler ( nullErrorHandler ) ;
status = XGetWindowProperty ( tqt_xdisplay ( ) , w , atoms - > wm_client_leader , 0 , 10000 ,
FALSE , XA_WINDOW , & type , & format ,
& nitems , & extra , & data ) ;
XSetErrorHandler ( oldHandler ) ;
if ( status = = Success )
{
if ( data & & nitems > 0 )
result = * ( ( Window * ) data ) ;
XFree ( data ) ;
}
return result ;
}
void Client : : getWmClientLeader ( )
{
wmClientLeaderWin = staticWmClientLeader ( window ( ) ) ;
}
/*!
Returns sessionId for this client ,
taken either from its window or from the leader window .
*/
TQCString Client : : sessionId ( )
{
TQCString result = staticSessionId ( window ( ) ) ;
if ( result . isEmpty ( ) & & wmClientLeaderWin & & wmClientLeaderWin ! = window ( ) )
result = staticSessionId ( wmClientLeaderWin ) ;
return result ;
}
/*!
Returns command property for this client ,
taken either from its window or from the leader window .
*/
TQCString Client : : wmCommand ( )
{
TQCString result = staticWmCommand ( window ( ) ) ;
if ( result . isEmpty ( ) & & wmClientLeaderWin & & wmClientLeaderWin ! = window ( ) )
result = staticWmCommand ( wmClientLeaderWin ) ;
return result ;
}
void Client : : getWmClientMachine ( )
{
client_machine = getStringProperty ( window ( ) , XA_WM_CLIENT_MACHINE ) ;
if ( client_machine . isEmpty ( ) & & wmClientLeaderWin & & wmClientLeaderWin ! = window ( ) )
client_machine = getStringProperty ( wmClientLeaderWin , XA_WM_CLIENT_MACHINE ) ;
if ( client_machine . isEmpty ( ) )
client_machine = " localhost " ;
}
/*!
Returns client machine for this client ,
taken either from its window or from the leader window .
*/
TQCString Client : : wmClientMachine ( bool use_localhost ) const
{
TQCString result = client_machine ;
if ( use_localhost )
{ // special name for the local machine (localhost)
if ( result ! = " localhost " & & isLocalMachine ( result ) )
result = " localhost " ;
}
return result ;
}
/*!
Returns client leader window for this client .
Returns the client window itself if no leader window is defined .
*/
Window Client : : wmClientLeader ( ) const
{
if ( wmClientLeaderWin )
return wmClientLeaderWin ;
return window ( ) ;
}
bool Client : : wantsTabFocus ( ) const
{
return ( isNormalWindow ( ) | | isDialog ( ) ) & & wantsInput ( ) & & ! skip_taskbar ;
}
bool Client : : wantsInput ( ) const
{
return rules ( ) - > checkAcceptFocus ( input | | Ptakefocus ) ;
}
bool Client : : isDesktop ( ) const
{
return windowType ( ) = = NET : : Desktop ;
}
bool Client : : isDock ( ) const
{
return windowType ( ) = = NET : : Dock ;
}
bool Client : : isTopMenu ( ) const
{
return windowType ( ) = = NET : : TopMenu ;
}
bool Client : : isMenu ( ) const
{
return windowType ( ) = = NET : : Menu & & ! isTopMenu ( ) ; // because of backwards comp.
}
bool Client : : isToolbar ( ) const
{
return windowType ( ) = = NET : : Toolbar ;
}
bool Client : : isSplash ( ) const
{
return windowType ( ) = = NET : : Splash ;
}
bool Client : : isUtility ( ) const
{
return windowType ( ) = = NET : : Utility ;
}
bool Client : : isDialog ( ) const
{
return windowType ( ) = = NET : : Dialog ;
}
bool Client : : isNormalWindow ( ) const
{
return windowType ( ) = = NET : : Normal ;
}
bool Client : : isSpecialWindow ( ) const
{
return isDesktop ( ) | | isDock ( ) | | isSplash ( ) | | isTopMenu ( )
| | isToolbar ( ) ; // TODO
}
NET : : WindowType Client : : windowType ( bool direct , int supported_types ) const
{
NET : : WindowType wt = info - > windowType ( supported_types ) ;
if ( direct )
return wt ;
NET : : WindowType wt2 = rules ( ) - > checkType ( wt ) ;
if ( wt ! = wt2 )
{
wt = wt2 ;
info - > setWindowType ( wt ) ; // force hint change
}
// hacks here
if ( wt = = NET : : Menu )
{
// ugly hack to support the times when NET::Menu meant NET::TopMenu
// if it's as wide as the screen, not very high and has its upper-left
// corner a bit above the screen's upper-left cornet, it's a topmenu
if ( x ( ) = = 0 & & y ( ) < 0 & & y ( ) > - 10 & & height ( ) < 100
& & abs ( width ( ) - workspace ( ) - > clientArea ( FullArea , this ) . width ( ) ) < 10 )
wt = NET : : TopMenu ;
}
// TODO change this to rule
const char * const oo_prefix = " openoffice.org " ; // TQCString has no startsWith()
// oo_prefix is lowercase, because resourceClass() is forced to be lowercase
if ( tqstrncmp ( resourceClass ( ) , oo_prefix , strlen ( oo_prefix ) ) = = 0 & & wt = = NET : : Dialog )
wt = NET : : Normal ; // see bug #66065
if ( wt = = NET : : Unknown ) // this is more or less suggested in NETWM spec
wt = isTransient ( ) ? NET : : Dialog : NET : : Normal ;
return wt ;
}
/*!
Sets an appropriate cursor shape for the logical mouse position \ a m
*/
void Client : : setCursor ( Position m )
{
if ( ! isResizable ( ) | | isShade ( ) )
{
m = PositionCenter ;
}
switch ( m )
{
case PositionTopLeft :
case PositionBottomRight :
setCursor ( tqsizeFDiagCursor ) ;
break ;
case PositionBottomLeft :
case PositionTopRight :
setCursor ( tqsizeBDiagCursor ) ;
break ;
case PositionTop :
case PositionBottom :
setCursor ( tqsizeVerCursor ) ;
break ;
case PositionLeft :
case PositionRight :
setCursor ( tqsizeHorCursor ) ;
break ;
default :
if ( buttonDown & & isMovable ( ) )
setCursor ( tqsizeAllCursor ) ;
else
setCursor ( tqarrowCursor ) ;
break ;
}
}
// TODO mit nejake checkCursor(), ktere se zavola v manage() a pri vecech, kdy by se kurzor mohl zmenit?
// TRANSLATION: TODO: have a checkCursor() function, which is called both in manage() and in cases where the cursor might change
void Client : : setCursor ( const TQCursor & c )
{
if ( c . handle ( ) = = cursor . handle ( ) )
return ;
cursor = c ;
if ( decoration ! = NULL )
decoration - > widget ( ) - > setCursor ( cursor ) ;
XDefineCursor ( tqt_xdisplay ( ) , frameId ( ) , cursor . handle ( ) ) ;
}
Client : : Position Client : : mousePosition ( const TQPoint & p ) const
{
if ( decoration ! = NULL )
return decoration - > mousePosition ( p ) ;
return PositionCenter ;
}
void Client : : updateAllowedActions ( bool force )
{
if ( ! isManaged ( ) & & ! force )
return ;
unsigned long old_allowed_actions = allowed_actions ;
allowed_actions = 0 ;
if ( isMovable ( ) )
allowed_actions | = NET : : ActionMove ;
if ( isResizable ( ) )
allowed_actions | = NET : : ActionResize ;
if ( isMinimizable ( ) )
allowed_actions | = NET : : ActionMinimize ;
if ( isShadeable ( ) )
allowed_actions | = NET : : ActionShade ;
// sticky state not supported
if ( isMaximizable ( ) )
allowed_actions | = NET : : ActionMax ;
if ( userCanSetFullScreen ( ) )
allowed_actions | = NET : : ActionFullScreen ;
allowed_actions | = NET : : ActionChangeDesktop ; // always (pagers shouldn't show Docks etc.)
if ( isCloseable ( ) )
allowed_actions | = NET : : ActionClose ;
if ( old_allowed_actions = = allowed_actions )
return ;
// TODO this could be delayed and compressed - it's only for pagers etc. anyway
info - > setAllowedActions ( allowed_actions ) ;
// TODO this should also tell the decoration, so that it can update the buttons
}
void Client : : autoRaise ( )
{
workspace ( ) - > raiseClient ( this ) ;
cancelAutoRaise ( ) ;
}
void Client : : cancelAutoRaise ( )
{
delete autoRaiseTimer ;
autoRaiseTimer = 0 ;
}
void Client : : setOpacity ( bool translucent , uint opacity )
{
if ( isDesktop ( ) )
return ; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
// tqWarning("setting opacity for %d",tqt_xdisplay());
//rule out activated translulcency with 100% opacity
if ( ! translucent | | opacity = = 0xFFFFFFFF )
{
opacity_ = 0xFFFFFFFF ;
XDeleteProperty ( tqt_xdisplay ( ) , frameId ( ) , atoms - > net_wm_window_opacity ) ;
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
}
else {
if ( opacity = = opacity_ )
return ;
opacity_ = opacity ;
long data = opacity ; // 32bit XChangeProperty needs long
XChangeProperty ( tqt_xdisplay ( ) , frameId ( ) , atoms - > net_wm_window_opacity , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & data , 1L ) ;
XChangeProperty ( tqt_xdisplay ( ) , window ( ) , atoms - > net_wm_window_opacity , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & data , 1L ) ;
}
}
void Client : : setShadowSize ( uint shadowSize )
{
// ignoring all individual settings - if we control a window, we control it's shadow
// TODO somehow handle individual settings for docks (besides custom sizes)
long data = shadowSize ;
XChangeProperty ( tqt_xdisplay ( ) , frameId ( ) , atoms - > net_wm_window_shadow , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & data , 1L ) ;
}
void Client : : updateOpacity ( )
// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
{
if ( ! ( isNormalWindow ( ) | | isDialog ( ) | | isUtility ( ) ) | | custom_opacity )
return ;
if ( isActive ( ) )
{
if ( ruleOpacityActive ( ) )
setOpacity ( rule_opacity_active < 0xFFFFFFFF , rule_opacity_active ) ;
else
setOpacity ( options - > translucentActiveWindows , options - > activeWindowOpacity ) ;
if ( isBMP ( ) )
// beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
{
ClientList tmpGroupMembers = group ( ) - > members ( ) ;
ClientList activeGroupMembers ;
activeGroupMembers . append ( this ) ;
tmpGroupMembers . remove ( this ) ;
ClientList : : Iterator it = tmpGroupMembers . begin ( ) ;
while ( it ! = tmpGroupMembers . end ( ) )
// search for next attached and not activated client and repeat if found
{
if ( ( * it ) ! = this & & ( * it ) - > isBMP ( ) )
// potential "to activate" client found
{
// tqWarning("client found");
if ( ( * it ) - > touches ( this ) ) // first test, if the new client touches the just activated one
{
// tqWarning("found client touches me");
if ( ruleOpacityActive ( ) )
( * it ) - > setOpacity ( rule_opacity_active < 0xFFFFFFFF , rule_opacity_active ) ;
else
( * it ) - > setOpacity ( options - > translucentActiveWindows , options - > activeWindowOpacity ) ;
// tqWarning("activated, search restarted (1)");
( * it ) - > setShadowSize ( options - > activeWindowShadowSize ) ;
activeGroupMembers . append ( * it ) ;
tmpGroupMembers . remove ( it ) ;
it = tmpGroupMembers . begin ( ) ; // restart, search next client
continue ;
}
else
{ // pot. client does not touch c, so we have to search if it touches some other activated client
bool found = false ;
for ( ClientList : : ConstIterator it2 = activeGroupMembers . begin ( ) ; it2 ! = activeGroupMembers . end ( ) ; it2 + + )
{
if ( ( * it2 ) ! = this & & ( * it2 ) ! = ( * it ) & & ( * it ) - > touches ( * it2 ) )
{
// tqWarning("found client touches other active client");
if ( ruleOpacityActive ( ) )
( * it ) - > setOpacity ( rule_opacity_active < 0xFFFFFFFF , rule_opacity_active ) ;
else
( * it ) - > setOpacity ( options - > translucentActiveWindows , options - > activeWindowOpacity ) ;
( * it ) - > setShadowSize ( options - > activeWindowShadowSize ) ;
activeGroupMembers . append ( * it ) ;
tmpGroupMembers . remove ( it ) ;
it = tmpGroupMembers . begin ( ) ; // reset potential client search
found = true ;
// tqWarning("activated, search restarted (2)");
break ; // skip this loop
}
}
if ( found ) continue ;
}
}
it + + ;
}
}
else if ( isNormalWindow ( ) )
// activate dependend minor windows as well
{
for ( ClientList : : ConstIterator it = group ( ) - > members ( ) . begin ( ) ; it ! = group ( ) - > members ( ) . end ( ) ; it + + )
if ( ( * it ) - > isDialog ( ) | | ( * it ) - > isUtility ( ) )
{
if ( ( * it ) - > ruleOpacityActive ( ) )
( * it ) - > setOpacity ( ( * it ) - > ruleOpacityActive ( ) < 0xFFFFFFFF , ( * it ) - > ruleOpacityActive ( ) ) ;
else
( * it ) - > setOpacity ( options - > translucentActiveWindows , options - > activeWindowOpacity ) ;
}
}
}
else
{
if ( ruleOpacityInactive ( ) )
setOpacity ( rule_opacity_inactive < 0xFFFFFFFF , rule_opacity_inactive ) ;
else
setOpacity ( options - > translucentInactiveWindows & & ! ( keepAbove ( ) & & options - > keepAboveAsActive ) ,
options - > inactiveWindowOpacity ) ;
// deactivate dependend minor windows as well
if ( isBMP ( ) )
// beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
{
ClientList tmpGroupMembers = group ( ) - > members ( ) ;
ClientList inactiveGroupMembers ;
inactiveGroupMembers . append ( this ) ;
tmpGroupMembers . remove ( this ) ;
ClientList : : Iterator it = tmpGroupMembers . begin ( ) ;
while ( it ! = tmpGroupMembers . end ( ) )
// search for next attached and not activated client and repeat if found
{
if ( ( * it ) ! = this & & ( * it ) - > isBMP ( ) )
// potential "to activate" client found
{
// tqWarning("client found");
if ( ( * it ) - > touches ( this ) ) // first test, if the new client touches the just activated one
{
// tqWarning("found client touches me");
if ( ( * it ) - > ruleOpacityInactive ( ) )
( * it ) - > setOpacity ( ( * it ) - > ruleOpacityInactive ( ) < 0xFFFFFFFF , ( * it ) - > ruleOpacityInactive ( ) ) ;
else
( * it ) - > setOpacity ( options - > translucentInactiveWindows & & ! ( ( * it ) - > keepAbove ( ) & & options - > keepAboveAsActive ) , options - > inactiveWindowOpacity ) ;
( * it ) - > setShadowSize ( options - > inactiveWindowShadowSize ) ;
// tqWarning("deactivated, search restarted (1)");
inactiveGroupMembers . append ( * it ) ;
tmpGroupMembers . remove ( it ) ;
it = tmpGroupMembers . begin ( ) ; // restart, search next client
continue ;
}
else // pot. client does not touch c, so we have to search if it touches some other activated client
{
bool found = false ;
for ( ClientList : : ConstIterator it2 = inactiveGroupMembers . begin ( ) ; it2 ! = inactiveGroupMembers . end ( ) ; it2 + + )
{
if ( ( * it2 ) ! = this & & ( * it2 ) ! = ( * it ) & & ( * it ) - > touches ( * it2 ) )
{
// tqWarning("found client touches other inactive client");
if ( ( * it ) - > ruleOpacityInactive ( ) )
( * it ) - > setOpacity ( ( * it ) - > ruleOpacityInactive ( ) < 0xFFFFFFFF , ( * it ) - > ruleOpacityInactive ( ) ) ;
else
( * it ) - > setOpacity ( options - > translucentInactiveWindows & & ! ( ( * it ) - > keepAbove ( ) & & options - > keepAboveAsActive ) , options - > inactiveWindowOpacity ) ;
( * it ) - > setShadowSize ( options - > inactiveWindowShadowSize ) ;
// tqWarning("deactivated, search restarted (2)");
inactiveGroupMembers . append ( * it ) ;
tmpGroupMembers . remove ( it ) ;
it = tmpGroupMembers . begin ( ) ; // reset potential client search
found = true ;
break ; // skip this loop
}
}
if ( found ) continue ;
}
}
it + + ;
}
}
else if ( isNormalWindow ( ) )
{
for ( ClientList : : ConstIterator it = group ( ) - > members ( ) . begin ( ) ; it ! = group ( ) - > members ( ) . end ( ) ; it + + )
if ( ( * it ) - > isUtility ( ) ) //don't deactivate dialogs...
{
if ( ( * it ) - > ruleOpacityInactive ( ) )
( * it ) - > setOpacity ( ( * it ) - > ruleOpacityInactive ( ) < 0xFFFFFFFF , ( * it ) - > ruleOpacityInactive ( ) ) ;
else
( * it ) - > setOpacity ( options - > translucentInactiveWindows & & ! ( ( * it ) - > keepAbove ( ) & & options - > keepAboveAsActive ) , options - > inactiveWindowOpacity ) ;
}
}
}
}
void Client : : updateShadowSize ( )
// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
{
if ( ! ( isNormalWindow ( ) | | isDialog ( ) | | isUtility ( ) ) )
return ;
if ( isActive ( ) )
setShadowSize ( options - > activeWindowShadowSize ) ;
else
setShadowSize ( options - > inactiveWindowShadowSize ) ;
}
uint Client : : ruleOpacityInactive ( )
{
return rule_opacity_inactive ; // != 0 ;
}
uint Client : : ruleOpacityActive ( )
{
return rule_opacity_active ; // != 0;
}
bool Client : : getWindowOpacity ( ) //query translucency settings from X, returns true if window opacity is set
{
unsigned char * data = 0 ;
Atom actual ;
int format , result ;
unsigned long n , left ;
result = XGetWindowProperty ( tqt_xdisplay ( ) , window ( ) , atoms - > net_wm_window_opacity , 0L , 1L , False , XA_CARDINAL , & actual , & format , & n , & left , /*(unsigned char **)*/ & data ) ;
if ( result = = Success & & data & & format = = 32 )
{
opacity_ = * reinterpret_cast < long * > ( data ) ;
custom_opacity = true ;
// setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
XFree ( ( char * ) data ) ;
return TRUE ;
}
return FALSE ;
}
void Client : : setCustomOpacityFlag ( bool custom )
{
custom_opacity = custom ;
}
uint Client : : opacity ( )
{
return opacity_ ;
}
int Client : : opacityPercentage ( )
{
return int ( 100 * ( ( double ) opacity_ / 0xffffffff ) ) ;
}
bool Client : : touches ( const Client * c )
// checks if this client borders c, needed to test beep media player window state
{
if ( y ( ) = = c - > y ( ) + c - > height ( ) ) // this bottom to c
return TRUE ;
if ( y ( ) + height ( ) = = c - > y ( ) ) // this top to c
return TRUE ;
if ( x ( ) = = c - > x ( ) + c - > width ( ) ) // this right to c
return TRUE ;
if ( x ( ) + width ( ) = = c - > x ( ) ) // this left to c
return TRUE ;
return FALSE ;
}
void Client : : setDecoHashProperty ( uint topHeight , uint rightWidth , uint bottomHeight , uint leftWidth )
{
long data = ( topHeight < 255 ? topHeight : 255 ) < < 24 |
( rightWidth < 255 ? rightWidth : 255 ) < < 16 |
( bottomHeight < 255 ? bottomHeight : 255 ) < < 8 |
( leftWidth < 255 ? leftWidth : 255 ) ;
XChangeProperty ( tqt_xdisplay ( ) , frameId ( ) , atoms - > net_wm_window_decohash , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & data , 1L ) ;
}
void Client : : unsetDecoHashProperty ( )
{
XDeleteProperty ( tqt_xdisplay ( ) , frameId ( ) , atoms - > net_wm_window_decohash ) ;
}
# ifndef NDEBUG
kdbgstream & operator < < ( kdbgstream & stream , const Client * cl )
{
if ( cl = = NULL )
return stream < < " \' NULL_CLIENT \' " ;
return stream < < " \' ID: " < < cl - > window ( ) < < " ;WMCLASS: " < < cl - > resourceClass ( ) < < " : " < < cl - > resourceName ( ) < < " ;Caption: " < < cl - > caption ( ) < < " \' " ;
}
kdbgstream & operator < < ( kdbgstream & stream , const ClientList & list )
{
stream < < " LIST:( " ;
bool first = true ;
for ( ClientList : : ConstIterator it = list . begin ( ) ;
it ! = list . end ( ) ;
+ + it )
{
if ( ! first )
stream < < " : " ;
first = false ;
stream < < * it ;
}
stream < < " ) " ;
return stream ;
}
kdbgstream & operator < < ( kdbgstream & stream , const ConstClientList & list )
{
stream < < " LIST:( " ;
bool first = true ;
for ( ConstClientList : : ConstIterator it = list . begin ( ) ;
it ! = list . end ( ) ;
+ + it )
{
if ( ! first )
stream < < " : " ;
first = false ;
stream < < * it ;
}
stream < < " ) " ;
return stream ;
}
# endif
TQPixmap * twin_get_menu_pix_hack ( )
{
static TQPixmap p ;
if ( p . isNull ( ) )
p = SmallIcon ( " bx2 " ) ;
return & p ;
}
} // namespace
# include "client.moc"