2000-03-24 22:23:02 +00:00
/*****************************************************************
2003-09-16 19:28:03 +00:00
KWin - the KDE window manager
This file is part of the KDE project .
2000-03-24 22:23:02 +00:00
Copyright ( C ) 1999 , 2000 Matthias Ettrich < ettrich @ kde . org >
2003-09-16 19:28:03 +00:00
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 .
2000-03-24 22:23:02 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-09-16 19:28:03 +00:00
# include "client.h"
1999-08-19 23:26:42 +00:00
# include <qapplication.h>
1999-09-27 16:02:44 +00:00
# include <qpainter.h>
2000-06-23 16:26:44 +00:00
# include <qdatetime.h>
2003-09-16 19:28:03 +00:00
# include <kprocess.h>
# include <unistd.h>
# include <kstandarddirs.h>
# include <qwhatsthis.h>
2002-03-03 12:39:31 +00:00
# include <kwin.h>
2000-08-24 12:44:18 +00:00
# include <kiconloader.h>
2002-11-19 14:44:11 +00:00
# include <stdlib.h>
2001-03-19 21:03:44 +00:00
2003-09-16 19:28:03 +00:00
# include "bridge.h"
# include "group.h"
# include "workspace.h"
# include "atoms.h"
# include "notifications.h"
2004-05-28 13:51:11 +00:00
# include "rules.h"
2001-04-03 14:40:34 +00:00
2003-09-16 19:28:03 +00:00
# include <X11/extensions/shape.h>
2005-07-28 14:59:42 +00:00
# include <QX11Info>
2000-06-08 17:05:51 +00:00
2001-02-22 09:45:19 +00:00
// put all externs before the namespace statement to allow the linker
// to resolve them properly
2001-02-20 01:20:38 +00:00
2003-09-16 19:28:03 +00:00
namespace KWinInternal
1999-08-19 23:26:42 +00:00
{
2003-01-07 14:26:58 +00:00
/*
2000-10-17 12:51:39 +00:00
2003-09-16 19:28:03 +00:00
Creating a client :
- only by calling Workspace : : createClient ( )
- it creates a new client and calls manage ( ) for it
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
Destroying a client :
- destroyClient ( ) - only when the window itself has been destroyed
- releaseWindow ( ) - the window is kept , only the client itself is destroyed
2000-10-17 12:51:39 +00:00
*/
1999-08-19 23:26:42 +00:00
1999-09-27 16:02:44 +00:00
1999-08-19 23:26:42 +00:00
/*!
\ class Client client . h
\ brief The Client class encapsulates a window decoration frame .
*/
/*!
2003-09-16 19:28:03 +00:00
This ctor is " dumb " - it only initializes data . All the real initialization
is done in manage ( ) .
*/
Client : : Client ( Workspace * ws )
: QObject ( NULL ) ,
client ( None ) ,
wrapper ( None ) ,
frame ( None ) ,
decoration ( NULL ) ,
wspace ( ws ) ,
bridge ( new Bridge ( this ) ) ,
move_faked_activity ( false ) ,
2004-03-05 13:39:27 +00:00
move_resize_grab_window ( None ) ,
2003-09-16 19:28:03 +00:00
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 ) ,
user_time ( CurrentTime ) , // not known yet
allowed_actions ( 0 ) ,
2005-06-08 17:16:53 +00:00
postpone_geometry_updates ( 0 ) ,
pending_geometry_update ( false ) ,
2003-09-24 11:01:14 +00:00
shade_geometry_change ( false ) ,
2003-09-16 19:28:03 +00:00
border_left ( 0 ) ,
border_right ( 0 ) ,
border_top ( 0 ) ,
2005-05-30 13:31:33 +00:00
border_bottom ( 0 ) ,
demandAttentionKNotifyTimer ( NULL )
2003-09-16 19:28:03 +00:00
// SELI do all as initialization
{
2000-07-09 20:29:53 +00:00
autoRaiseTimer = 0 ;
2001-01-14 20:16:04 +00:00
shadeHoverTimer = 0 ;
2000-06-08 17:05:51 +00:00
1999-08-19 23:26:42 +00:00
// set the initial mapping state
2003-09-16 19:28:03 +00:00
mapping_state = WithdrawnState ;
desk = 0 ; // no desktop yet
1999-08-19 23:26:42 +00:00
2003-12-15 15:10:17 +00:00
mode = PositionCenter ;
2006-02-19 01:33:48 +00:00
buttonDown = false ;
moveResizeMode = false ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
info = NULL ;
2002-04-16 19:23:45 +00:00
2003-09-16 19:28:03 +00:00
shade_mode = ShadeNone ;
2006-02-19 01:33:48 +00:00
active = false ;
2005-05-11 14:46:23 +00:00
deleting = false ;
2006-02-19 01:33:48 +00:00
keep_above = false ;
keep_below = false ;
is_shape = false ;
2004-07-27 08:35:51 +00:00
motif_noborder = false ;
2006-02-19 01:33:48 +00:00
motif_may_move = true ;
motif_may_resize = true ;
motif_may_close = true ;
2003-09-16 19:28:03 +00:00
fullscreen_mode = FullScreenNone ;
2006-02-19 01:33:48 +00:00
skip_taskbar = false ;
2003-09-16 19:28:03 +00:00
original_skip_taskbar = false ;
minimized = false ;
hidden = false ;
modal = false ;
noborder = false ;
user_noborder = false ;
not_obscured = false ;
2003-10-10 11:23:42 +00:00
urgency = false ;
2004-03-24 19:05:49 +00:00
ignore_focus_stealing = false ;
2005-05-30 13:31:33 +00:00
demands_attention = false ;
2004-05-28 11:33:36 +00:00
check_active_modal = false ;
2002-04-16 19:23:45 +00:00
2002-03-17 13:32:05 +00:00
Pdeletewindow = 0 ;
Ptakefocus = 0 ;
2004-04-16 10:23:42 +00:00
Ptakeactivity = 0 ;
2002-03-17 13:32:05 +00:00
Pcontexthelp = 0 ;
2003-09-16 19:28:03 +00:00
Pping = 0 ;
2006-02-19 01:33:48 +00:00
input = false ;
skip_pager = false ;
2000-08-31 17:15:10 +00:00
2002-03-17 13:32:05 +00:00
max_mode = MaximizeRestore ;
2005-08-16 21:18:47 +00:00
maxmode_restore = MaximizeRestore ;
2000-08-30 14:27:30 +00:00
cmap = None ;
2003-09-19 11:13:24 +00:00
frame_geometry = QRect ( 0 , 0 , 100 , 100 ) ; // so that decorations don't start with size being (0,0)
client_size = QSize ( 100 , 100 ) ;
2005-01-15 17:07:48 +00:00
custom_opacity = false ;
rule_opacity_active = 0 ; ; //translucency rules
rule_opacity_inactive = 0 ; //dito.
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
// SELI initialize xsizehints??
2001-01-14 20:16:04 +00:00
}
2001-01-14 20:25:32 +00:00
1999-08-19 23:26:42 +00:00
/*!
2003-09-16 19:28:03 +00:00
" Dumb " destructor .
1999-08-19 23:26:42 +00:00
*/
Client : : ~ Client ( )
2003-09-16 19:28:03 +00:00
{
assert ( ! moveResizeMode ) ;
assert ( client = = None ) ;
assert ( frame = = None & & wrapper = = None ) ;
assert ( decoration = = NULL ) ;
2005-06-08 17:16:53 +00:00
assert ( postpone_geometry_updates = = 0 ) ;
2004-05-28 11:33:36 +00:00
assert ( ! check_active_modal ) ;
2000-06-08 17:05:51 +00:00
delete info ;
2003-09-16 19:28:03 +00:00
delete bridge ;
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
// use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
void Client : : deleteClient ( Client * c , allowed_t )
{
delete c ;
}
1999-08-19 23:26:42 +00:00
/*!
2003-09-16 19:28:03 +00:00
Releases the window . The client has done its job and the window is still existing .
1999-08-19 23:26:42 +00:00
*/
2003-09-16 19:28:03 +00:00
void Client : : releaseWindow ( bool on_shutdown )
{
2005-05-11 14:46:23 +00:00
assert ( ! deleting ) ;
deleting = true ;
2005-06-07 15:31:15 +00:00
workspace ( ) - > discardUsedWindowRules ( this , true ) ; // remove ForceTemporarily rules
2004-10-06 14:02:30 +00:00
StackingUpdatesBlocker blocker ( workspace ( ) ) ;
2006-02-19 01:33:48 +00:00
if ( ! custom_opacity ) setOpacity ( false ) ;
2003-09-16 19:28:03 +00:00
if ( moveResizeMode )
leaveMoveResize ( ) ;
2004-05-31 14:25:25 +00:00
finishWindowRules ( ) ;
2005-06-08 17:16:53 +00:00
+ + postpone_geometry_updates ;
2005-04-28 09:47:57 +00:00
setMappingState ( WithdrawnState ) ;
2003-09-16 19:28:03 +00:00
setModal ( false ) ; // otherwise its mainwindow wouldn't get focus
2003-11-27 14:54:16 +00:00
hidden = true ; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
2003-09-16 19:28:03 +00:00
if ( ! on_shutdown )
workspace ( ) - > clientHidden ( this ) ;
2005-07-28 14:59:42 +00:00
XUnmapWindow ( QX11Info : : display ( ) , frameId ( ) ) ; // destroying decoration would cause ugly visual effect
2003-09-16 19:28:03 +00:00
destroyDecoration ( ) ;
2003-09-19 14:53:39 +00:00
cleanGrouping ( ) ;
2003-09-16 19:28:03 +00:00
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
2002-02-27 21:01:01 +00:00
}
2005-07-28 14:59:42 +00:00
XDeleteProperty ( QX11Info : : display ( ) , client , atoms - > kde_net_wm_user_creation_time ) ;
XDeleteProperty ( QX11Info : : display ( ) , client , atoms - > net_frame_extents ) ;
XDeleteProperty ( QX11Info : : display ( ) , client , atoms - > kde_net_wm_frame_strut ) ;
XReparentWindow ( QX11Info : : display ( ) , client , workspace ( ) - > rootWin ( ) , x ( ) , y ( ) ) ;
XRemoveFromSaveSet ( QX11Info : : display ( ) , client ) ;
XSelectInput ( QX11Info : : display ( ) , client , NoEventMask ) ;
2003-09-16 19:28:03 +00:00
if ( on_shutdown )
{ // map the window, so it can be found after another WM is started
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , client ) ;
2003-09-16 19:28:03 +00:00
// TODO preserve minimized, shaded etc. state?
}
2003-11-21 16:46:57 +00:00
else
{
2004-02-09 13:33:57 +00:00
// Make sure it's not mapped if the app unmapped it (#65279). The app
2003-11-21 16:46:57 +00:00
// may do map+unmap before we initially map the window by calling rawShow() from manage().
2005-07-28 14:59:42 +00:00
XUnmapWindow ( QX11Info : : display ( ) , client ) ;
2003-11-21 16:46:57 +00:00
}
2003-09-16 19:28:03 +00:00
client = None ;
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , wrapper ) ;
2003-09-16 19:28:03 +00:00
wrapper = None ;
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , frame ) ;
2003-09-16 19:28:03 +00:00
frame = None ;
2005-06-08 17:16:53 +00:00
- - postpone_geometry_updates ; // don't use GeometryUpdatesBlocker, it would now set the geometry
2003-09-16 19:28:03 +00:00
deleteClient ( this , Allowed ) ;
}
2002-02-27 21:01:01 +00:00
2003-09-16 19:28:03 +00:00
// like releaseWindow(), but this one is called when the window has been already destroyed
// (e.g. the application closed it)
void Client : : destroyClient ( )
{
2005-05-11 14:46:23 +00:00
assert ( ! deleting ) ;
deleting = true ;
2005-06-07 15:31:15 +00:00
workspace ( ) - > discardUsedWindowRules ( this , true ) ; // remove ForceTemporarily rules
2004-10-06 14:02:30 +00:00
StackingUpdatesBlocker blocker ( workspace ( ) ) ;
2003-09-16 19:28:03 +00:00
if ( moveResizeMode )
leaveMoveResize ( ) ;
2004-05-31 14:25:25 +00:00
finishWindowRules ( ) ;
2005-06-08 17:16:53 +00:00
+ + postpone_geometry_updates ;
2003-09-16 19:28:03 +00:00
setModal ( false ) ;
2003-10-31 09:45:14 +00:00
hidden = true ; // so that it's not considered visible anymore
2003-09-16 19:28:03 +00:00
workspace ( ) - > clientHidden ( this ) ;
destroyDecoration ( ) ;
2003-09-19 14:53:39 +00:00
cleanGrouping ( ) ;
2003-09-16 19:28:03 +00:00
workspace ( ) - > removeClient ( this , Allowed ) ;
client = None ; // invalidate
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , wrapper ) ;
2003-09-16 19:28:03 +00:00
wrapper = None ;
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , frame ) ;
2003-09-16 19:28:03 +00:00
frame = None ;
2005-06-08 17:16:53 +00:00
- - postpone_geometry_updates ; // don't use GeometryUpdatesBlocker, it would now set the geometry
2003-09-16 19:28:03 +00:00
deleteClient ( this , Allowed ) ;
}
2003-10-22 08:26:09 +00:00
void Client : : updateDecoration ( bool check_workspace_pos , bool force )
2003-09-16 19:28:03 +00:00
{
if ( ! force & & ( ( decoration = = NULL & & noBorder ( ) )
| | ( decoration ! = NULL & & ! noBorder ( ) ) ) )
return ;
2003-09-19 11:13:24 +00:00
bool do_show = false ;
2005-06-08 17:16:53 +00:00
postponeGeometryUpdates ( true ) ;
2003-09-16 19:28:03 +00:00
if ( force )
2003-10-22 08:26:09 +00:00
destroyDecoration ( ) ;
2003-09-16 19:28:03 +00:00
if ( ! noBorder ( ) )
{
decoration = workspace ( ) - > createDecoration ( bridge ) ;
// TODO check decoration's minimum size?
decoration - > init ( ) ;
2003-09-19 11:11:07 +00:00
decoration - > widget ( ) - > installEventFilter ( this ) ;
2005-07-28 14:59:42 +00:00
XReparentWindow ( QX11Info : : display ( ) , decoration - > widget ( ) - > winId ( ) , frameId ( ) , 0 , 0 ) ;
2003-09-16 19:28:03 +00:00
decoration - > widget ( ) - > lower ( ) ;
decoration - > borders ( border_left , border_right , border_top , border_bottom ) ;
2005-07-01 19:55:06 +00:00
options - > onlyDecoTranslucent ?
setDecoHashProperty ( border_top , border_right , border_bottom , border_left ) :
unsetDecoHashProperty ( ) ;
2003-09-19 11:13:04 +00:00
int save_workarea_diff_x = workarea_diff_x ;
int save_workarea_diff_y = workarea_diff_y ;
2003-09-24 11:01:14 +00:00
move ( calculateGravitation ( false ) ) ;
2005-06-08 18:07:27 +00:00
plainResize ( sizeForClientSize ( clientSize ( ) ) , ForceGeometrySet ) ;
2003-09-19 11:13:04 +00:00
workarea_diff_x = save_workarea_diff_x ;
workarea_diff_y = save_workarea_diff_y ;
2003-09-19 11:13:24 +00:00
do_show = true ;
2003-09-16 19:28:03 +00:00
}
else
2003-10-22 08:26:09 +00:00
destroyDecoration ( ) ;
2003-09-16 19:28:03 +00:00
if ( check_workspace_pos )
checkWorkspacePosition ( ) ;
2005-06-08 17:16:53 +00:00
postponeGeometryUpdates ( false ) ;
2003-09-19 11:13:24 +00:00
if ( do_show )
decoration - > widget ( ) - > show ( ) ;
2005-06-21 09:00:28 +00:00
updateFrameExtents ( ) ;
2002-09-11 13:02:54 +00:00
}
2003-10-22 08:26:09 +00:00
void Client : : destroyDecoration ( )
2003-09-16 19:28:03 +00:00
{
if ( decoration ! = NULL )
{
2003-10-22 08:26:09 +00:00
delete decoration ;
decoration = NULL ;
2003-10-02 08:56:59 +00:00
QPoint grav = calculateGravitation ( true ) ;
2003-09-16 19:28:03 +00:00
border_left = border_right = border_top = border_bottom = 0 ;
setMask ( QRegion ( ) ) ; // reset shape mask
2003-09-19 11:13:04 +00:00
int save_workarea_diff_x = workarea_diff_x ;
int save_workarea_diff_y = workarea_diff_y ;
2005-06-08 18:07:27 +00:00
plainResize ( sizeForClientSize ( clientSize ( ) ) , ForceGeometrySet ) ;
2004-02-09 13:33:57 +00:00
move ( grav ) ;
2003-09-19 11:13:04 +00:00
workarea_diff_x = save_workarea_diff_x ;
workarea_diff_y = save_workarea_diff_y ;
2003-09-16 19:28:03 +00:00
}
}
2001-01-24 16:47:44 +00:00
2003-09-16 19:28:03 +00:00
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 ;
2005-06-08 17:16:53 +00:00
GeometryUpdatesPostponer blocker ( this ) ;
2003-09-16 19:28:03 +00:00
move ( calculateGravitation ( true ) ) ;
border_left = new_left ;
border_right = new_right ;
border_top = new_top ;
border_bottom = new_bottom ;
2005-07-01 19:55:06 +00:00
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 ( ) ;
2003-09-16 19:28:03 +00:00
move ( calculateGravitation ( false ) ) ;
2003-10-02 08:57:17 +00:00
plainResize ( sizeForClientSize ( clientSize ( ) ) , ForceGeometrySet ) ;
2003-09-16 19:28:03 +00:00
checkWorkspacePosition ( ) ;
}
void Client : : detectNoBorder ( )
{
2004-07-27 08:35:51 +00:00
if ( Shape : : hasShape ( window ( ) ) )
2003-09-16 19:28:03 +00:00
{
2004-07-27 08:35:51 +00:00
noborder = true ;
2003-09-16 19:28:03 +00:00
return ;
2002-02-27 21:01:01 +00:00
}
2003-09-16 19:28:03 +00:00
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 ) ;
2002-02-27 21:01:01 +00:00
}
2005-05-11 14:20:54 +00:00
// 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 ;
2000-10-04 10:59:00 +00:00
}
2005-06-24 15:22:34 +00:00
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 :
2006-02-19 01:33:48 +00:00
setShapable ( false ) ;
2005-06-24 15:22:34 +00:00
break ;
default :
assert ( false ) ;
}
}
2005-06-21 09:00:28 +00:00
void Client : : updateFrameExtents ( )
2003-09-16 19:28:03 +00:00
{
NETStrut strut ;
strut . left = border_left ;
strut . right = border_right ;
strut . top = border_top ;
strut . bottom = border_bottom ;
2005-06-21 09:00:28 +00:00
info - > setFrameExtents ( strut ) ;
2003-09-16 19:28:03 +00:00
}
// 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 QSize & s )
{
if ( decoration = = NULL )
return ;
QSize oldsize = decoration - > widget ( ) - > size ( ) ;
decoration - > resize ( s ) ;
if ( oldsize = = s )
{
QResizeEvent e ( s , oldsize ) ;
QApplication : : sendEvent ( decoration - > widget ( ) , & e ) ;
2002-02-27 21:01:01 +00:00
}
2000-03-24 22:23:02 +00:00
}
2003-09-16 19:28:03 +00:00
bool Client : : noBorder ( ) const
{
2004-07-27 08:35:51 +00:00
return noborder | | isFullScreen ( ) | | user_noborder | | motif_noborder ;
2003-09-16 19:28:03 +00:00
}
2000-07-15 01:12:41 +00:00
2003-09-16 19:28:03 +00:00
bool Client : : userCanSetNoBorder ( ) const
{
2003-10-06 11:31:43 +00:00
return ! noborder & & ! isFullScreen ( ) & & ! isShade ( ) ;
2003-09-16 19:28:03 +00:00
}
2002-10-24 15:47:09 +00:00
2003-09-16 19:28:03 +00:00
bool Client : : isUserNoBorder ( ) const
{
return user_noborder ;
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
void Client : : setUserNoBorder ( bool set )
{
if ( ! userCanSetNoBorder ( ) )
return ;
2004-06-03 14:09:45 +00:00
set = rules ( ) - > checkNoBorder ( set ) ;
2003-09-16 19:28:03 +00:00
if ( user_noborder = = set )
return ;
user_noborder = set ;
2003-10-22 08:26:09 +00:00
updateDecoration ( true , false ) ;
2004-06-11 15:12:29 +00:00
updateWindowRules ( ) ;
2003-09-16 19:28:03 +00:00
}
2002-02-28 22:11:43 +00:00
2003-09-16 19:28:03 +00:00
void Client : : updateShape ( )
{
2006-02-19 01:33:48 +00:00
setShapable ( true ) ;
2003-09-16 19:28:03 +00:00
if ( shape ( ) )
2005-01-21 16:19:10 +00:00
{
2005-07-28 14:59:42 +00:00
XShapeCombineShape ( QX11Info : : display ( ) , frameId ( ) , ShapeBounding ,
2003-09-16 19:28:03 +00:00
clientPos ( ) . x ( ) , clientPos ( ) . y ( ) ,
window ( ) , ShapeBounding , ShapeSet ) ;
2005-01-21 16:19:10 +00:00
}
2003-09-16 19:28:03 +00:00
else
2005-01-21 16:19:10 +00:00
{
2005-07-28 14:59:42 +00:00
XShapeCombineMask ( QX11Info : : display ( ) , frameId ( ) , ShapeBounding , 0 , 0 ,
2003-09-16 19:28:03 +00:00
None , ShapeSet ) ;
2005-01-21 16:19:10 +00:00
}
2003-09-16 19:28:03 +00:00
// workaround for #19644 - shaped windows shouldn't have decoration
if ( shape ( ) & & ! noBorder ( ) )
{
noborder = true ;
updateDecoration ( true ) ;
}
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
void Client : : setMask ( const QRegion & reg , int mode )
{
2003-10-27 16:28:53 +00:00
_mask = reg ;
2003-09-16 19:28:03 +00:00
if ( reg . isNull ( ) )
2005-07-28 14:59:42 +00:00
XShapeCombineMask ( QX11Info : : display ( ) , frameId ( ) , ShapeBounding , 0 , 0 ,
2003-09-16 19:28:03 +00:00
None , ShapeSet ) ;
else if ( mode = = X : : Unsorted )
2005-07-28 14:59:42 +00:00
XShapeCombineRegion ( QX11Info : : display ( ) , frameId ( ) , ShapeBounding , 0 , 0 ,
2003-09-16 19:28:03 +00:00
reg . handle ( ) , ShapeSet ) ;
else
{
2005-07-28 14:59:42 +00:00
QVector < QRect > rects = reg . rects ( ) ;
2003-09-16 19:28:03 +00:00
XRectangle * xrects = new XRectangle [ rects . count ( ) ] ;
2005-07-28 14:59:42 +00:00
for ( int i = 0 ;
2003-09-16 19:28:03 +00:00
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 ( ) ;
}
2005-07-28 14:59:42 +00:00
XShapeCombineRectangles ( QX11Info : : display ( ) , frameId ( ) , ShapeBounding , 0 , 0 ,
2003-09-16 19:28:03 +00:00
xrects , rects . count ( ) , ShapeSet , mode ) ;
delete [ ] xrects ;
}
}
2000-06-23 16:26:44 +00:00
2003-10-27 16:28:53 +00:00
QRegion Client : : mask ( ) const
{
if ( _mask . isEmpty ( ) )
return QRegion ( 0 , 0 , width ( ) , height ( ) ) ;
return _mask ;
}
2005-01-21 16:19:10 +00:00
void Client : : setShapable ( bool b )
{
2005-01-27 09:58:34 +00:00
long tmp = b ? 1 : 0 ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , frameId ( ) , atoms - > net_wm_window_shapable , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & tmp , 1L ) ;
2005-01-21 16:19:10 +00:00
}
2003-10-27 16:28:53 +00:00
2003-09-16 19:28:03 +00:00
void Client : : hideClient ( bool hide )
{
if ( hidden = = hide )
2002-08-28 15:17:31 +00:00
return ;
2003-09-16 19:28:03 +00:00
hidden = hide ;
2005-04-12 17:22:47 +00:00
updateVisibility ( ) ;
2000-05-07 20:38:11 +00:00
}
2005-04-12 17:22:47 +00:00
2003-09-16 19:28:03 +00:00
/*
Returns whether the window is minimizable or not
2000-11-17 19:43:20 +00:00
*/
2003-09-16 19:28:03 +00:00
bool Client : : isMinimizable ( ) const
{
2005-05-11 14:20:54 +00:00
if ( isSpecialWindow ( ) )
2003-09-16 19:28:03 +00:00
return false ;
2004-06-07 14:58:48 +00:00
if ( isTransient ( ) )
2004-04-20 15:19:47 +00:00
{ // #66868 - let other xmms windows be minimized when the mainwindow is minimized
bool shown_mainwindow = false ;
2003-09-16 19:28:03 +00:00
ClientList mainclients = mainClients ( ) ;
for ( ClientList : : ConstIterator it = mainclients . begin ( ) ;
it ! = mainclients . end ( ) ;
+ + it )
2004-04-20 15:19:47 +00:00
{
2003-10-10 13:00:01 +00:00
if ( ( * it ) - > isShown ( true ) )
2004-04-20 15:19:47 +00:00
shown_mainwindow = true ;
}
if ( ! shown_mainwindow )
return true ;
2002-02-27 21:01:01 +00:00
}
2004-04-20 15:19:47 +00:00
// 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 ;
2003-09-16 19:28:03 +00:00
return true ;
2000-11-17 19:43:20 +00:00
}
2000-12-01 18:27:26 +00:00
/*!
2003-09-16 19:28:03 +00:00
Minimizes this client plus its transients
2000-11-17 19:43:20 +00:00
*/
2004-03-01 18:00:07 +00:00
void Client : : minimize ( bool avoid_animation )
2003-09-16 19:28:03 +00:00
{
if ( ! isMinimizable ( ) | | isMinimized ( ) )
2002-02-27 21:01:01 +00:00
return ;
2000-05-20 07:54:11 +00:00
2003-09-16 19:28:03 +00:00
Notify : : raise ( Notify : : Minimize ) ;
2000-12-01 18:27:26 +00:00
2003-09-16 19:28:03 +00:00
// SELI mainClients().isEmpty() ??? - and in unminimize() too
2005-04-12 17:22:47 +00:00
if ( mainClients ( ) . isEmpty ( ) & & isOnCurrentDesktop ( ) & & isShown ( true ) & & ! avoid_animation )
2003-09-16 19:28:03 +00:00
animateMinimizeOrUnminimize ( true ) ; // was visible or shaded
2001-01-15 13:25:39 +00:00
2005-11-01 16:56:09 +00:00
minimized = true ;
2005-04-12 17:22:47 +00:00
updateVisibility ( ) ;
2003-09-16 19:28:03 +00:00
updateAllowedActions ( ) ;
workspace ( ) - > updateMinimizedOfTransients ( this ) ;
2004-06-11 15:12:29 +00:00
updateWindowRules ( ) ;
2006-02-27 10:13:31 +00:00
workspace ( ) - > updateFocusChains ( this , false ) ; // make it last in the focus chain
2000-06-23 18:18:34 +00:00
}
2000-04-26 21:28:51 +00:00
2004-03-01 18:00:07 +00:00
void Client : : unminimize ( bool avoid_animation )
2003-09-16 19:28:03 +00:00
{
if ( ! isMinimized ( ) )
return ;
2000-12-01 18:27:26 +00:00
2003-09-16 19:28:03 +00:00
Notify : : raise ( Notify : : UnMinimize ) ;
2005-04-12 17:22:47 +00:00
minimized = false ;
if ( isOnCurrentDesktop ( ) & & isShown ( true ) )
2003-09-16 19:28:03 +00:00
{
2004-03-01 18:00:07 +00:00
if ( mainClients ( ) . isEmpty ( ) & & ! avoid_animation )
2006-02-19 01:33:48 +00:00
animateMinimizeOrUnminimize ( false ) ;
2003-09-16 19:28:03 +00:00
}
2005-04-12 17:22:47 +00:00
updateVisibility ( ) ;
2003-09-16 19:28:03 +00:00
updateAllowedActions ( ) ;
workspace ( ) - > updateMinimizedOfTransients ( this ) ;
2004-06-11 15:12:29 +00:00
updateWindowRules ( ) ;
1999-08-19 23:26:42 +00:00
}
2000-06-23 18:18:34 +00:00
2003-09-16 19:28:03 +00:00
extern bool blockAnimation ;
2001-04-27 08:38:44 +00:00
2003-09-16 19:28:03 +00:00
void Client : : animateMinimizeOrUnminimize ( bool minimize )
{
if ( blockAnimation )
return ;
if ( ! options - > animateMinimize )
return ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
if ( decoration ! = NULL & & decoration - > animateMinimize ( minimize ) )
return ; // decoration did it
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
// 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.
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
float lf , rf , tf , bf , step ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
int speed = options - > animateMinimizeSpeed ;
if ( speed > 10 )
speed = 10 ;
if ( speed < 0 )
speed = 0 ;
2000-03-24 09:11:37 +00:00
2003-09-16 19:28:03 +00:00
step = 40. * ( 11 - speed ) ;
2000-03-24 09:11:37 +00:00
2003-09-16 19:28:03 +00:00
NETRect r = info - > iconGeometry ( ) ;
QRect icongeom ( r . pos . x , r . pos . y , r . size . width , r . size . height ) ;
if ( ! icongeom . isValid ( ) )
return ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
QPixmap pm = animationPixmap ( minimize ? width ( ) : icongeom . width ( ) ) ;
2000-06-23 16:26:44 +00:00
2003-09-16 19:28:03 +00:00
QRect before , after ;
if ( minimize )
{
before = QRect ( x ( ) , y ( ) , width ( ) , pm . height ( ) ) ;
after = QRect ( icongeom . x ( ) , icongeom . y ( ) , icongeom . width ( ) , pm . height ( ) ) ;
}
else
{
before = QRect ( icongeom . x ( ) , icongeom . y ( ) , icongeom . width ( ) , pm . height ( ) ) ;
after = QRect ( x ( ) , y ( ) , width ( ) , pm . height ( ) ) ;
2002-02-27 21:01:01 +00:00
}
2001-01-14 20:16:04 +00:00
2003-09-16 19:28:03 +00:00
lf = ( after . left ( ) - before . left ( ) ) / step ;
rf = ( after . right ( ) - before . right ( ) ) / step ;
tf = ( after . top ( ) - before . top ( ) ) / step ;
bf = ( after . bottom ( ) - before . bottom ( ) ) / step ;
2001-01-15 13:25:39 +00:00
2003-12-04 13:54:10 +00:00
grabXServer ( ) ;
2001-01-15 13:25:39 +00:00
2003-09-16 19:28:03 +00:00
QRect area = before ;
QRect area2 ;
QPixmap pm2 ;
2000-08-16 12:18:56 +00:00
2003-09-16 19:28:03 +00:00
QTime t ;
t . start ( ) ;
float diff ;
2000-08-16 12:18:56 +00:00
2003-09-16 19:28:03 +00:00
QPainter p ( workspace ( ) - > desktopWidget ( ) ) ;
2006-02-19 01:33:48 +00:00
bool need_to_clear = false ;
2003-09-16 19:28:03 +00:00
QPixmap pm3 ;
do
{
if ( area2 ! = area )
{
pm = animationPixmap ( area . width ( ) ) ;
2005-07-28 14:59:42 +00:00
pm2 = QPixmap : : grabWindow ( QX11Info : : appRootWindow ( ) , area . x ( ) , area . y ( ) , area . width ( ) , area . height ( ) ) ;
2003-09-16 19:28:03 +00:00
p . drawPixmap ( area . x ( ) , area . y ( ) , pm ) ;
if ( need_to_clear )
{
p . drawPixmap ( area2 . x ( ) , area2 . y ( ) , pm3 ) ;
2006-02-19 01:33:48 +00:00
need_to_clear = false ;
2003-09-16 19:28:03 +00:00
}
area2 = area ;
}
2005-07-28 14:59:42 +00:00
XFlush ( QX11Info : : display ( ) ) ;
2006-02-19 01:33:48 +00:00
XSync ( QX11Info : : display ( ) , false ) ;
2003-09-16 19:28:03 +00:00
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 ;
2006-02-19 01:33:48 +00:00
need_to_clear = true ;
2003-09-16 19:28:03 +00:00
}
}
} while ( t . elapsed ( ) < step ) ;
if ( area2 = = area | | need_to_clear )
p . drawPixmap ( area2 . x ( ) , area2 . y ( ) , pm2 ) ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
p . end ( ) ;
2003-12-04 13:54:10 +00:00
ungrabXServer ( ) ;
2003-09-16 19:28:03 +00:00
}
1999-08-19 23:26:42 +00:00
/*!
2003-09-16 19:28:03 +00:00
The pixmap shown during ( un ) minimalization animation
1999-08-19 23:26:42 +00:00
*/
2003-09-16 19:28:03 +00:00
QPixmap Client : : animationPixmap ( int w )
{
QFont font = options - > font ( isActive ( ) ) ;
QFontMetrics fm ( font ) ;
QPixmap pm ( w , fm . lineSpacing ( ) ) ;
pm . fill ( options - > color ( Options : : ColorTitleBar , isActive ( ) | | isMinimized ( ) ) ) ;
QPainter p ( & pm ) ;
p . setPen ( options - > color ( Options : : ColorFont , isActive ( ) | | isMinimized ( ) ) ) ;
p . setFont ( options - > font ( isActive ( ) ) ) ;
2005-10-27 09:07:06 +00:00
p . drawText ( pm . rect ( ) , Qt : : AlignLeft | Qt : : AlignVCenter | Qt : : TextSingleLine , caption ( ) ) ;
2003-09-16 19:28:03 +00:00
return pm ;
1999-08-19 23:26:42 +00:00
}
2003-09-16 19:28:03 +00:00
bool Client : : isShadeable ( ) const
{
return ! isSpecialWindow ( ) & & ! noBorder ( ) ;
2001-01-14 20:16:04 +00:00
}
2000-09-11 20:54:00 +00:00
2003-09-16 19:28:03 +00:00
void Client : : setShade ( ShadeMode mode )
{
if ( ! isShadeable ( ) )
return ;
2004-06-03 14:09:45 +00:00
mode = rules ( ) - > checkShade ( mode ) ;
2003-09-16 19:28:03 +00:00
if ( shade_mode = = mode )
return ;
bool was_shade = isShade ( ) ;
2004-02-16 15:19:39 +00:00
ShadeMode was_shade_mode = shade_mode ;
2003-09-16 19:28:03 +00:00
shade_mode = mode ;
if ( was_shade = = isShade ( ) )
2004-11-25 16:08:46 +00:00
{
if ( decoration ! = NULL ) // decoration may want to update after e.g. hover-shade changes
decoration - > shadeChange ( ) ;
2003-09-16 19:28:03 +00:00
return ; // no real change in shaded state
2004-11-25 16:08:46 +00:00
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
if ( shade_mode = = ShadeNormal )
{
2003-10-10 13:00:01 +00:00
if ( isShown ( true ) & & isOnCurrentDesktop ( ) )
2003-09-16 19:28:03 +00:00
Notify : : raise ( Notify : : ShadeUp ) ;
}
else if ( shade_mode = = ShadeNone )
{
2003-10-10 13:00:01 +00:00
if ( isShown ( true ) & & isOnCurrentDesktop ( ) )
2003-09-16 19:28:03 +00:00
Notify : : raise ( Notify : : ShadeDown ) ;
}
2001-01-15 13:25:39 +00:00
2003-09-16 19:28:03 +00:00
assert ( decoration ! = NULL ) ; // noborder windows can't be shaded
2005-06-08 17:16:53 +00:00
GeometryUpdatesPostponer blocker ( this ) ;
2003-09-16 19:28:03 +00:00
// decorations may turn off some borders when shaded
decoration - > borders ( border_left , border_right , border_top , border_bottom ) ;
2001-01-14 20:16:04 +00:00
2000-09-25 15:30:51 +00:00
int as = options - > animateShade ? 10 : 1 ;
2003-09-16 19:28:03 +00:00
// TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
if ( isShade ( ) )
{ // shade_mode == ShadeNormal
2005-01-15 17:07:48 +00:00
// we're about to shade, texx xcompmgr to prepare
2005-01-27 09:58:34 +00:00
long _shade = 1 ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , frameId ( ) , atoms - > net_wm_window_shade , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & _shade , 1L ) ;
2005-01-15 17:07:48 +00:00
// shade
2002-02-27 21:01:01 +00:00
int h = height ( ) ;
2003-09-24 11:01:14 +00:00
shade_geometry_change = true ;
2005-06-08 18:07:27 +00:00
QSize s ( sizeForClientSize ( QSize ( clientSize ( ) ) ) ) ;
s . setHeight ( border_top + border_bottom ) ;
2005-07-28 14:59:42 +00:00
XSelectInput ( QX11Info : : display ( ) , wrapper , ClientWinMask ) ; // avoid getting UnmapNotify
XUnmapWindow ( QX11Info : : display ( ) , wrapper ) ;
XUnmapWindow ( QX11Info : : display ( ) , client ) ;
XSelectInput ( QX11Info : : display ( ) , wrapper , ClientWinMask | SubstructureNotifyMask ) ;
2005-01-15 17:07:48 +00:00
//as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it
//done xcompmgr workaround
2006-02-19 01:33:48 +00:00
// FRAME repaint( false );
2003-09-16 19:28:03 +00:00
// bool wasStaticContents = testWFlags( WStaticContents );
// setWFlags( WStaticContents );
2006-02-17 21:54:55 +00:00
int step = qMax ( 4 , QABS ( h - s . height ( ) ) / as ) + 1 ;
2003-09-16 19:28:03 +00:00
do
{
2002-02-27 21:01:01 +00:00
h - = step ;
2005-07-28 14:59:42 +00:00
XResizeWindow ( QX11Info : : display ( ) , frameId ( ) , s . width ( ) , h ) ;
2003-09-16 19:28:03 +00:00
resizeDecoration ( QSize ( s . width ( ) , h ) ) ;
2002-02-27 21:01:01 +00:00
QApplication : : syncX ( ) ;
2003-09-16 19:28:03 +00:00
} while ( h > s . height ( ) + step ) ;
// if ( !wasStaticContents )
// clearWFlags( WStaticContents );
2003-10-02 08:57:17 +00:00
plainResize ( s ) ;
2005-06-08 18:07:27 +00:00
shade_geometry_change = false ;
2003-09-16 19:28:03 +00:00
if ( isActive ( ) )
2004-02-16 15:19:39 +00:00
{
if ( was_shade_mode = = ShadeHover )
workspace ( ) - > activateNextClient ( this ) ;
else
workspace ( ) - > focusToNull ( ) ;
}
2005-01-15 17:07:48 +00:00
// tell xcompmgr shade's done
_shade = 2 ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , frameId ( ) , atoms - > net_wm_window_shade , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & _shade , 1L ) ;
2003-09-16 19:28:03 +00:00
}
else
{
2002-02-27 21:01:01 +00:00
int h = height ( ) ;
2003-09-24 11:01:14 +00:00
shade_geometry_change = true ;
2005-06-08 18:07:27 +00:00
QSize s ( sizeForClientSize ( clientSize ( ) ) ) ;
2003-09-16 19:28:03 +00:00
// FRAME bool wasStaticContents = testWFlags( WStaticContents );
// setWFlags( WStaticContents );
2006-02-17 21:54:55 +00:00
int step = qMax ( 4 , QABS ( h - s . height ( ) ) / as ) + 1 ;
2003-09-16 19:28:03 +00:00
do
{
2002-02-27 21:01:01 +00:00
h + = step ;
2005-07-28 14:59:42 +00:00
XResizeWindow ( QX11Info : : display ( ) , frameId ( ) , s . width ( ) , h ) ;
2003-09-16 19:28:03 +00:00
resizeDecoration ( QSize ( s . width ( ) , h ) ) ;
2002-02-27 21:01:01 +00:00
// assume a border
// we do not have time to wait for X to send us paint events
2006-02-19 01:33:48 +00:00
// FRAME repaint( 0, h - step-5, width(), step+5, true);
2002-02-27 21:01:01 +00:00
QApplication : : syncX ( ) ;
2003-09-16 19:28:03 +00:00
} while ( h < s . height ( ) - step ) ;
// if ( !wasStaticContents )
// clearWFlags( WStaticContents );
2003-09-24 11:01:14 +00:00
shade_geometry_change = false ;
2003-10-02 08:57:17 +00:00
plainResize ( s ) ;
2003-09-16 19:28:03 +00:00
if ( shade_mode = = ShadeHover | | shade_mode = = ShadeActivated )
2006-02-19 01:33:48 +00:00
setActive ( true ) ;
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , wrapperId ( ) ) ;
XMapWindow ( QX11Info : : display ( ) , window ( ) ) ;
XDeleteProperty ( QX11Info : : display ( ) , client , atoms - > net_wm_window_shade ) ;
2002-02-27 21:01:01 +00:00
if ( isActive ( ) )
workspace ( ) - > requestFocus ( this ) ;
2003-09-16 19:28:03 +00:00
}
2004-11-12 17:13:16 +00:00
checkMaximizeGeometry ( ) ;
2003-09-16 19:28:03 +00:00
info - > setState ( isShade ( ) ? NET : : Shaded : 0 , NET : : Shaded ) ;
2003-10-10 13:00:01 +00:00
info - > setState ( isShown ( false ) ? 0 : NET : : Hidden , NET : : Hidden ) ;
2005-05-11 14:46:23 +00:00
updateVisibility ( ) ;
2003-09-16 19:28:03 +00:00
updateAllowedActions ( ) ;
workspace ( ) - > updateMinimizedOfTransients ( this ) ;
decoration - > shadeChange ( ) ;
2004-06-11 15:12:29 +00:00
updateWindowRules ( ) ;
2003-09-16 19:28:03 +00:00
}
void Client : : shadeHover ( )
{
setShade ( ShadeHover ) ;
2005-05-06 15:20:49 +00:00
cancelShadeHover ( ) ;
}
void Client : : cancelShadeHover ( )
{
2003-09-16 19:28:03 +00:00
delete shadeHoverTimer ;
shadeHoverTimer = 0 ;
}
void Client : : toggleShade ( )
{
// if the mode is ShadeHover or ShadeActive, cancel shade too
setShade ( shade_mode = = ShadeNone ? ShadeNormal : ShadeNone ) ;
}
2005-04-12 17:22:47 +00:00
void Client : : updateVisibility ( )
2003-09-16 19:28:03 +00:00
{
2005-05-11 14:46:23 +00:00
if ( deleting )
return ;
2005-04-12 17:22:47 +00:00
bool show = true ;
if ( hidden )
2003-09-16 19:28:03 +00:00
{
2005-04-12 17:22:47 +00:00
setMappingState ( IconicState ) ;
info - > setState ( NET : : Hidden , NET : : Hidden ) ;
setSkipTaskbar ( true , false ) ; // also hide from taskbar
rawHide ( ) ;
show = false ;
2003-09-16 19:28:03 +00:00
}
else
{
2005-04-12 17:22:47 +00:00
setSkipTaskbar ( original_skip_taskbar , false ) ;
}
if ( minimized )
{
setMappingState ( IconicState ) ;
info - > setState ( NET : : Hidden , NET : : Hidden ) ;
2003-09-16 19:28:03 +00:00
rawHide ( ) ;
2005-04-12 17:22:47 +00:00
show = false ;
}
2005-05-13 08:57:21 +00:00
if ( show )
info - > setState ( 0 , NET : : Hidden ) ;
2005-04-12 17:22:47 +00:00
if ( ! isOnCurrentDesktop ( ) )
{
setMappingState ( IconicState ) ;
rawHide ( ) ;
show = false ;
}
if ( show )
{
2005-05-13 08:57:21 +00:00
if ( workspace ( ) - > showingDesktop ( ) )
workspace ( ) - > resetShowingDesktop ( true ) ;
2005-04-12 17:22:47 +00:00
if ( isShade ( ) )
setMappingState ( IconicState ) ;
else
setMappingState ( NormalState ) ;
rawShow ( ) ;
2003-09-16 19:28:03 +00:00
}
1999-08-19 23:26:42 +00:00
}
1999-11-29 14:19:32 +00:00
2003-09-16 19:28:03 +00:00
/*!
Sets the client window ' s mapping state . Possible values are
WithdrawnState , IconicState , NormalState .
*/
void Client : : setMappingState ( int s )
{
assert ( client ! = None ) ;
2005-05-11 14:46:23 +00:00
assert ( ! deleting | | s = = WithdrawnState ) ;
2003-09-16 19:28:03 +00:00
if ( mapping_state = = s )
return ;
bool was_unmanaged = ( mapping_state = = WithdrawnState ) ;
mapping_state = s ;
if ( mapping_state = = WithdrawnState )
{
2005-07-28 14:59:42 +00:00
XDeleteProperty ( QX11Info : : display ( ) , window ( ) , atoms - > wm_state ) ;
2003-09-16 19:28:03 +00:00
return ;
}
assert ( s = = NormalState | | s = = IconicState ) ;
2001-01-15 13:25:39 +00:00
2003-09-16 19:28:03 +00:00
unsigned long data [ 2 ] ;
data [ 0 ] = ( unsigned long ) s ;
data [ 1 ] = ( unsigned long ) None ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , window ( ) , atoms - > wm_state , atoms - > wm_state , 32 ,
2003-09-16 19:28:03 +00:00
PropModeReplace , ( unsigned char * ) data , 2 ) ;
1999-08-19 23:26:42 +00:00
2005-06-08 17:16:53 +00:00
if ( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
postponeGeometryUpdates ( false ) ;
2003-09-16 19:28:03 +00:00
}
1999-08-19 23:26:42 +00:00
/*!
2003-09-16 19:28:03 +00:00
Reimplemented to map the managed window in the window wrapper .
Proper mapping state should be set before showing the client .
*/
void Client : : rawShow ( )
2003-12-15 14:44:17 +00:00
{
2003-09-29 11:21:11 +00:00
if ( decoration ! = NULL )
decoration - > widget ( ) - > show ( ) ; // not really necessary, but let it know the state
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , frame ) ;
2003-09-16 19:28:03 +00:00
if ( ! isShade ( ) )
{
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , wrapper ) ;
XMapWindow ( QX11Info : : display ( ) , client ) ;
2003-09-16 19:28:03 +00:00
}
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
/*!
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.
2005-07-28 14:59:42 +00:00
XSelectInput ( QX11Info : : display ( ) , wrapper , ClientWinMask ) ; // avoid getting UnmapNotify
XUnmapWindow ( QX11Info : : display ( ) , frame ) ;
XUnmapWindow ( QX11Info : : display ( ) , wrapper ) ;
XUnmapWindow ( QX11Info : : display ( ) , client ) ;
XSelectInput ( QX11Info : : display ( ) , wrapper , ClientWinMask | SubstructureNotifyMask ) ;
2003-09-29 11:21:11 +00:00
if ( decoration ! = NULL )
decoration - > widget ( ) - > hide ( ) ; // not really necessary, but let it know the state
2003-09-16 19:28:03 +00:00
workspace ( ) - > clientHidden ( this ) ;
}
1999-08-19 23:26:42 +00:00
2004-04-16 10:23:42 +00:00
void Client : : sendClientMessage ( Window w , Atom a , Atom protocol , long data1 , long data2 , long data3 )
2003-09-16 19:28:03 +00:00
{
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 ;
2004-04-16 10:23:42 +00:00
ev . xclient . data . l [ 0 ] = protocol ;
2005-07-28 14:59:42 +00:00
ev . xclient . data . l [ 1 ] = QX11Info : : appTime ( ) ;
2004-04-16 10:23:42 +00:00
ev . xclient . data . l [ 2 ] = data1 ;
ev . xclient . data . l [ 3 ] = data2 ;
ev . xclient . data . l [ 4 ] = data3 ;
2003-09-16 19:28:03 +00:00
mask = 0L ;
2005-07-28 14:59:42 +00:00
if ( w = = QX11Info : : appRootWindow ( ) )
2003-09-16 19:28:03 +00:00
mask = SubstructureRedirectMask ; /* magic! */
2005-07-28 14:59:42 +00:00
XSendEvent ( QX11Info : : display ( ) , w , False , mask , & ev ) ;
2003-09-16 19:28:03 +00:00
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
/*
Returns whether the window may be closed ( have a close button )
1999-08-19 23:26:42 +00:00
*/
2003-09-16 19:28:03 +00:00
bool Client : : isCloseable ( ) const
{
2005-05-11 14:20:54 +00:00
return rules ( ) - > checkCloseable ( motif_may_close & & ! isSpecialWindow ( ) ) ;
2003-09-16 19:28:03 +00:00
}
1999-12-06 00:43:55 +00:00
2003-09-16 19:28:03 +00:00
/*!
Closes the window by either sending a delete_window message or
using XKill .
*/
void Client : : closeWindow ( )
{
if ( ! isCloseable ( ) )
2002-02-27 21:01:01 +00:00
return ;
2006-01-20 15:49:37 +00:00
// Update user time, because the window may create a confirming dialog.
updateUserTime ( ) ;
2003-09-16 19:28:03 +00:00
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 ( ) ;
}
2000-07-09 20:29:53 +00:00
}
2001-09-06 09:21:19 +00:00
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
/*!
Kills the window via XKill
*/
void Client : : killWindow ( )
{
2006-02-06 14:47:18 +00:00
kDebug ( 1212 ) < < " Client::killWindow(): " < < caption ( ) < < endl ;
2003-09-16 19:28:03 +00:00
// not sure if we need an Notify::Kill or not.. until then, use
// Notify::Close
Notify : : raise ( Notify : : Close ) ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
if ( isDialog ( ) )
Notify : : raise ( Notify : : TransDelete ) ;
if ( isNormalWindow ( ) )
Notify : : raise ( Notify : : Delete ) ;
killProcess ( false ) ;
// always kill this client at the server
2005-07-28 14:59:42 +00:00
XKillClient ( QX11Info : : display ( ) , window ( ) ) ;
2003-10-22 08:26:09 +00:00
destroyClient ( ) ;
2003-09-16 19:28:03 +00:00
}
2003-06-17 09:24:14 +00:00
2003-09-16 19:28:03 +00:00
// 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 :(
2004-06-11 15:01:18 +00:00
if ( options - > killPingTimeout = = 0 )
return ; // turned off
2003-09-16 19:28:03 +00:00
if ( ping_timer ! = NULL )
return ; // pinging already
ping_timer = new QTimer ( this ) ;
connect ( ping_timer , SIGNAL ( timeout ( ) ) , SLOT ( pingTimeout ( ) ) ) ;
2004-06-11 15:01:18 +00:00
ping_timer - > start ( options - > killPingTimeout , true ) ;
2005-07-28 14:59:42 +00:00
ping_timestamp = QX11Info : : appTime ( ) ;
2003-09-16 19:28:03 +00:00
workspace ( ) - > sendPingToWindow ( window ( ) , ping_timestamp ) ;
}
void Client : : gotPing ( Time timestamp )
{
if ( timestamp ! = ping_timestamp )
return ;
delete ping_timer ;
ping_timer = NULL ;
if ( process_killer ! = NULL )
{
process_killer - > kill ( ) ;
delete process_killer ;
process_killer = NULL ;
}
}
2000-07-09 20:29:53 +00:00
2003-09-16 19:28:03 +00:00
void Client : : pingTimeout ( )
{
2006-02-06 14:47:18 +00:00
kDebug ( 1212 ) < < " Ping timeout: " < < caption ( ) < < endl ;
2003-09-16 19:28:03 +00:00
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 ) ;
2005-07-28 14:59:42 +00:00
QByteArray machine = wmClientMachine ( true ) ;
2003-09-16 19:28:03 +00:00
pid_t pid = info - > pid ( ) ;
if ( pid < = 0 | | machine . isEmpty ( ) ) // needed properties missing
2002-02-27 21:01:01 +00:00
return ;
2006-02-06 14:47:18 +00:00
kDebug ( 1212 ) < < " Kill process: " < < pid < < " ( " < < machine < < " ) " < < endl ;
2003-09-16 19:28:03 +00:00
if ( ! ask )
{
if ( machine ! = " localhost " )
{
KProcess proc ;
2005-07-28 14:59:42 +00:00
proc < < " xon " < < machine < < " kill " < < QString : : number ( pid ) ;
2003-09-16 19:28:03 +00:00
proc . start ( KProcess : : DontCare ) ;
}
else
: : kill ( pid , SIGTERM ) ;
}
else
{ // SELI TODO handle the window created by handler specially (on top,urgent?)
process_killer = new KProcess ( this ) ;
* process_killer < < KStandardDirs : : findExe ( " kwin_killer_helper " )
2005-07-28 14:59:42 +00:00
< < " --pid " < < QByteArray ( ) . setNum ( pid ) < < " --hostname " < < machine
2005-09-24 12:26:22 +00:00
< < " --windowname " < < caption ( ) . toUtf8 ( )
2003-09-16 19:28:03 +00:00
< < " --applicationname " < < resourceClass ( )
2005-07-28 14:59:42 +00:00
< < " --wid " < < QString : : number ( window ( ) )
< < " --timestamp " < < QString : : number ( timestamp ) ;
2003-09-16 19:28:03 +00:00
connect ( process_killer , SIGNAL ( processExited ( KProcess * ) ) ,
SLOT ( processKillerExited ( ) ) ) ;
if ( ! process_killer - > start ( KProcess : : NotifyOnExit ) )
{
delete process_killer ;
process_killer = NULL ;
return ;
}
}
}
2000-06-28 13:20:42 +00:00
2003-09-16 19:28:03 +00:00
void Client : : processKillerExited ( )
{
2006-02-06 14:47:18 +00:00
kDebug ( 1212 ) < < " Killer exited " < < endl ;
2003-09-16 19:28:03 +00:00
delete process_killer ;
process_killer = NULL ;
}
2000-06-28 13:20:42 +00:00
2003-09-16 19:28:03 +00:00
void Client : : setSkipTaskbar ( bool b , bool from_outside )
{
2006-02-27 10:13:31 +00:00
int was_wants_tab_focus = wantsTabFocus ( ) ;
2003-09-16 19:28:03 +00:00
if ( from_outside )
2004-06-03 14:09:45 +00:00
{
b = rules ( ) - > checkSkipTaskbar ( b ) ;
2003-09-16 19:28:03 +00:00
original_skip_taskbar = b ;
2004-06-03 14:09:45 +00:00
}
2001-03-12 21:32:13 +00:00
if ( b = = skipTaskbar ( ) )
2002-02-27 21:01:01 +00:00
return ;
2001-03-12 21:32:13 +00:00
skip_taskbar = b ;
info - > setState ( b ? NET : : SkipTaskbar : 0 , NET : : SkipTaskbar ) ;
2004-06-11 15:12:29 +00:00
updateWindowRules ( ) ;
2006-02-27 10:13:31 +00:00
if ( was_wants_tab_focus ! = wantsTabFocus ( ) )
workspace ( ) - > updateFocusChains ( this , isActive ( ) ) ;
2003-09-16 19:28:03 +00:00
}
2001-03-12 21:32:13 +00:00
2001-05-02 20:37:30 +00:00
void Client : : setSkipPager ( bool b )
2003-09-16 19:28:03 +00:00
{
2004-06-03 14:09:45 +00:00
b = rules ( ) - > checkSkipPager ( b ) ;
2001-05-02 20:37:30 +00:00
if ( b = = skipPager ( ) )
2002-02-27 21:01:01 +00:00
return ;
2001-05-02 20:37:30 +00:00
skip_pager = b ;
info - > setState ( b ? NET : : SkipPager : 0 , NET : : SkipPager ) ;
2004-06-11 15:12:29 +00:00
updateWindowRules ( ) ;
2003-09-16 19:28:03 +00:00
}
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
}
2001-05-02 20:37:30 +00:00
2002-12-30 20:34:38 +00:00
void Client : : setDesktop ( int desktop )
2003-09-16 19:28:03 +00:00
{
2004-03-01 17:20:19 +00:00
if ( desktop ! = NET : : OnAllDesktops ) // do range check
2005-10-22 11:35:06 +00:00
desktop = qMax ( 1 , qMin ( workspace ( ) - > numberOfDesktops ( ) , desktop ) ) ;
2004-05-28 13:51:11 +00:00
desktop = rules ( ) - > checkDesktop ( desktop ) ;
2002-12-30 20:34:38 +00:00
if ( desk = = desktop )
return ;
int was_desk = desk ;
1999-11-22 01:57:51 +00:00
desk = desktop ;
2000-06-08 17:05:51 +00:00
info - > setDesktop ( desktop ) ;
2003-09-16 19:28:03 +00:00
if ( ( was_desk = = NET : : OnAllDesktops ) ! = ( desktop = = NET : : OnAllDesktops ) )
{ // onAllDesktops changed
2003-10-10 13:00:01 +00:00
if ( isShown ( true ) )
2003-09-16 19:28:03 +00:00
Notify : : raise ( isOnAllDesktops ( ) ? Notify : : OnAllDesktops : Notify : : NotOnAllDesktops ) ;
workspace ( ) - > updateOnAllDesktopsOfTransients ( this ) ;
}
if ( decoration ! = NULL )
decoration - > desktopChange ( ) ;
2006-02-27 10:13:31 +00:00
workspace ( ) - > updateFocusChains ( this , true ) ;
2005-04-12 17:22:47 +00:00
updateVisibility ( ) ;
2004-06-11 15:12:29 +00:00
updateWindowRules ( ) ;
2002-12-30 20:34:38 +00:00
}
2003-09-16 19:28:03 +00:00
void Client : : setOnAllDesktops ( bool b )
{
if ( ( b & & isOnAllDesktops ( ) )
| | ( ! b & & ! isOnAllDesktops ( ) ) )
2002-12-30 20:34:38 +00:00
return ;
if ( b )
setDesktop ( NET : : OnAllDesktops ) ;
else
setDesktop ( workspace ( ) - > currentDesktop ( ) ) ;
2001-01-11 23:41:07 +00:00
}
2003-09-16 19:28:03 +00:00
bool Client : : isOnCurrentDesktop ( ) const
{
return isOnDesktop ( workspace ( ) - > currentDesktop ( ) ) ;
1999-11-28 20:10:58 +00:00
}
1999-08-19 23:26:42 +00:00
2004-04-16 10:23:42 +00:00
// performs activation and/or raising of the window
void Client : : takeActivity ( int flags , bool handled , allowed_t )
2003-09-16 19:28:03 +00:00
{
2004-04-16 10:23:42 +00:00
if ( ! handled | | ! Ptakeactivity )
{
if ( flags & ActivityFocus )
takeFocus ( Allowed ) ;
if ( flags & ActivityRaise )
workspace ( ) - > raiseClient ( this ) ;
return ;
}
2000-07-11 14:38:17 +00:00
2004-04-16 10:23:42 +00:00
# ifndef NDEBUG
static Time previous_activity_timestamp ;
static Client * previous_client ;
2005-07-28 14:59:42 +00:00
if ( previous_activity_timestamp = = QX11Info : : appTime ( ) & & previous_client ! = this )
2004-04-16 10:23:42 +00:00
{
2006-02-06 14:47:18 +00:00
kDebug ( 1212 ) < < " Repeated use of the same X timestamp for activity " < < endl ;
kDebug ( 1212 ) < < kBacktrace ( ) < < endl ;
2004-04-16 10:23:42 +00:00
}
2005-07-28 14:59:42 +00:00
previous_activity_timestamp = QX11Info : : appTime ( ) ;
2004-04-16 10:23:42 +00:00
previous_client = this ;
# endif
2005-07-28 14:59:42 +00:00
workspace ( ) - > sendTakeActivity ( this , QX11Info : : appTime ( ) , flags ) ;
2004-04-16 10:23:42 +00:00
}
// performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
void Client : : takeFocus ( allowed_t )
{
2004-01-09 17:35:21 +00:00
# ifndef NDEBUG
static Time previous_focus_timestamp ;
2004-01-15 12:18:27 +00:00
static Client * previous_client ;
2005-07-28 14:59:42 +00:00
if ( previous_focus_timestamp = = QX11Info : : appTime ( ) & & previous_client ! = this )
2004-01-09 17:35:21 +00:00
{
2006-02-06 14:47:18 +00:00
kDebug ( 1212 ) < < " Repeated use of the same X timestamp for focus " < < endl ;
kDebug ( 1212 ) < < kBacktrace ( ) < < endl ;
2004-01-09 17:35:21 +00:00
}
2005-07-28 14:59:42 +00:00
previous_focus_timestamp = QX11Info : : appTime ( ) ;
2004-01-15 12:18:27 +00:00
previous_client = this ;
2004-01-09 17:35:21 +00:00
# endif
2004-06-09 08:30:06 +00:00
if ( rules ( ) - > checkAcceptFocus ( input ) )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
XSetInputFocus ( QX11Info : : display ( ) , window ( ) , RevertToPointerRoot , QX11Info : : appTime ( ) ) ;
2003-09-16 19:28:03 +00:00
}
1999-11-01 23:41:44 +00:00
if ( Ptakefocus )
2003-09-16 19:28:03 +00:00
sendClientMessage ( window ( ) , atoms - > wm_protocols , atoms - > wm_take_focus ) ;
2004-04-16 10:23:42 +00:00
workspace ( ) - > setShouldGetFocus ( this ) ;
2003-01-10 12:39:27 +00:00
}
1999-11-22 01:57:51 +00:00
1999-12-01 22:09:32 +00:00
/*!
Returns whether the window provides context help or not . If it does ,
2003-10-04 21:27:23 +00:00
you should show a help menu item or a help button like ' ? ' and call
1999-12-01 22:09:32 +00:00
contextHelp ( ) if this is invoked .
1999-12-06 00:43:55 +00:00
1999-12-01 22:09:32 +00:00
\ sa contextHelp ( )
*/
bool Client : : providesContextHelp ( ) const
2003-09-16 19:28:03 +00:00
{
1999-12-01 22:09:32 +00:00
return Pcontexthelp ;
2003-09-16 19:28:03 +00:00
}
1999-12-01 22:09:32 +00:00
/*!
Invokes context help on the window . Only works if the window
actually provides context help .
1999-12-06 00:43:55 +00:00
1999-12-01 22:09:32 +00:00
\ sa providesContextHelp ( )
*/
2003-09-16 19:28:03 +00:00
void Client : : showContextHelp ( )
{
if ( Pcontexthelp )
{
sendClientMessage ( window ( ) , atoms - > wm_protocols , atoms - > net_wm_context_help ) ;
QWhatsThis : : enterWhatsThisMode ( ) ; // SELI?
2002-07-05 20:00:02 +00:00
}
}
2003-09-16 19:28:03 +00:00
1999-11-29 02:06:41 +00:00
2003-09-16 19:28:03 +00:00
/*!
Fetches the window ' s caption ( WM_NAME property ) . It will be
stored in the client ' s caption ( ) .
*/
void Client : : fetchName ( )
{
2004-05-28 15:04:01 +00:00
setCaption ( readName ( ) ) ;
}
2003-09-16 19:28:03 +00:00
2004-05-28 15:04:01 +00:00
QString Client : : readName ( ) const
{
2003-09-16 19:28:03 +00:00
if ( info - > name ( ) & & info - > name ( ) [ 0 ] ! = ' \0 ' )
2004-05-28 15:04:01 +00:00
return QString : : fromUtf8 ( info - > name ( ) ) ;
2003-09-16 19:28:03 +00:00
else
2004-05-28 15:04:01 +00:00
return KWin : : readNameProperty ( window ( ) , XA_WM_NAME ) ;
}
KWIN_COMPARE_PREDICATE ( FetchNameInternalPredicate , const Client * , ( ! cl - > isSpecialWindow ( ) | | cl - > isToolbar ( ) ) & & cl ! = value & & cl - > caption ( ) = = value - > caption ( ) ) ;
2005-07-28 14:59:42 +00:00
void Client : : setCaption ( const QString & _s , bool force )
2004-05-28 15:04:01 +00:00
{
2005-07-28 14:59:42 +00:00
QString s = _s ;
2004-05-28 15:04:01 +00:00
if ( s ! = cap_normal | | force )
2003-09-16 19:28:03 +00:00
{
2004-08-25 11:49:30 +00:00
bool reset_name = force ;
2005-07-28 14:59:42 +00:00
for ( int i = 0 ;
2003-11-25 14:55:15 +00:00
i < s . length ( ) ;
+ + i )
if ( ! s [ i ] . isPrint ( ) )
2005-07-28 14:59:42 +00:00
s [ i ] = QChar ( ' ' ) ;
2003-10-15 09:48:22 +00:00
cap_normal = s ;
2003-09-16 19:28:03 +00:00
bool was_suffix = ( ! cap_suffix . isEmpty ( ) ) ;
2004-11-09 12:17:18 +00:00
QString machine_suffix ;
2005-02-07 14:35:53 +00:00
if ( wmClientMachine ( false ) ! = " localhost " & & ! isLocalMachine ( wmClientMachine ( false ) ) )
2004-11-09 13:45:21 +00:00
machine_suffix = " <@ " + wmClientMachine ( true ) + " > " ;
2005-02-07 15:17:26 +00:00
QString shortcut_suffix = ! shortcut ( ) . isNull ( ) ? ( " { " + shortcut ( ) . toString ( ) + " } " ) : " " ;
cap_suffix = machine_suffix + shortcut_suffix ;
2004-01-30 15:24:46 +00:00
if ( ( ! isSpecialWindow ( ) | | isToolbar ( ) ) & & workspace ( ) - > findClient ( FetchNameInternalPredicate ( this ) ) )
2003-09-16 19:28:03 +00:00
{
int i = 2 ;
do
{
2005-02-07 15:17:26 +00:00
cap_suffix = machine_suffix + " < " + QString : : number ( i ) + " > " + shortcut_suffix ;
2003-09-16 19:28:03 +00:00
i + + ;
2003-10-15 09:48:22 +00:00
} while ( workspace ( ) - > findClient ( FetchNameInternalPredicate ( this ) ) ) ;
2005-09-24 12:26:22 +00:00
info - > setVisibleName ( caption ( ) . toUtf8 ( ) ) ;
2003-11-13 17:51:11 +00:00
reset_name = false ;
2003-09-16 19:28:03 +00:00
}
2003-11-13 17:51:11 +00:00
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
2003-09-16 19:28:03 +00:00
{
info - > setVisibleName ( " " ) ; // remove
info - > setVisibleIconName ( " " ) ; // remove
}
2003-09-19 11:16:40 +00:00
else if ( ! cap_suffix . isEmpty ( ) & & ! cap_iconic . isEmpty ( ) ) // keep the same suffix in iconic name if it's set
2005-09-24 12:26:22 +00:00
info - > setVisibleIconName ( ( cap_iconic + cap_suffix ) . toUtf8 ( ) ) ;
2003-09-16 19:28:03 +00:00
if ( isManaged ( ) & & decoration ! = NULL )
decoration - > captionChange ( ) ;
2001-03-19 15:35:07 +00:00
}
2000-03-24 22:23:02 +00:00
}
2003-09-16 19:28:03 +00:00
2005-02-07 15:17:26 +00:00
void Client : : updateCaption ( )
{
setCaption ( cap_normal , true ) ;
}
2003-09-16 19:28:03 +00:00
void Client : : fetchIconicName ( )
{
QString s ;
if ( info - > iconName ( ) & & info - > iconName ( ) [ 0 ] ! = ' \0 ' )
s = QString : : fromUtf8 ( info - > iconName ( ) ) ;
else
s = KWin : : readNameProperty ( window ( ) , XA_WM_ICON_NAME ) ;
if ( s ! = cap_iconic )
{
2004-08-25 11:49:30 +00:00
bool was_set = ! cap_iconic . isEmpty ( ) ;
2003-09-16 19:28:03 +00:00
cap_iconic = s ;
2004-08-25 11:49:30 +00:00
if ( ! cap_suffix . isEmpty ( ) )
{
if ( ! cap_iconic . isEmpty ( ) ) // keep the same suffix in iconic name if it's set
2005-09-24 12:26:22 +00:00
info - > setVisibleIconName ( ( s + cap_suffix ) . toUtf8 ( ) ) ;
2004-08-25 11:49:30 +00:00
else if ( was_set )
info - > setVisibleIconName ( " " ) ; //remove
}
2003-09-16 19:28:03 +00:00
}
}
/*!\reimp
*/
2004-05-28 13:51:11 +00:00
QString Client : : caption ( bool full ) const
2003-09-16 19:28:03 +00:00
{
2004-05-28 13:51:11 +00:00
return full ? cap_normal + cap_suffix : cap_normal ;
2003-09-16 19:28:03 +00:00
}
void Client : : getWMHints ( )
{
2005-07-28 14:59:42 +00:00
XWMHints * hints = XGetWMHints ( QX11Info : : display ( ) , window ( ) ) ;
2003-09-16 19:28:03 +00:00
input = true ;
window_group = None ;
2003-10-10 11:23:42 +00:00
urgency = false ;
2003-09-16 19:28:03 +00:00
if ( hints )
{
2003-10-10 11:23:42 +00:00
if ( hints - > flags & InputHint )
2003-09-16 19:28:03 +00:00
input = hints - > input ;
if ( hints - > flags & WindowGroupHint )
window_group = hints - > window_group ;
2003-10-10 11:23:42 +00:00
urgency = ( hints - > flags & UrgencyHint ) ? true : false ; // true/false needed, it's uint bitfield
XFree ( ( char * ) hints ) ;
2003-09-16 19:28:03 +00:00
}
checkGroup ( ) ;
2003-10-10 11:23:42 +00:00
updateUrgency ( ) ;
2003-09-16 19:28:03 +00:00
updateAllowedActions ( ) ; // group affects isMinimizable()
}
2004-07-27 08:35:51 +00:00
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 ;
}
2005-06-24 15:14:02 +00:00
else
motif_may_resize = motif_may_move = true ;
2004-07-27 08:35:51 +00:00
// 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
}
2003-09-16 19:28:03 +00:00
void Client : : readIcons ( Window win , QPixmap * icon , QPixmap * miniicon )
{
// get the icons, allow scaling
if ( icon ! = NULL )
2006-02-19 01:33:48 +00:00
* icon = KWin : : icon ( win , 32 , 32 , true , KWin : : NETWM | KWin : : WMHints ) ;
2003-09-16 19:28:03 +00:00
if ( miniicon ! = NULL )
if ( icon = = NULL | | ! icon - > isNull ( ) )
2006-02-19 01:33:48 +00:00
* miniicon = KWin : : icon ( win , 16 , 16 , true , KWin : : NETWM | KWin : : WMHints ) ;
2003-09-16 19:28:03 +00:00
else
* miniicon = QPixmap ( ) ;
}
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
2006-02-19 01:33:48 +00:00
icon_pix = KWin : : icon ( window ( ) , 32 , 32 , true , KWin : : ClassHint | KWin : : XApp ) ;
miniicon_pix = KWin : : icon ( window ( ) , 16 , 16 , true , KWin : : ClassHint | KWin : : XApp ) ;
2003-09-16 19:28:03 +00:00
}
if ( isManaged ( ) & & decoration ! = NULL )
decoration - > iconChange ( ) ;
}
void Client : : getWindowProtocols ( )
{
Atom * p ;
int i , n ;
Pdeletewindow = 0 ;
Ptakefocus = 0 ;
2004-04-16 10:23:42 +00:00
Ptakeactivity = 0 ;
2003-09-16 19:28:03 +00:00
Pcontexthelp = 0 ;
Pping = 0 ;
2005-07-28 14:59:42 +00:00
if ( XGetWMProtocols ( QX11Info : : display ( ) , window ( ) , & p , & n ) )
2003-09-16 19:28:03 +00:00
{
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 ;
2004-04-16 10:23:42 +00:00
else if ( p [ i ] = = atoms - > net_wm_take_activity )
Ptakeactivity = 1 ;
2003-09-16 19:28:03 +00:00
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 ;
}
2000-03-24 22:23:02 +00:00
2001-03-19 15:35:07 +00:00
/*!
2002-10-22 20:41:49 +00:00
Returns WM_WINDOW_ROLE property for a given window .
2001-03-19 15:35:07 +00:00
*/
2005-07-28 14:59:42 +00:00
QByteArray Client : : staticWindowRole ( WId w )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
return getStringProperty ( w , atoms - > wm_window_role ) . lower ( ) ;
2003-09-16 19:28:03 +00:00
}
2001-03-19 15:35:07 +00:00
/*!
Returns SM_CLIENT_ID property for a given window .
*/
2005-07-28 14:59:42 +00:00
QByteArray Client : : staticSessionId ( WId w )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
return getStringProperty ( w , atoms - > sm_client_id ) ;
2003-09-16 19:28:03 +00:00
}
2001-03-19 15:35:07 +00:00
/*!
Returns WM_COMMAND property for a given window .
*/
2005-07-28 14:59:42 +00:00
QByteArray Client : : staticWmCommand ( WId w )
2003-09-16 19:28:03 +00:00
{
2001-03-19 15:35:07 +00:00
return getStringProperty ( w , XA_WM_COMMAND , ' ' ) ;
2003-09-16 19:28:03 +00:00
}
2001-03-19 15:35:07 +00:00
/*!
Returns WM_CLIENT_LEADER property for a given window .
*/
Window Client : : staticWmClientLeader ( WId w )
2003-09-16 19:28:03 +00:00
{
2000-03-24 22:23:02 +00:00
Atom type ;
2001-03-20 20:48:40 +00:00
int format , status ;
2001-03-19 15:35:07 +00:00
unsigned long nitems = 0 ;
unsigned long extra = 0 ;
unsigned char * data = 0 ;
Window result = w ;
2001-03-20 20:48:40 +00:00
XErrorHandler oldHandler = XSetErrorHandler ( nullErrorHandler ) ;
2005-07-28 14:59:42 +00:00
status = XGetWindowProperty ( QX11Info : : display ( ) , w , atoms - > wm_client_leader , 0 , 10000 ,
2006-02-19 01:33:48 +00:00
false , XA_WINDOW , & type , & format ,
2001-03-20 20:48:40 +00:00
& nitems , & extra , & data ) ;
XSetErrorHandler ( oldHandler ) ;
2003-09-16 19:28:03 +00:00
if ( status = = Success )
{
2001-03-19 15:35:07 +00:00
if ( data & & nitems > 0 )
result = * ( ( Window * ) data ) ;
XFree ( data ) ;
2003-09-16 19:28:03 +00:00
}
2000-03-24 22:23:02 +00:00
return result ;
2003-09-16 19:28:03 +00:00
}
2000-03-24 22:23:02 +00:00
2001-06-21 08:46:44 +00:00
2001-03-19 15:35:07 +00:00
void Client : : getWmClientLeader ( )
2003-09-16 19:28:03 +00:00
{
wmClientLeaderWin = staticWmClientLeader ( window ( ) ) ;
}
2000-08-30 14:27:30 +00:00
2001-03-19 15:35:07 +00:00
/*!
2001-03-20 21:05:57 +00:00
Returns sessionId for this client ,
2001-03-19 15:35:07 +00:00
taken either from its window or from the leader window .
*/
2005-07-28 14:59:42 +00:00
QByteArray Client : : sessionId ( )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
QByteArray result = staticSessionId ( window ( ) ) ;
2003-09-16 19:28:03 +00:00
if ( result . isEmpty ( ) & & wmClientLeaderWin & & wmClientLeaderWin ! = window ( ) )
2001-03-19 15:35:07 +00:00
result = staticSessionId ( wmClientLeaderWin ) ;
return result ;
2003-09-16 19:28:03 +00:00
}
2001-01-11 23:41:07 +00:00
2001-03-19 15:35:07 +00:00
/*!
2001-03-20 21:05:57 +00:00
Returns command property for this client ,
2001-03-19 15:35:07 +00:00
taken either from its window or from the leader window .
*/
2005-07-28 14:59:42 +00:00
QByteArray Client : : wmCommand ( )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
QByteArray result = staticWmCommand ( window ( ) ) ;
2003-09-16 19:28:03 +00:00
if ( result . isEmpty ( ) & & wmClientLeaderWin & & wmClientLeaderWin ! = window ( ) )
2001-03-19 15:35:07 +00:00
result = staticWmCommand ( wmClientLeaderWin ) ;
return result ;
2003-09-16 19:28:03 +00:00
}
2001-03-19 15:35:07 +00:00
2005-02-07 14:35:53 +00:00
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 " ;
}
2001-03-19 15:35:07 +00:00
/*!
2001-03-20 21:05:57 +00:00
Returns client machine for this client ,
2001-03-19 15:35:07 +00:00
taken either from its window or from the leader window .
*/
2005-07-28 14:59:42 +00:00
QByteArray Client : : wmClientMachine ( bool use_localhost ) const
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
QByteArray result = client_machine ;
2004-05-28 13:54:20 +00:00
if ( use_localhost )
{ // special name for the local machine (localhost)
if ( result ! = " localhost " & & isLocalMachine ( result ) )
result = " localhost " ;
}
2001-03-19 15:35:07 +00:00
return result ;
2003-09-16 19:28:03 +00:00
}
2001-03-19 15:35:07 +00:00
2001-03-20 21:05:57 +00:00
/*!
2001-03-19 15:35:07 +00:00
Returns client leader window for this client .
Returns the client window itself if no leader window is defined .
*/
2003-09-16 19:28:03 +00:00
Window Client : : wmClientLeader ( ) const
{
2001-03-19 15:35:07 +00:00
if ( wmClientLeaderWin )
return wmClientLeaderWin ;
2003-09-16 19:28:03 +00:00
return window ( ) ;
2002-07-05 20:05:22 +00:00
}
2000-06-22 18:08:35 +00:00
bool Client : : wantsTabFocus ( ) const
2003-09-16 19:28:03 +00:00
{
2005-05-19 12:06:04 +00:00
return ( isNormalWindow ( ) | | isDialog ( ) ) & & wantsInput ( ) ;
2003-09-16 19:28:03 +00:00
}
2000-06-22 18:08:35 +00:00
2000-09-25 15:30:51 +00:00
bool Client : : wantsInput ( ) const
2003-09-16 19:28:03 +00:00
{
2004-06-09 08:30:06 +00:00
return rules ( ) - > checkAcceptFocus ( input | | Ptakefocus ) ;
2003-09-16 19:28:03 +00:00
}
2000-09-25 15:30:51 +00:00
2000-06-22 18:08:35 +00:00
bool Client : : isDesktop ( ) const
2003-09-16 19:28:03 +00:00
{
2000-06-22 18:08:35 +00:00
return windowType ( ) = = NET : : Desktop ;
2003-09-16 19:28:03 +00:00
}
2000-06-22 18:08:35 +00:00
bool Client : : isDock ( ) const
2003-09-16 19:28:03 +00:00
{
2000-06-22 18:08:35 +00:00
return windowType ( ) = = NET : : Dock ;
2003-09-16 19:28:03 +00:00
}
2000-06-22 18:08:35 +00:00
2002-07-05 20:05:22 +00:00
bool Client : : isTopMenu ( ) const
2003-09-16 19:28:03 +00:00
{
2002-07-05 20:05:22 +00:00
return windowType ( ) = = NET : : TopMenu ;
2003-09-16 19:28:03 +00:00
}
2000-07-10 15:54:17 +00:00
2002-10-18 11:13:30 +00:00
bool Client : : isMenu ( ) const
2003-09-16 19:28:03 +00:00
{
return windowType ( ) = = NET : : Menu & & ! isTopMenu ( ) ; // because of backwards comp.
}
bool Client : : isToolbar ( ) const
{
return windowType ( ) = = NET : : Toolbar ;
}
2003-07-28 13:26:08 +00:00
bool Client : : isSplash ( ) const
2003-09-16 19:28:03 +00:00
{
2003-07-28 13:26:08 +00:00
return windowType ( ) = = NET : : Splash ;
2003-09-16 19:28:03 +00:00
}
2000-09-25 15:30:51 +00:00
2003-09-16 19:28:03 +00:00
bool Client : : isUtility ( ) const
{
return windowType ( ) = = NET : : Utility ;
}
2002-08-28 15:17:31 +00:00
2002-09-30 13:32:58 +00:00
bool Client : : isDialog ( ) const
2003-09-16 19:28:03 +00:00
{
return windowType ( ) = = NET : : Dialog ;
}
2002-09-30 13:32:58 +00:00
bool Client : : isNormalWindow ( ) const
2003-09-16 19:28:03 +00:00
{
return windowType ( ) = = NET : : Normal ;
}
2000-09-25 15:30:51 +00:00
2003-09-16 19:28:03 +00:00
bool Client : : isSpecialWindow ( ) const
{
return isDesktop ( ) | | isDock ( ) | | isSplash ( ) | | isTopMenu ( )
| | isToolbar ( ) ; // TODO
}
2004-05-31 14:04:49 +00:00
NET : : WindowType Client : : windowType ( bool direct , int supported_types ) const
2003-09-16 19:28:03 +00:00
{
NET : : WindowType wt = info - > windowType ( supported_types ) ;
2004-05-31 14:04:49 +00:00
if ( direct )
return wt ;
2004-05-28 15:04:01 +00:00
NET : : WindowType wt2 = rules ( ) - > checkType ( wt ) ;
if ( wt ! = wt2 )
{
wt = wt2 ;
info - > setWindowType ( wt ) ; // force hint change
}
2004-05-31 14:04:49 +00:00
// 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 ;
2003-09-16 19:28:03 +00:00
}
2004-05-31 14:04:49 +00:00
// TODO change this to rule
2005-07-28 14:59:42 +00:00
const char * const oo_prefix = " openoffice.org " ; // QByteArray has no startsWith()
2004-05-31 14:04:49 +00:00
// oo_prefix is lowercase, because resourceClass() is forced to be lowercase
if ( qstrncmp ( 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 ;
2003-09-16 19:28:03 +00:00
return wt ;
}
2000-06-22 18:08:35 +00:00
2000-06-23 16:26:44 +00:00
/*!
2003-09-16 19:28:03 +00:00
Sets an appropriate cursor shape for the logical mouse position \ a m
2000-06-23 16:26:44 +00:00
2000-06-22 14:12:13 +00:00
*/
2003-12-15 15:10:17 +00:00
void Client : : setCursor ( Position m )
2003-09-16 19:28:03 +00:00
{
2004-06-29 11:08:14 +00:00
if ( ! isResizable ( ) | | isShade ( ) )
2003-09-16 19:28:03 +00:00
{
2004-04-19 14:55:29 +00:00
m = PositionCenter ;
2002-02-27 21:01:01 +00:00
}
2003-09-16 19:28:03 +00:00
switch ( m )
{
2003-12-15 15:10:17 +00:00
case PositionTopLeft :
case PositionBottomRight :
2005-10-27 09:07:06 +00:00
setCursor ( Qt : : SizeFDiagCursor ) ;
2003-09-16 19:28:03 +00:00
break ;
2003-12-15 15:10:17 +00:00
case PositionBottomLeft :
case PositionTopRight :
2005-10-27 09:07:06 +00:00
setCursor ( Qt : : SizeBDiagCursor ) ;
2003-09-16 19:28:03 +00:00
break ;
2003-12-15 15:10:17 +00:00
case PositionTop :
case PositionBottom :
2005-10-27 09:07:06 +00:00
setCursor ( Qt : : SizeHorCursor ) ;
2003-09-16 19:28:03 +00:00
break ;
2003-12-15 15:10:17 +00:00
case PositionLeft :
case PositionRight :
2005-10-27 09:07:06 +00:00
setCursor ( Qt : : SizeHorCursor ) ;
2003-09-16 19:28:03 +00:00
break ;
default :
2004-05-31 14:25:25 +00:00
if ( buttonDown & & isMovable ( ) )
2005-10-27 09:07:06 +00:00
setCursor ( Qt : : SizeAllCursor ) ;
2004-03-05 14:22:11 +00:00
else
2005-10-27 09:07:06 +00:00
setCursor ( Qt : : ArrowCursor ) ;
2003-09-16 19:28:03 +00:00
break ;
2002-02-27 21:01:01 +00:00
}
2003-09-16 19:28:03 +00:00
}
2000-06-23 16:26:44 +00:00
2003-09-16 19:28:03 +00:00
// TODO mit nejake checkCursor(), ktere se zavola v manage() a pri vecech, kdy by se kurzor mohl zmenit?
void Client : : setCursor ( const QCursor & c )
{
if ( c . handle ( ) = = cursor . handle ( ) )
return ;
cursor = c ;
if ( decoration ! = NULL )
decoration - > widget ( ) - > setCursor ( cursor ) ;
2005-07-28 14:59:42 +00:00
XDefineCursor ( QX11Info : : display ( ) , frameId ( ) , cursor . handle ( ) ) ;
2003-09-16 19:28:03 +00:00
}
2000-07-09 20:29:53 +00:00
2003-12-15 15:10:17 +00:00
Client : : Position Client : : mousePosition ( const QPoint & p ) const
2003-09-16 19:28:03 +00:00
{
if ( decoration ! = NULL )
return decoration - > mousePosition ( p ) ;
2003-12-15 15:10:17 +00:00
return PositionCenter ;
2003-09-16 19:28:03 +00:00
}
2000-06-23 16:26:44 +00:00
2003-09-16 19:28:03 +00:00
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
}
2000-06-23 16:26:44 +00:00
2000-07-09 20:29:53 +00:00
void Client : : autoRaise ( )
2003-09-16 19:28:03 +00:00
{
2000-07-09 20:29:53 +00:00
workspace ( ) - > raiseClient ( this ) ;
2004-04-16 10:23:42 +00:00
cancelAutoRaise ( ) ;
2003-09-16 19:28:03 +00:00
}
2004-04-16 10:23:42 +00:00
2004-02-10 14:46:03 +00:00
void Client : : cancelAutoRaise ( )
{
delete autoRaiseTimer ;
autoRaiseTimer = 0 ;
}
2005-01-15 17:07:48 +00:00
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
2005-07-28 14:59:42 +00:00
// qWarning("setting opacity for %d",QX11Info::display());
2005-01-15 17:07:48 +00:00
//rule out activated translulcency with 100% opacity
if ( ! translucent | | opacity = = 0xFFFFFFFF )
{
opacity_ = 0xFFFFFFFF ;
2005-07-28 14:59:42 +00:00
XDeleteProperty ( QX11Info : : display ( ) , frameId ( ) , atoms - > net_wm_window_opacity ) ;
XDeleteProperty ( QX11Info : : display ( ) , 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
2005-01-15 17:07:48 +00:00
}
else {
if ( opacity = = opacity_ )
return ;
opacity_ = opacity ;
2005-01-27 09:58:34 +00:00
long data = opacity ; // 32bit XChangeProperty needs long
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , frameId ( ) , atoms - > net_wm_window_opacity , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & data , 1L ) ;
XChangeProperty ( QX11Info : : display ( ) , window ( ) , atoms - > net_wm_window_opacity , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & data , 1L ) ;
2005-01-15 17:07:48 +00:00
}
}
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)
2005-01-27 09:58:34 +00:00
long data = shadowSize ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , frameId ( ) , atoms - > net_wm_window_shadow , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & data , 1L ) ;
2005-01-15 17:07:48 +00:00
}
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
{
// qWarning("client found");
if ( ( * it ) - > touches ( this ) ) // first test, if the new client touches the just activated one
{
// qWarning("found client touches me");
if ( ruleOpacityActive ( ) )
( * it ) - > setOpacity ( rule_opacity_active < 0xFFFFFFFF , rule_opacity_active ) ;
else
( * it ) - > setOpacity ( options - > translucentActiveWindows , options - > activeWindowOpacity ) ;
// qWarning("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 ) )
{
// qWarning("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 ;
// qWarning("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
{
// qWarning("client found");
if ( ( * it ) - > touches ( this ) ) // first test, if the new client touches the just activated one
{
// qWarning("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 ) ;
// qWarning("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 ) )
{
// qWarning("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 ) ;
// qWarning("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 ;
2005-07-28 14:59:42 +00:00
result = XGetWindowProperty ( QX11Info : : display ( ) , window ( ) , atoms - > net_wm_window_opacity , 0L , 1L , False , XA_CARDINAL , & actual , & format , & n , & left , /*(unsigned char **)*/ & data ) ;
2005-04-04 13:11:53 +00:00
if ( result = = Success & & data ! = None & & format = = 32 )
2005-01-15 17:07:48 +00:00
{
2005-04-04 13:11:53 +00:00
opacity_ = * reinterpret_cast < long * > ( data ) ;
2005-01-15 17:07:48 +00:00
custom_opacity = true ;
// setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
2006-01-22 15:10:14 +00:00
XFree ( ( char * ) data ) ;
2006-02-19 01:33:48 +00:00
return true ;
2005-01-15 17:07:48 +00:00
}
2006-02-19 01:33:48 +00:00
return false ;
2005-01-15 17:07:48 +00:00
}
void Client : : setCustomOpacityFlag ( bool custom )
{
custom_opacity = custom ;
}
uint Client : : opacity ( )
{
return opacity_ ;
}
int Client : : opacityPercentage ( )
{
2005-01-27 09:58:34 +00:00
return int ( 100 * ( ( double ) opacity_ / 0xffffffff ) ) ;
2005-01-15 17:07:48 +00:00
}
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
2006-02-19 01:33:48 +00:00
return true ;
2005-01-15 17:07:48 +00:00
if ( y ( ) + height ( ) = = c - > y ( ) ) // this top to c
2006-02-19 01:33:48 +00:00
return true ;
2005-01-15 17:07:48 +00:00
if ( x ( ) = = c - > x ( ) + c - > width ( ) ) // this right to c
2006-02-19 01:33:48 +00:00
return true ;
2005-01-15 17:07:48 +00:00
if ( x ( ) + width ( ) = = c - > x ( ) ) // this left to c
2006-02-19 01:33:48 +00:00
return true ;
return false ;
2005-01-15 17:07:48 +00:00
}
2005-07-01 19:55:06 +00:00
void Client : : setDecoHashProperty ( uint topHeight , uint rightWidth , uint bottomHeight , uint leftWidth )
2005-02-09 18:31:35 +00:00
{
2005-07-01 19:55:06 +00:00
long data = ( topHeight < 255 ? topHeight : 255 ) < < 24 |
( rightWidth < 255 ? rightWidth : 255 ) < < 16 |
( bottomHeight < 255 ? bottomHeight : 255 ) < < 8 |
( leftWidth < 255 ? leftWidth : 255 ) ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , frameId ( ) , atoms - > net_wm_window_decohash , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) & data , 1L ) ;
2005-07-01 19:55:06 +00:00
}
void Client : : unsetDecoHashProperty ( )
{
2005-07-28 14:59:42 +00:00
XDeleteProperty ( QX11Info : : display ( ) , frameId ( ) , atoms - > net_wm_window_decohash ) ;
2005-02-09 18:31:35 +00:00
}
2004-06-18 08:57:42 +00:00
# ifndef NDEBUG
2003-09-16 19:28:03 +00:00
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 ( ) < < " \' " ;
}
2003-12-11 09:09:05 +00:00
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 ;
}
2003-09-16 19:28:03 +00:00
# endif
1999-08-19 23:26:42 +00:00
2000-09-07 22:55:18 +00:00
QPixmap * kwin_get_menu_pix_hack ( )
2003-09-16 19:28:03 +00:00
{
static QPixmap p ;
if ( p . isNull ( ) )
p = SmallIcon ( " bx2 " ) ;
return & p ;
}
2000-07-16 10:20:29 +00:00
2003-09-16 19:28:03 +00:00
} // namespace
2000-07-16 10:20:29 +00:00
2000-06-09 00:20:21 +00:00
# include "client.moc"