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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-03-19 15:35:07 +00:00
2000-07-29 07:59:24 +00:00
//#define QT_CLEAN_NAMESPACE
2001-03-19 15:35:07 +00:00
2003-09-16 19:28:03 +00:00
# include "workspace.h"
# include <kapplication.h>
# include <kstartupinfo.h>
# include <fixx11h.h>
1999-11-11 01:27:37 +00:00
# include <kconfig.h>
# include <kglobal.h>
1999-11-13 01:51:22 +00:00
# include <klocale.h>
2000-10-17 15:55:40 +00:00
# include <qregexp.h>
2003-09-16 19:28:03 +00:00
# include <qpainter.h>
# include <qbitmap.h>
2001-06-26 23:30:52 +00:00
# include <qclipboard.h>
2003-09-16 19:28:03 +00:00
# include <kmenubar.h>
2003-10-13 16:22:39 +00:00
# include <kprocess.h>
# include <kglobalaccel.h>
2005-01-21 04:58:54 +00:00
# include <dcopclient.h>
2005-07-28 14:59:42 +00:00
# include <QDesktopWidget>
2005-08-02 13:25:20 +00:00
# include <kipc.h>
2003-09-16 19:28:03 +00:00
# include "plugins.h"
1999-08-19 23:26:42 +00:00
# include "client.h"
2002-04-05 19:54:21 +00:00
# include "popupinfo.h"
2003-09-16 19:28:03 +00:00
# include "tabbox.h"
1999-08-19 23:26:42 +00:00
# include "atoms.h"
2003-09-16 19:28:03 +00:00
# include "placement.h"
# include "notifications.h"
# include "group.h"
2004-05-28 13:51:11 +00:00
# include "rules.h"
2003-09-16 19:28:03 +00:00
# include <X11/extensions/shape.h>
1999-08-19 23:26:42 +00:00
# include <X11/keysym.h>
1999-12-06 00:43:55 +00:00
# include <X11/keysymdef.h>
2000-05-17 23:02:42 +00:00
# include <X11/cursorfont.h>
2005-07-28 14:59:42 +00:00
# include <QX11Info>
# include <stdio.h>
2005-10-03 15:13:54 +00:00
# include <kauthorized.h>
2005-10-10 15:52:58 +00:00
# include <ktoolinvocation.h>
2000-06-23 16:26:44 +00:00
2003-09-16 19:28:03 +00:00
namespace KWinInternal
2000-06-22 14:12:13 +00:00
{
2002-06-25 07:42:01 +00:00
2003-09-16 19:28:03 +00:00
extern int screen_number ;
2000-06-21 17:43:44 +00:00
2001-04-22 06:51:07 +00:00
Workspace * Workspace : : _self = 0 ;
2005-04-07 10:20:44 +00:00
KProcess * kompmgr = 0 ;
2005-01-15 17:07:48 +00:00
bool allowKompmgrRestart = TRUE ;
2000-05-04 23:12:29 +00:00
// Rikkus: This class is too complex. It needs splitting further.
// It's a nightmare to understand, especially with so few comments :(
2000-06-22 14:12:13 +00:00
// Matthias: Feel free to ask me questions about it. Feel free to add
// comments. I dissagree that further splittings makes it easier. 2500
// lines are not too much. It's the task that is complex, not the
// code.
2000-03-24 22:23:02 +00:00
Workspace : : Workspace ( bool restore )
2003-06-04 18:06:21 +00:00
: DCOPObject ( " KWinInterface " ) ,
QObject ( 0 , " workspace " ) ,
2000-05-04 23:12:29 +00:00
current_desktop ( 0 ) ,
number_of_desktops ( 0 ) ,
2005-01-10 09:56:21 +00:00
active_popup ( NULL ) ,
active_popup_client ( NULL ) ,
2000-05-04 23:12:29 +00:00
desktop_widget ( 0 ) ,
2004-06-11 15:10:09 +00:00
temporaryRulesMessages ( " _KDE_NET_WM_TEMPORARY_RULES " , NULL , false ) ,
2000-05-04 23:12:29 +00:00
active_client ( 0 ) ,
2001-02-03 12:30:46 +00:00
last_active_client ( 0 ) ,
2000-10-02 12:02:15 +00:00
most_recently_raised ( 0 ) ,
2003-09-16 19:28:03 +00:00
movingClient ( 0 ) ,
2004-04-22 12:30:57 +00:00
pending_take_activity ( NULL ) ,
2004-05-28 08:53:44 +00:00
delayfocus_client ( 0 ) ,
2005-05-13 08:57:21 +00:00
showing_desktop ( false ) ,
block_showing_desktop ( 0 ) ,
2003-09-16 19:28:03 +00:00
was_user_interaction ( false ) ,
session_saving ( false ) ,
2000-05-04 23:12:29 +00:00
control_grab ( false ) ,
2001-02-16 18:05:27 +00:00
tab_grab ( false ) ,
2000-05-04 23:12:29 +00:00
mouse_emulation ( false ) ,
2004-01-09 17:35:21 +00:00
block_focus ( 0 ) ,
2001-02-16 18:05:27 +00:00
tab_box ( 0 ) ,
2002-04-05 19:54:21 +00:00
popupinfo ( 0 ) ,
2001-02-16 18:05:27 +00:00
popup ( 0 ) ,
2004-02-13 15:15:37 +00:00
advanced_popup ( 0 ) ,
2001-02-16 18:05:27 +00:00
desk_popup ( 0 ) ,
2003-09-16 19:28:03 +00:00
desk_popup_index ( 0 ) ,
2001-02-16 18:05:27 +00:00
keys ( 0 ) ,
2005-01-10 09:56:21 +00:00
client_keys ( NULL ) ,
client_keys_dialog ( NULL ) ,
client_keys_client ( NULL ) ,
2005-08-02 13:25:20 +00:00
disable_shortcuts_keys ( NULL ) ,
global_shortcuts_disabled ( false ) ,
global_shortcuts_disabled_for_client ( false ) ,
2003-09-16 19:28:03 +00:00
root ( 0 ) ,
workspaceInit ( true ) ,
startup ( 0 ) , electric_have_borders ( false ) ,
electric_current_border ( 0 ) ,
electric_top_border ( None ) ,
electric_bottom_border ( None ) ,
electric_left_border ( None ) ,
electric_right_border ( None ) ,
layoutOrientation ( Qt : : Vertical ) ,
layoutX ( - 1 ) ,
layoutY ( 2 ) ,
workarea ( NULL ) ,
2004-02-17 17:34:00 +00:00
screenarea ( NULL ) ,
2004-08-16 13:52:21 +00:00
managing_topmenus ( false ) ,
topmenu_selection ( NULL ) ,
topmenu_watcher ( NULL ) ,
topmenu_height ( 0 ) ,
topmenu_space ( NULL ) ,
2003-09-16 19:28:03 +00:00
set_active_client_recursion ( 0 ) ,
2004-02-10 09:24:57 +00:00
block_stacking_updates ( 0 ) ,
forced_global_mouse_grab ( false )
2003-09-16 19:28:03 +00:00
{
2001-04-22 06:51:07 +00:00
_self = this ;
2001-02-20 01:20:38 +00:00
mgr = new PluginMgr ;
2005-07-28 14:59:42 +00:00
root = QX11Info : : appRootWindow ( ) ;
QX11Info info ;
default_colormap = DefaultColormap ( QX11Info : : display ( ) , info . screen ( ) ) ;
2000-08-30 14:27:30 +00:00
installed_colormap = default_colormap ;
2000-03-24 22:23:02 +00:00
2004-06-11 15:10:09 +00:00
connect ( & temporaryRulesMessages , SIGNAL ( gotMessage ( const QString & ) ) ,
this , SLOT ( gotTemporaryRulesMessage ( const QString & ) ) ) ;
2004-06-11 15:12:29 +00:00
connect ( & rulesUpdatedTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( writeWindowRules ( ) ) ) ;
2004-06-11 15:10:09 +00:00
2003-09-16 19:28:03 +00:00
updateXTime ( ) ; // needed for proper initialization of user_time in Client ctor
2004-05-28 08:53:44 +00:00
delayFocusTimer = 0 ;
2005-07-28 14:59:42 +00:00
electric_time_first = QX11Info : : appTime ( ) ;
electric_time_last = QX11Info : : appTime ( ) ;
2003-10-10 12:48:09 +00:00
2000-03-24 22:23:02 +00:00
if ( restore )
2000-05-04 23:12:29 +00:00
loadSessionInfo ( ) ;
2001-02-01 01:13:44 +00:00
2004-05-28 13:51:11 +00:00
loadWindowRules ( ) ;
1999-08-19 23:26:42 +00:00
( void ) QApplication : : desktop ( ) ; // trigger creation of desktop widget
2000-05-04 23:12:29 +00:00
desktop_widget =
new QWidget (
2001-02-16 18:05:27 +00:00
0 ,
" desktop_widget " ,
2005-07-28 14:59:42 +00:00
Qt : : Desktop ) ;
desktop_widget - > setAttribute ( Qt : : WA_PaintUnclipped ) ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
kapp - > setGlobalMouseTracking ( true ) ; // so that this doesn't mess eventmask on root window later
2001-05-24 21:01:09 +00:00
// call this before XSelectInput() on the root window
2003-09-16 19:28:03 +00:00
startup = new KStartupInfo (
KStartupInfo : : DisableKWinModule | KStartupInfo : : AnnounceSilenceChanges , this ) ;
2001-05-24 21:01:09 +00:00
1999-08-19 23:26:42 +00:00
// select windowmanager privileges
2005-07-28 14:59:42 +00:00
XSelectInput ( QX11Info : : display ( ) , root ,
2001-02-16 18:05:27 +00:00
KeyPressMask |
PropertyChangeMask |
ColormapChangeMask |
SubstructureRedirectMask |
2004-02-02 14:17:01 +00:00
SubstructureNotifyMask |
FocusChangeMask // for NotifyDetailNone
2001-02-16 18:05:27 +00:00
) ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
Shape : : init ( ) ;
1999-11-14 06:34:28 +00:00
1999-11-13 03:44:09 +00:00
// compatibility
long data = 1 ;
1999-11-14 06:34:28 +00:00
2000-05-04 23:12:29 +00:00
XChangeProperty (
2005-07-28 14:59:42 +00:00
QX11Info : : display ( ) ,
QX11Info : : appRootWindow ( ) ,
2000-06-08 17:05:51 +00:00
atoms - > kwin_running ,
atoms - > kwin_running ,
2000-05-04 23:12:29 +00:00
32 ,
PropModeAppend ,
( unsigned char * ) & data ,
1
) ;
2005-01-10 09:56:21 +00:00
client_keys = new KGlobalAccel ( this ) ;
2002-01-19 04:55:32 +00:00
initShortcuts ( ) ;
1999-11-22 01:57:51 +00:00
tab_box = new TabBox ( this ) ;
2002-04-05 19:54:21 +00:00
popupinfo = new PopupInfo ( ) ;
2000-07-11 14:49:52 +00:00
2000-07-11 14:38:17 +00:00
init ( ) ;
2003-09-16 19:28:03 +00:00
connect ( kapp - > desktop ( ) , SIGNAL ( resized ( int ) ) , SLOT ( desktopResized ( ) ) ) ;
2005-01-15 17:07:48 +00:00
// start kompmgr - i wanted to put this into main.cpp, but that would prevent dcop support, as long as Application was no dcop_object
if ( options - > useTranslucency )
{
kompmgr = new KProcess ;
connect ( kompmgr , SIGNAL ( receivedStderr ( KProcess * , char * , int ) ) , SLOT ( handleKompmgrOutput ( KProcess * , char * , int ) ) ) ;
* kompmgr < < " kompmgr " ;
startKompmgr ( ) ;
}
2003-09-16 19:28:03 +00:00
}
1999-08-19 23:26:42 +00:00
void Workspace : : init ( )
2003-09-16 19:28:03 +00:00
{
2004-04-16 16:17:32 +00:00
checkElectricBorders ( ) ;
2001-08-27 05:42:32 +00:00
2005-01-15 17:07:48 +00:00
// not used yet
// topDock = 0L;
// maximizedWindowCounter = 0;
2000-06-08 17:05:51 +00:00
supportWindow = new QWidget ;
2005-07-28 14:59:42 +00:00
XLowerWindow ( QX11Info : : display ( ) , supportWindow - > winId ( ) ) ; // see usage in layers.cpp
2000-06-21 17:43:44 +00:00
2004-02-02 14:17:01 +00:00
XSetWindowAttributes attr ;
attr . override_redirect = 1 ;
2005-07-28 14:59:42 +00:00
null_focus_window = XCreateWindow ( QX11Info : : display ( ) , QX11Info : : appRootWindow ( ) , - 1 , - 1 , 1 , 1 , 0 , CopyFromParent ,
2004-02-02 14:17:01 +00:00
InputOnly , CopyFromParent , CWOverrideRedirect , & attr ) ;
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , null_focus_window ) ;
2004-02-02 14:17:01 +00:00
2003-09-16 19:28:03 +00:00
unsigned long protocols [ 5 ] =
2003-01-03 17:01:52 +00:00
{
2001-02-16 18:05:27 +00:00
NET : : Supported |
NET : : SupportingWMCheck |
NET : : ClientList |
NET : : ClientListStacking |
2003-01-03 17:01:52 +00:00
NET : : DesktopGeometry |
2001-02-16 18:05:27 +00:00
NET : : NumberOfDesktops |
NET : : CurrentDesktop |
NET : : ActiveWindow |
NET : : WorkArea |
NET : : CloseWindow |
NET : : DesktopNames |
NET : : KDESystemTrayWindows |
NET : : WMName |
NET : : WMVisibleName |
NET : : WMDesktop |
NET : : WMWindowType |
NET : : WMState |
NET : : WMStrut |
NET : : WMIconGeometry |
NET : : WMIcon |
NET : : WMPid |
2002-07-05 20:00:02 +00:00
NET : : WMMoveResize |
2001-02-16 18:05:27 +00:00
NET : : WMKDESystemTrayWinFor |
2005-06-21 09:00:28 +00:00
NET : : WMFrameExtents |
2003-09-16 19:28:03 +00:00
NET : : WMPing
2003-01-03 17:01:52 +00:00
,
NET : : NormalMask |
NET : : DesktopMask |
NET : : DockMask |
NET : : ToolbarMask |
NET : : MenuMask |
NET : : DialogMask |
NET : : OverrideMask |
NET : : TopMenuMask |
2003-09-16 19:28:03 +00:00
NET : : UtilityMask |
2003-07-28 13:26:08 +00:00
NET : : SplashMask |
2003-01-03 17:01:52 +00:00
0
,
2003-09-16 19:28:03 +00:00
NET : : Modal |
// NET::Sticky | // large desktops not supported (and probably never will be)
2003-01-03 17:01:52 +00:00
NET : : MaxVert |
NET : : MaxHoriz |
NET : : Shaded |
NET : : SkipTaskbar |
2003-01-10 12:31:57 +00:00
NET : : KeepAbove |
// NET::StaysOnTop | the same like KeepAbove
2003-01-03 17:01:52 +00:00
NET : : SkipPager |
2003-09-16 19:28:03 +00:00
NET : : Hidden |
NET : : FullScreen |
NET : : KeepBelow |
NET : : DemandsAttention |
0
,
NET : : WM2UserTime |
NET : : WM2StartupId |
NET : : WM2AllowedActions |
2003-09-30 15:15:21 +00:00
NET : : WM2RestackWindow |
2003-10-01 12:08:53 +00:00
NET : : WM2MoveResizeWindow |
2004-02-17 17:34:00 +00:00
NET : : WM2ExtendedStrut |
2004-06-11 15:10:09 +00:00
NET : : WM2KDETemporaryRules |
2005-05-13 08:57:21 +00:00
NET : : WM2ShowingDesktop |
2003-01-03 17:01:52 +00:00
0
2003-09-16 19:28:03 +00:00
,
NET : : ActionMove |
NET : : ActionResize |
NET : : ActionMinimize |
NET : : ActionShade |
// NET::ActionStick | // Sticky state is not supported
NET : : ActionMaxVert |
NET : : ActionMaxHoriz |
NET : : ActionFullScreen |
NET : : ActionChangeDesktop |
NET : : ActionClose |
0
,
2003-01-03 17:01:52 +00:00
} ;
2003-09-16 19:28:03 +00:00
2005-07-28 14:59:42 +00:00
QX11Info info ;
rootInfo = new RootInfo ( this , QX11Info : : display ( ) , supportWindow - > winId ( ) , " KWin " ,
protocols , 5 , info . screen ( ) ) ;
2000-07-12 18:08:24 +00:00
loadDesktopSettings ( ) ;
2003-09-16 19:28:03 +00:00
// extra NETRootInfo instance in Client mode is needed to get the values of the properties
2005-07-28 14:59:42 +00:00
NETRootInfo client_info ( QX11Info : : display ( ) , NET : : ActiveWindow | NET : : CurrentDesktop ) ;
2003-09-16 19:28:03 +00:00
int initial_desktop ;
if ( ! kapp - > isSessionRestored ( ) )
initial_desktop = client_info . currentDesktop ( ) ;
else
{
2005-11-19 08:06:46 +00:00
KConfigGroup group ( kapp - > sessionConfig ( ) , " Session " ) ;
2005-10-31 13:06:25 +00:00
initial_desktop = group . readNumEntry ( " desktop " , 1 ) ;
2003-09-16 19:28:03 +00:00
}
if ( ! setCurrentDesktop ( initial_desktop ) )
setCurrentDesktop ( 1 ) ;
1999-08-19 23:26:42 +00:00
2002-06-29 06:31:33 +00:00
// now we know how many desktops we'll, thus, we initialise the positioning object
2003-09-16 19:28:03 +00:00
initPositioning = new Placement ( this ) ;
2002-06-29 06:31:33 +00:00
2001-06-04 14:01:00 +00:00
connect ( & reconfigureTimer , SIGNAL ( timeout ( ) ) , this ,
SLOT ( slotReconfigure ( ) ) ) ;
2003-09-16 19:28:03 +00:00
connect ( & updateToolWindowsTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( slotUpdateToolWindows ( ) ) ) ;
2001-01-25 19:17:17 +00:00
2000-06-24 06:48:53 +00:00
connect ( kapp , SIGNAL ( appearanceChanged ( ) ) , this ,
2002-03-16 09:26:49 +00:00
SLOT ( slotReconfigure ( ) ) ) ;
2001-11-30 08:04:17 +00:00
connect ( kapp , SIGNAL ( settingsChanged ( int ) ) , this ,
SLOT ( slotSettingsChanged ( int ) ) ) ;
2005-08-02 13:25:20 +00:00
connect ( kapp , SIGNAL ( kipcMessage ( int , int ) ) , this , SLOT ( kipcMessage ( int , int ) ) ) ;
1999-12-24 01:36:47 +00:00
2003-09-16 19:28:03 +00:00
active_client = NULL ;
rootInfo - > setActiveWindow ( None ) ;
focusToNull ( ) ;
2004-01-09 17:35:21 +00:00
if ( ! kapp - > isSessionRestored ( ) )
+ + block_focus ; // because it will be set below
2003-09-16 19:28:03 +00:00
char nm [ 100 ] ;
2005-07-28 14:59:42 +00:00
sprintf ( nm , " _KDE_TOPMENU_OWNER_S%d " , DefaultScreen ( QX11Info : : display ( ) ) ) ;
Atom topmenu_atom = XInternAtom ( QX11Info : : display ( ) , nm , False ) ;
2003-09-16 19:28:03 +00:00
topmenu_selection = new KSelectionOwner ( topmenu_atom ) ;
topmenu_watcher = new KSelectionWatcher ( topmenu_atom ) ;
2003-12-04 13:54:10 +00:00
// TODO grabXServer(); - where exactly put this? topmenu selection claiming down belong must be before
2003-09-16 19:28:03 +00:00
{ // begin updates blocker block
StackingUpdatesBlocker blocker ( this ) ;
2003-11-12 09:47:13 +00:00
if ( options - > topMenuEnabled ( ) & & topmenu_selection - > claim ( false ) )
setupTopMenuHandling ( ) ; // this can call updateStackingOrder()
else
lostTopMenuSelection ( ) ;
2004-02-02 14:17:01 +00:00
unsigned int i , nwins ;
Window root_return , parent_return , * wins ;
2005-07-28 14:59:42 +00:00
XQueryTree ( QX11Info : : display ( ) , root , & root_return , & parent_return , & wins , & nwins ) ;
2004-05-17 12:06:45 +00:00
for ( i = 0 ; i < nwins ; i + + )
2003-09-16 19:28:03 +00:00
{
2004-02-02 14:17:01 +00:00
XWindowAttributes attr ;
2005-07-28 14:59:42 +00:00
XGetWindowAttributes ( QX11Info : : display ( ) , wins [ i ] , & attr ) ;
2003-09-16 19:28:03 +00:00
if ( attr . override_redirect )
2001-02-16 18:05:27 +00:00
continue ;
2003-11-12 09:47:13 +00:00
if ( topmenu_space & & topmenu_space - > winId ( ) = = wins [ i ] )
continue ;
2004-05-17 12:06:45 +00:00
if ( attr . map_state ! = IsUnmapped )
2003-09-16 19:28:03 +00:00
{
if ( addSystemTrayWin ( wins [ i ] ) )
continue ;
Client * c = createClient ( wins [ i ] , true ) ;
2005-07-28 14:59:42 +00:00
if ( c ! = NULL & & root ! = QX11Info : : appRootWindow ( ) )
2003-09-16 19:28:03 +00:00
{ // TODO what is this?
2001-02-16 18:05:27 +00:00
// TODO may use QWidget:.create
2005-07-28 14:59:42 +00:00
XReparentWindow ( QX11Info : : display ( ) , c - > frameId ( ) , root , 0 , 0 ) ;
2003-09-16 19:28:03 +00:00
c - > move ( 0 , 0 ) ;
}
}
2001-02-16 18:05:27 +00:00
}
2003-09-16 19:28:03 +00:00
if ( wins )
XFree ( ( void * ) wins ) ;
// propagate clients, will really happen at the end of the updates blocker block
updateStackingOrder ( true ) ;
1999-11-20 06:27:07 +00:00
2003-09-16 19:28:03 +00:00
updateClientArea ( ) ;
raiseElectricBorders ( ) ;
2002-06-29 06:31:33 +00:00
2002-06-28 20:28:33 +00:00
// NETWM spec says we have to set it to (0,0) if we don't support it
2003-09-16 19:28:03 +00:00
NETPoint * viewports = new NETPoint [ number_of_desktops ] ;
rootInfo - > setDesktopViewport ( number_of_desktops , * viewports ) ;
delete [ ] viewports ;
QRect geom = QApplication : : desktop ( ) - > geometry ( ) ;
NETSize desktop_geometry ;
desktop_geometry . width = geom . width ( ) ;
desktop_geometry . height = geom . height ( ) ;
2002-12-27 22:26:30 +00:00
// TODO update also after gaining XRANDR support
2003-09-16 19:28:03 +00:00
rootInfo - > setDesktopGeometry ( - 1 , desktop_geometry ) ;
2005-05-13 08:57:21 +00:00
setShowingDesktop ( false ) ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
} // end updates blocker block
Client * new_active_client = NULL ;
if ( ! kapp - > isSessionRestored ( ) )
2004-01-09 17:35:21 +00:00
{
- - block_focus ;
2003-09-16 19:28:03 +00:00
new_active_client = findClient ( WindowMatchPredicate ( client_info . activeWindow ( ) ) ) ;
2004-01-09 17:35:21 +00:00
}
2003-09-16 19:28:03 +00:00
if ( new_active_client = = NULL
& & activeClient ( ) = = NULL & & should_get_focus . count ( ) = = 0 ) // no client activated in manage()
{
if ( new_active_client = = NULL )
new_active_client = topClientOnDesktop ( currentDesktop ( ) ) ;
if ( new_active_client = = NULL & & ! desktops . isEmpty ( ) )
new_active_client = findDesktop ( true , currentDesktop ( ) ) ;
}
if ( new_active_client ! = NULL )
activateClient ( new_active_client ) ;
// SELI TODO this won't work with unreasonable focus policies,
// and maybe in rare cases also if the selected client doesn't
// want focus
workspaceInit = false ;
2003-12-04 13:54:10 +00:00
// TODO ungrabXServer()
1999-08-19 23:26:42 +00:00
}
2003-09-16 19:28:03 +00:00
Workspace : : ~ Workspace ( )
{
2005-01-15 17:07:48 +00:00
if ( kompmgr )
delete kompmgr ;
2003-09-16 19:28:03 +00:00
blockStackingUpdates ( true ) ;
2003-12-04 13:54:10 +00:00
// TODO grabXServer();
2003-09-16 19:28:03 +00:00
// use stacking_order, so that kwin --replace keeps stacking order
for ( ClientList : : ConstIterator it = stacking_order . begin ( ) ;
it ! = stacking_order . end ( ) ;
+ + it )
{
// only release the window
( * it ) - > releaseWindow ( true ) ;
2004-05-28 13:51:11 +00:00
// no removeClient() is called !
2003-09-16 19:28:03 +00:00
}
2000-09-14 06:03:47 +00:00
delete desktop_widget ;
1999-08-19 23:26:42 +00:00
delete tab_box ;
2002-04-05 19:54:21 +00:00
delete popupinfo ;
1999-08-19 23:26:42 +00:00
delete popup ;
2005-07-28 14:59:42 +00:00
if ( root = = QX11Info : : appRootWindow ( ) )
XDeleteProperty ( QX11Info : : display ( ) , QX11Info : : appRootWindow ( ) , atoms - > kwin_running ) ;
2001-01-14 20:16:04 +00:00
2004-05-28 13:51:11 +00:00
writeWindowRules ( ) ;
1999-12-03 19:04:03 +00:00
KGlobal : : config ( ) - > sync ( ) ;
2000-06-21 17:43:44 +00:00
2000-06-08 17:05:51 +00:00
delete rootInfo ;
delete supportWindow ;
2001-02-20 01:20:38 +00:00
delete mgr ;
2003-09-16 19:28:03 +00:00
delete [ ] workarea ;
2004-02-17 17:34:00 +00:00
delete [ ] screenarea ;
2003-09-16 19:28:03 +00:00
delete startup ;
delete initPositioning ;
delete topmenu_watcher ;
delete topmenu_selection ;
2003-11-12 09:47:13 +00:00
delete topmenu_space ;
2005-01-10 09:56:21 +00:00
delete client_keys_dialog ;
2004-06-18 08:57:42 +00:00
while ( ! rules . isEmpty ( ) )
2004-05-28 13:51:11 +00:00
{
2004-06-18 08:57:42 +00:00
delete rules . front ( ) ;
rules . pop_front ( ) ;
2004-05-28 13:51:11 +00:00
}
2005-07-28 14:59:42 +00:00
foreach ( SessionInfo * s , session )
delete s ;
XDestroyWindow ( QX11Info : : display ( ) , null_focus_window ) ;
2003-12-04 13:54:10 +00:00
// TODO ungrabXServer();
2001-04-22 06:51:07 +00:00
_self = 0 ;
2000-11-17 16:39:47 +00:00
}
2000-12-14 11:35:12 +00:00
2003-11-24 15:05:50 +00:00
Client * Workspace : : createClient ( Window w , bool is_mapped )
2003-09-16 19:28:03 +00:00
{
StackingUpdatesBlocker blocker ( this ) ;
Client * c = new Client ( this ) ;
2003-11-24 15:05:50 +00:00
if ( ! c - > manage ( w , is_mapped ) )
2003-09-16 19:28:03 +00:00
{
Client : : deleteClient ( c , Allowed ) ;
return NULL ;
2002-04-02 12:36:24 +00:00
}
2003-09-16 19:28:03 +00:00
addClient ( c , Allowed ) ;
return c ;
}
2000-03-21 20:02:27 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : addClient ( Client * c , allowed_t )
{
2005-01-15 17:07:48 +00:00
// waited with trans settings until window figured out if active or not ;)
// qWarning("%s", (const char*)(c->resourceClass()));
c - > setBMP ( c - > resourceName ( ) = = " beep-media-player " | | c - > decorationId ( ) = = None ) ;
// first check if the window has it's own opinion of it's translucency ;)
c - > getWindowOpacity ( ) ;
if ( c - > isDock ( ) )
{
// if (c->x() == 0 && c->y() == 0 && c->width() > c->height()) topDock = c;
if ( ! c - > hasCustomOpacity ( ) ) // this xould be done slightly more efficient, but we want to support the topDock in future
{
c - > setShadowSize ( options - > dockShadowSize ) ;
c - > setOpacity ( options - > translucentDocks , options - > dockOpacity ) ;
}
}
//------------------------------------------------
2003-09-16 19:28:03 +00:00
Group * grp = findGroup ( c - > window ( ) ) ;
if ( grp ! = NULL )
grp - > gotLeader ( c ) ;
2000-12-17 03:23:34 +00:00
2003-09-16 19:28:03 +00:00
if ( c - > isDesktop ( ) )
2003-11-10 18:09:16 +00:00
{
2003-09-16 19:28:03 +00:00
desktops . append ( c ) ;
2003-11-10 18:09:16 +00:00
if ( active_client = = NULL & & should_get_focus . isEmpty ( ) & & c - > isOnCurrentDesktop ( ) )
requestFocus ( c ) ; // CHECKME? make sure desktop is active after startup if there's no other window active
}
2003-09-16 19:28:03 +00:00
else
2001-02-16 18:05:27 +00:00
{
2003-09-16 19:28:03 +00:00
if ( c - > wantsTabFocus ( ) & & ! focus_chain . contains ( c ) )
focus_chain . append ( c ) ;
clients . append ( c ) ;
2001-02-16 18:05:27 +00:00
}
2003-09-16 19:28:03 +00:00
if ( ! unconstrained_stacking_order . contains ( c ) )
unconstrained_stacking_order . append ( c ) ;
2004-06-08 14:04:29 +00:00
if ( ! stacking_order . contains ( c ) ) // it'll be updated later, and updateToolWindows() requires
stacking_order . append ( c ) ; // c to be in stacking_order
2003-11-10 18:08:04 +00:00
if ( c - > isTopMenu ( ) )
addTopMenu ( c ) ;
2003-09-25 15:36:10 +00:00
updateClientArea ( ) ; // this cannot be in manage(), because the client got added only now
2003-09-16 19:28:03 +00:00
updateClientLayer ( c ) ;
if ( c - > isDesktop ( ) )
2001-08-27 05:42:32 +00:00
{
2003-09-16 19:28:03 +00:00
raiseClient ( c ) ;
// if there's no active client, make this desktop the active one
if ( activeClient ( ) = = NULL & & should_get_focus . count ( ) = = 0 )
activateClient ( findDesktop ( true , currentDesktop ( ) ) ) ;
2001-02-16 18:05:27 +00:00
}
2004-11-04 17:56:05 +00:00
c - > checkActiveModal ( ) ;
2003-09-16 19:28:03 +00:00
checkTransients ( c - > window ( ) ) ; // SELI does this really belong here?
updateStackingOrder ( true ) ; // propagate new client
2004-06-08 14:04:29 +00:00
if ( c - > isUtility ( ) | | c - > isMenu ( ) | | c - > isToolbar ( ) )
updateToolWindows ( true ) ;
1999-08-19 23:26:42 +00:00
}
2001-03-14 09:21:16 +00:00
1999-08-19 23:26:42 +00:00
/*
Destroys the client \ a c
*/
2003-09-16 19:28:03 +00:00
void Workspace : : removeClient ( Client * c , allowed_t )
{
2005-01-10 09:56:21 +00:00
if ( c = = active_popup_client )
closeActivePopup ( ) ;
if ( client_keys_client = = c )
setupWindowShortcutDone ( false ) ;
if ( ! c - > shortcut ( ) . isNull ( ) )
2005-01-17 15:53:14 +00:00
c - > setShortcut ( QString : : null ) ; // remove from client_keys
2002-03-11 05:02:50 +00:00
2003-09-16 19:28:03 +00:00
if ( c - > isDialog ( ) )
Notify : : raise ( Notify : : TransDelete ) ;
if ( c - > isNormalWindow ( ) )
Notify : : raise ( Notify : : Delete ) ;
Q_ASSERT ( clients . contains ( c ) | | desktops . contains ( c ) ) ;
clients . remove ( c ) ;
desktops . remove ( c ) ;
unconstrained_stacking_order . remove ( c ) ;
stacking_order . remove ( c ) ;
focus_chain . remove ( c ) ;
attention_chain . remove ( c ) ;
2003-11-10 18:08:04 +00:00
if ( c - > isTopMenu ( ) )
removeTopMenu ( c ) ;
2003-09-16 19:28:03 +00:00
Group * group = findGroup ( c - > window ( ) ) ;
if ( group ! = NULL )
group - > lostLeader ( ) ;
2001-03-14 09:21:16 +00:00
2000-10-02 12:02:15 +00:00
if ( c = = most_recently_raised )
2001-02-16 18:05:27 +00:00
most_recently_raised = 0 ;
2003-09-16 19:28:03 +00:00
should_get_focus . remove ( c ) ;
2002-12-28 00:25:19 +00:00
Q_ASSERT ( c ! = active_client ) ;
2001-02-03 12:30:46 +00:00
if ( c = = last_active_client )
2001-02-16 18:05:27 +00:00
last_active_client = 0 ;
2004-04-22 12:30:57 +00:00
if ( c = = pending_take_activity )
pending_take_activity = NULL ;
2004-08-03 14:15:41 +00:00
if ( c = = delayfocus_client )
cancelDelayFocus ( ) ;
2003-09-16 19:28:03 +00:00
updateStackingOrder ( true ) ;
2001-11-07 01:09:29 +00:00
if ( tab_grab )
tab_box - > repaint ( ) ;
2000-04-26 21:28:51 +00:00
updateClientArea ( ) ;
2003-09-16 19:28:03 +00:00
}
2001-07-09 03:10:16 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : updateCurrentTopMenu ( )
{
2003-12-15 18:30:14 +00:00
if ( ! managingTopMenus ( ) )
return ;
2003-09-16 19:28:03 +00:00
// toplevel menubar handling
Client * menubar = 0 ;
2003-11-12 09:47:13 +00:00
bool block_desktop_menubar = false ;
2003-09-16 19:28:03 +00:00
if ( active_client )
{
// show the new menu bar first...
Client * menu_client = active_client ;
for ( ; ; )
{
2003-11-12 09:47:13 +00:00
if ( menu_client - > isFullScreen ( ) )
block_desktop_menubar = true ;
2003-09-16 19:28:03 +00:00
for ( ClientList : : ConstIterator it = menu_client - > transients ( ) . begin ( ) ;
it ! = menu_client - > transients ( ) . end ( ) ;
+ + it )
if ( ( * it ) - > isTopMenu ( ) )
2003-11-10 18:08:59 +00:00
{
menubar = * it ;
break ;
}
2003-09-16 19:28:03 +00:00
if ( menubar ! = NULL | | ! menu_client - > isTransient ( ) )
break ;
if ( menu_client - > isModal ( ) | | menu_client - > transientFor ( ) = = NULL )
2003-11-12 09:47:13 +00:00
break ; // don't use mainwindow's menu if this is modal or group transient
2003-09-16 19:28:03 +00:00
menu_client = menu_client - > transientFor ( ) ;
}
2004-02-18 18:27:04 +00:00
if ( ! menubar )
{ // try to find any topmenu from the application (#72113)
for ( ClientList : : ConstIterator it = active_client - > group ( ) - > members ( ) . begin ( ) ;
it ! = active_client - > group ( ) - > members ( ) . end ( ) ;
+ + it )
if ( ( * it ) - > isTopMenu ( ) )
{
menubar = * it ;
break ;
}
}
2003-11-12 09:47:13 +00:00
}
2004-01-16 17:03:14 +00:00
if ( ! menubar & & ! block_desktop_menubar & & options - > desktopTopMenu ( ) )
2003-11-12 09:47:13 +00:00
{
// Find the menubar of the desktop
Client * desktop = findDesktop ( true , currentDesktop ( ) ) ;
if ( desktop ! = NULL )
2003-09-16 19:28:03 +00:00
{
2003-11-12 09:47:13 +00:00
for ( ClientList : : ConstIterator it = desktop - > transients ( ) . begin ( ) ;
it ! = desktop - > transients ( ) . end ( ) ;
+ + it )
if ( ( * it ) - > isTopMenu ( ) )
2003-09-16 19:28:03 +00:00
{
menubar = * it ;
break ;
}
}
2003-11-18 18:10:36 +00:00
// TODO to be cleaned app with window grouping
// Without qt-copy patch #0009, the topmenu and desktop are not in the same group,
// thus the topmenu is not transient for it :-/.
if ( menubar = = NULL )
{
for ( ClientList : : ConstIterator it = topmenus . begin ( ) ;
it ! = topmenus . end ( ) ;
+ + it )
2003-12-15 18:30:14 +00:00
if ( ( * it ) - > wasOriginallyGroupTransient ( ) ) // kdesktop's topmenu has WM_TRANSIENT_FOR
{ // set pointing to the root window
menubar = * it ; // to recognize it here
break ; // Also, with the xroot hack in kdesktop,
} // there's no NET::Desktop window to be transient for
2003-11-18 18:10:36 +00:00
}
2001-12-09 04:17:36 +00:00
}
2001-07-09 03:10:16 +00:00
2003-11-10 18:08:59 +00:00
// kdDebug() << "CURRENT TOPMENU:" << menubar << ":" << active_client << endl;
2003-09-16 19:28:03 +00:00
if ( menubar )
2003-11-11 18:51:10 +00:00
{
if ( active_client & & ! menubar - > isOnDesktop ( active_client - > desktop ( ) ) )
menubar - > setDesktop ( active_client - > desktop ( ) ) ;
2003-09-16 19:28:03 +00:00
menubar - > hideClient ( false ) ;
2003-12-15 18:30:14 +00:00
topmenu_space - > hide ( ) ;
2004-01-30 14:55:47 +00:00
// make it appear like it's been raised manually - it's in the Dock layer anyway,
// and not raising it could mess up stacking order of topmenus within one application,
// and thus break raising of mainclients in raiseClient()
unconstrained_stacking_order . remove ( menubar ) ;
unconstrained_stacking_order . append ( menubar ) ;
2003-12-15 18:30:14 +00:00
}
2004-01-16 17:03:14 +00:00
else if ( ! block_desktop_menubar )
2003-12-15 18:30:14 +00:00
{ // no topmenu active - show the space window, so that there's not empty space
topmenu_space - > show ( ) ;
2003-11-11 18:51:10 +00:00
}
2001-12-09 04:17:36 +00:00
2003-09-16 19:28:03 +00:00
// ... then hide the other ones. Avoids flickers.
2004-05-17 12:06:45 +00:00
for ( ClientList : : ConstIterator it = clients . begin ( ) ; it ! = clients . end ( ) ; + + it )
2003-09-16 19:28:03 +00:00
{
if ( ( * it ) - > isTopMenu ( ) & & ( * it ) ! = menubar )
( * it ) - > hideClient ( true ) ;
}
2002-01-19 04:55:32 +00:00
}
2001-03-28 12:44:31 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : updateToolWindows ( bool also_hide )
{
// TODO what if Client's transiency/group changes? should this be called too? (I'm paranoid, am I not?)
2005-05-11 14:49:01 +00:00
if ( ! options - > hideUtilityWindowsForInactive )
{
for ( ClientList : : ConstIterator it = clients . begin ( ) ;
it ! = clients . end ( ) ;
+ + it )
( * it ) - > hideClient ( false ) ;
return ;
}
2003-09-16 19:28:03 +00:00
const Group * group = NULL ;
const Client * client = active_client ;
// Go up in transiency hiearchy, if the top is found, only tool transients for the top mainwindow
// will be shown; if a group transient is group, all tools in the group will be shown
while ( client ! = NULL )
{
if ( ! client - > isTransient ( ) )
break ;
if ( client - > groupTransient ( ) )
{
group = client - > group ( ) ;
break ;
}
client = client - > transientFor ( ) ;
2001-03-19 20:05:36 +00:00
}
2003-09-16 19:28:03 +00:00
// use stacking order only to reduce flicker, it doesn't matter if block_stacking_updates == 0,
// i.e. if it's not up to date
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
// SELI but maybe it should - what if a new client has been added that's not in stacking order yet?
ClientList to_show , to_hide ;
for ( ClientList : : ConstIterator it = stacking_order . begin ( ) ;
it ! = stacking_order . end ( ) ;
+ + it )
{
if ( ( * it ) - > isUtility ( ) | | ( * it ) - > isMenu ( ) | | ( * it ) - > isToolbar ( ) )
{
bool show = true ;
if ( ! ( * it ) - > isTransient ( ) )
{
if ( ( * it ) - > group ( ) - > members ( ) . count ( ) = = 1 ) // has its own group, keep always visible
show = true ;
else if ( client ! = NULL & & ( * it ) - > group ( ) = = client - > group ( ) )
show = true ;
else
show = false ;
}
else
{
if ( group ! = NULL & & ( * it ) - > group ( ) = = group )
show = true ;
else if ( client ! = NULL & & client - > hasTransient ( ( * it ) , true ) )
show = true ;
else
show = false ;
}
2004-06-08 14:04:29 +00:00
if ( ! show & & also_hide )
{
const ClientList mainclients = ( * it ) - > mainClients ( ) ;
// don't hide utility windows which are standalone(?) or
// have e.g. kicker as mainwindow
if ( mainclients . isEmpty ( ) )
show = true ;
for ( ClientList : : ConstIterator it2 = mainclients . begin ( ) ;
it2 ! = mainclients . end ( ) ;
+ + it2 )
{
if ( ( * it2 ) - > isSpecialWindow ( ) )
show = true ;
}
if ( ! show )
to_hide . append ( * it ) ;
}
2003-09-16 19:28:03 +00:00
if ( show )
to_show . append ( * it ) ;
}
} // first show new ones, then hide
2005-07-28 14:59:42 +00:00
for ( int i = to_show . size ( ) - 1 ;
i > = 0 ;
- - i ) //from topmost
2003-09-16 19:28:03 +00:00
// TODO since this is in stacking order, the order of taskbar entries changes :(
2005-07-28 14:59:42 +00:00
to_show . at ( i ) - > hideClient ( false ) ;
2003-09-16 19:28:03 +00:00
if ( also_hide )
{
for ( ClientList : : ConstIterator it = to_hide . begin ( ) ;
it ! = to_hide . end ( ) ;
+ + it ) // from bottommost
( * it ) - > hideClient ( true ) ;
updateToolWindowsTimer . stop ( ) ;
}
else // setActiveClient() is after called with NULL client, quickly followed
{ // by setting a new client, which would result in flickering
updateToolWindowsTimer . start ( 50 , true ) ;
2001-12-09 04:17:36 +00:00
}
2001-03-19 20:05:36 +00:00
}
2001-06-10 04:10:42 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : slotUpdateToolWindows ( )
{
updateToolWindows ( true ) ;
2001-06-10 04:10:42 +00:00
}
2003-09-16 19:28:03 +00:00
/*!
Updates the current colormap according to the currently active client
*/
void Workspace : : updateColormap ( )
{
Colormap cmap = default_colormap ;
if ( activeClient ( ) & & activeClient ( ) - > colormap ( ) ! = None )
cmap = activeClient ( ) - > colormap ( ) ;
2004-05-17 12:06:45 +00:00
if ( cmap ! = installed_colormap )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
XInstallColormap ( QX11Info : : display ( ) , cmap ) ;
2003-09-16 19:28:03 +00:00
installed_colormap = cmap ;
}
2001-06-18 20:18:32 +00:00
}
2001-03-19 20:05:36 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : reconfigure ( )
{
reconfigureTimer . start ( 200 , true ) ;
2001-06-18 20:18:32 +00:00
}
2001-03-19 20:05:36 +00:00
2001-03-28 12:44:31 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : slotSettingsChanged ( int category )
{
kdDebug ( 1212 ) < < " Workspace::slotSettingsChanged() " < < endl ;
if ( category = = ( int ) KApplication : : SETTINGS_SHORTCUTS )
readShortcuts ( ) ;
2001-03-19 20:05:36 +00:00
}
2001-06-10 04:10:42 +00:00
2001-03-19 20:05:36 +00:00
/*!
2003-09-16 19:28:03 +00:00
Reread settings
2001-03-19 20:05:36 +00:00
*/
2003-09-16 19:28:03 +00:00
KWIN_PROCEDURE ( CheckBorderSizesProcedure , cl - > checkBorderSizes ( ) ) ;
2001-12-29 04:19:24 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : slotReconfigure ( )
2001-09-06 22:54:31 +00:00
{
2003-09-16 19:28:03 +00:00
kdDebug ( 1212 ) < < " Workspace::slotReconfigure() " < < endl ;
reconfigureTimer . stop ( ) ;
2001-06-03 22:29:12 +00:00
2003-09-16 19:28:03 +00:00
KGlobal : : config ( ) - > reparseConfiguration ( ) ;
unsigned long changed = options - > updateSettings ( ) ;
tab_box - > reconfigure ( ) ;
popupinfo - > reconfigure ( ) ;
2005-08-08 14:25:41 +00:00
initPositioning - > reinitCascading ( 0 ) ;
2003-09-16 19:28:03 +00:00
readShortcuts ( ) ;
2004-03-24 19:05:49 +00:00
forEachClient ( CheckIgnoreFocusStealingProcedure ( ) ) ;
2005-05-11 14:49:01 +00:00
updateToolWindows ( true ) ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
if ( mgr - > reset ( changed ) )
{ // decorations need to be recreated
2003-09-24 11:00:57 +00:00
#if 0 // This actually seems to make things worse now
2003-11-11 18:38:19 +00:00
QWidget curtain ;
2003-09-16 19:28:03 +00:00
curtain . setBackgroundMode ( NoBackground ) ;
curtain . setGeometry ( QApplication : : desktop ( ) - > geometry ( ) ) ;
curtain . show ( ) ;
2003-09-24 11:00:57 +00:00
# endif
2003-09-16 19:28:03 +00:00
for ( ClientList : : ConstIterator it = clients . begin ( ) ;
it ! = clients . end ( ) ;
+ + it )
{
( * it ) - > updateDecoration ( true , true ) ;
}
mgr - > destroyPreviousPlugin ( ) ;
}
else
{
forEachClient ( CheckBorderSizesProcedure ( ) ) ;
2001-02-16 18:05:27 +00:00
}
1999-08-19 23:26:42 +00:00
2004-04-16 16:17:32 +00:00
checkElectricBorders ( ) ;
1999-08-19 23:26:42 +00:00
2004-03-08 15:31:09 +00:00
if ( options - > topMenuEnabled ( ) & & ! managingTopMenus ( ) )
2003-11-12 09:47:13 +00:00
{
2004-03-08 15:31:09 +00:00
if ( topmenu_selection - > claim ( false ) )
2003-11-12 09:47:13 +00:00
setupTopMenuHandling ( ) ;
2004-03-08 15:31:09 +00:00
else
lostTopMenuSelection ( ) ;
2003-11-12 09:47:13 +00:00
}
2004-03-08 15:31:09 +00:00
else if ( ! options - > topMenuEnabled ( ) & & managingTopMenus ( ) )
2003-11-12 09:47:13 +00:00
{
2004-03-08 15:31:09 +00:00
topmenu_selection - > release ( ) ;
lostTopMenuSelection ( ) ;
2003-11-12 09:47:13 +00:00
}
2003-09-16 19:28:03 +00:00
topmenu_height = 0 ; // invalidate used menu height
if ( managingTopMenus ( ) )
{
2003-11-13 14:34:05 +00:00
updateTopMenuGeometry ( ) ;
2003-11-12 09:47:13 +00:00
updateCurrentTopMenu ( ) ;
2001-03-19 20:05:36 +00:00
}
2004-06-11 15:12:29 +00:00
loadWindowRules ( ) ;
2005-06-07 15:31:15 +00:00
for ( ClientList : : Iterator it = clients . begin ( ) ;
it ! = clients . end ( ) ;
+ + it )
{
( * it ) - > setupWindowRules ( true ) ;
( * it ) - > applyWindowRules ( ) ;
discardUsedWindowRules ( * it , false ) ;
}
2005-01-15 17:07:48 +00:00
if ( options - > resetKompmgr ) // need restart
{
bool tmp = options - > useTranslucency ;
stopKompmgr ( ) ;
if ( tmp )
QTimer : : singleShot ( 200 , this , SLOT ( startKompmgr ( ) ) ) ; // wait some time to ensure system's ready for restart
}
1999-08-19 23:26:42 +00:00
}
2003-09-16 19:28:03 +00:00
void Workspace : : loadDesktopSettings ( )
{
2004-08-26 14:06:33 +00:00
KConfig * c = KGlobal : : config ( ) ;
2005-07-28 14:59:42 +00:00
QString groupname ;
2003-09-16 19:28:03 +00:00
if ( screen_number = = 0 )
groupname = " Desktops " ;
else
groupname . sprintf ( " Desktops-screen-%d " , screen_number ) ;
2005-10-31 13:06:25 +00:00
KConfigGroup group ( c , groupname ) ;
2001-06-10 04:10:42 +00:00
2005-10-31 13:06:25 +00:00
int n = group . readNumEntry ( " Number " , 4 ) ;
2003-09-16 19:28:03 +00:00
number_of_desktops = n ;
delete workarea ;
workarea = new QRect [ n + 1 ] ;
2004-02-18 17:57:57 +00:00
delete screenarea ;
screenarea = NULL ;
2003-09-16 19:28:03 +00:00
rootInfo - > setNumberOfDesktops ( number_of_desktops ) ;
desktop_focus_chain . resize ( n ) ;
2004-05-17 12:06:45 +00:00
for ( int i = 1 ; i < = n ; i + + )
2003-09-16 19:28:03 +00:00
{
2005-10-31 13:06:25 +00:00
QString s = group . readEntry ( QString ( " Name_%1 " ) . arg ( i ) ,
2003-09-16 19:28:03 +00:00
i18n ( " Desktop %1 " ) . arg ( i ) ) ;
2005-09-24 12:26:22 +00:00
rootInfo - > setDesktopName ( i , s . toUtf8 ( ) . data ( ) ) ;
2003-09-16 19:28:03 +00:00
desktop_focus_chain [ i - 1 ] = i ;
2003-02-28 14:16:31 +00:00
}
2002-03-02 21:03:49 +00:00
}
2003-09-16 19:28:03 +00:00
void Workspace : : saveDesktopSettings ( )
{
2004-08-26 14:06:33 +00:00
KConfig * c = KGlobal : : config ( ) ;
2005-07-28 14:59:42 +00:00
QString groupname ;
2003-09-16 19:28:03 +00:00
if ( screen_number = = 0 )
groupname = " Desktops " ;
else
groupname . sprintf ( " Desktops-screen-%d " , screen_number ) ;
2005-10-31 13:06:25 +00:00
KConfigGroup group ( c , groupname ) ;
1999-08-19 23:26:42 +00:00
2005-10-31 13:06:25 +00:00
group . writeEntry ( " Number " , number_of_desktops ) ;
2004-05-17 12:06:45 +00:00
for ( int i = 1 ; i < = number_of_desktops ; i + + )
2003-09-16 19:28:03 +00:00
{
QString s = desktopName ( i ) ;
QString defaultvalue = i18n ( " Desktop %1 " ) . arg ( i ) ;
2004-05-17 12:06:45 +00:00
if ( s . isEmpty ( ) )
2003-09-16 19:28:03 +00:00
{
s = defaultvalue ;
2005-09-24 12:26:22 +00:00
rootInfo - > setDesktopName ( i , s . toUtf8 ( ) . data ( ) ) ;
2003-09-16 19:28:03 +00:00
}
1999-08-19 23:26:42 +00:00
2004-05-17 12:06:45 +00:00
if ( s ! = defaultvalue )
2003-09-16 19:28:03 +00:00
{
2005-10-31 13:06:25 +00:00
group . writeEntry ( QString ( " Name_%1 " ) . arg ( i ) , s ) ;
2003-09-16 19:28:03 +00:00
}
2004-05-17 12:06:45 +00:00
else
2003-09-16 19:28:03 +00:00
{
2005-10-31 13:06:25 +00:00
QString currentvalue = group . readEntry ( QString ( " Name_%1 " ) . arg ( i ) ) ;
2003-09-16 19:28:03 +00:00
if ( currentvalue ! = defaultvalue )
2005-10-31 13:06:25 +00:00
group . writeEntry ( QString ( " Name_%1 " ) . arg ( i ) , " " ) ;
2003-09-16 19:28:03 +00:00
}
}
}
1999-08-19 23:26:42 +00:00
2004-03-18 13:18:41 +00:00
QStringList Workspace : : configModules ( bool controlCenter )
2003-09-16 19:28:03 +00:00
{
QStringList args ;
2004-03-18 13:18:41 +00:00
args < < " kde-kwindecoration.desktop " ;
if ( controlCenter )
args < < " kde-kwinoptions.desktop " ;
2005-10-10 15:52:58 +00:00
else if ( KAuthorized : : authorizeControlModule ( " kde-kwinoptions.desktop " ) )
2005-01-15 17:07:48 +00:00
args < < " kwinactions " < < " kwinfocus " < < " kwinmoving " < < " kwinadvanced " < < " kwinrules " < < " kwintranslucency " ;
2004-03-18 13:18:41 +00:00
return args ;
}
void Workspace : : configureWM ( )
{
2005-10-10 15:52:58 +00:00
KToolInvocation : : kdeinitExec ( " kcmshell " , configModules ( false ) ) ;
2003-09-16 19:28:03 +00:00
}
1999-08-19 23:26:42 +00:00
2000-06-23 16:26:44 +00:00
/*!
2003-09-16 19:28:03 +00:00
avoids managing a window with title \ a title
1999-08-19 23:26:42 +00:00
*/
2003-09-16 19:28:03 +00:00
void Workspace : : doNotManage ( QString title )
{
doNotManageList . append ( title ) ;
2000-06-22 18:08:35 +00:00
}
1999-08-19 23:26:42 +00:00
/*!
2003-09-16 19:28:03 +00:00
Hack for java applets
1999-08-19 23:26:42 +00:00
*/
2003-09-16 19:28:03 +00:00
bool Workspace : : isNotManaged ( const QString & title )
2002-04-08 23:43:19 +00:00
{
2004-05-17 12:06:45 +00:00
for ( QStringList : : Iterator it = doNotManageList . begin ( ) ; it ! = doNotManageList . end ( ) ; + + it )
2002-04-08 23:43:19 +00:00
{
2003-09-16 19:28:03 +00:00
QRegExp r ( ( * it ) ) ;
2004-05-17 12:06:45 +00:00
if ( r . search ( title ) ! = - 1 )
2003-09-16 19:28:03 +00:00
{
doNotManageList . remove ( it ) ;
return TRUE ;
2001-02-16 18:05:27 +00:00
}
}
2003-09-16 19:28:03 +00:00
return FALSE ;
2000-07-10 15:54:17 +00:00
}
2000-07-11 12:15:58 +00:00
2003-09-16 19:28:03 +00:00
/*!
Refreshes all the client windows
*/
2004-05-17 12:06:45 +00:00
void Workspace : : refresh ( )
2003-09-16 19:28:03 +00:00
{
2003-11-11 18:38:19 +00:00
QWidget w ;
2003-09-16 19:28:03 +00:00
w . setGeometry ( QApplication : : desktop ( ) - > geometry ( ) ) ;
w . show ( ) ;
w . hide ( ) ;
2005-11-10 15:28:02 +00:00
QApplication : : flush ( ) ;
2000-07-10 15:54:17 +00:00
}
2000-06-21 17:43:44 +00:00
1999-08-19 23:26:42 +00:00
/*!
2003-09-16 19:28:03 +00:00
During virt . desktop switching , desktop areas covered by windows that are
going to be hidden are first obscured by new windows with no background
( i . e . transparent ) placed right below the windows . These invisible windows
are removed after the switch is complete .
Reduces desktop ( wallpaper ) repaints during desktop switching
*/
class ObscuringWindows
{
public :
~ ObscuringWindows ( ) ;
void create ( Client * c ) ;
private :
2005-07-28 14:59:42 +00:00
QList < Window > obscuring_windows ;
static QList < Window > * cached ;
2003-09-16 19:28:03 +00:00
static unsigned int max_cache_size ;
} ;
2001-09-06 09:21:19 +00:00
2005-07-28 14:59:42 +00:00
QList < Window > * ObscuringWindows : : cached = 0 ;
2003-09-16 19:28:03 +00:00
unsigned int ObscuringWindows : : max_cache_size = 0 ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
void ObscuringWindows : : create ( Client * c )
{
if ( cached = = 0 )
2005-07-28 14:59:42 +00:00
cached = new QList < Window > ;
2003-09-16 19:28:03 +00:00
Window obs_win ;
XWindowChanges chngs ;
int mask = CWSibling | CWStackMode ;
2004-05-17 12:06:45 +00:00
if ( cached - > count ( ) > 0 )
2003-09-16 19:28:03 +00:00
{
cached - > remove ( obs_win = cached - > first ( ) ) ;
chngs . x = c - > x ( ) ;
chngs . y = c - > y ( ) ;
chngs . width = c - > width ( ) ;
chngs . height = c - > height ( ) ;
mask | = CWX | CWY | CWWidth | CWHeight ;
2001-02-16 18:05:27 +00:00
}
2004-05-17 12:06:45 +00:00
else
2003-09-16 19:28:03 +00:00
{
XSetWindowAttributes a ;
a . background_pixmap = None ;
a . override_redirect = True ;
2005-07-28 14:59:42 +00:00
obs_win = XCreateWindow ( QX11Info : : display ( ) , QX11Info : : appRootWindow ( ) , c - > x ( ) , c - > y ( ) ,
2003-09-16 19:28:03 +00:00
c - > width ( ) , c - > height ( ) , 0 , CopyFromParent , InputOutput ,
CopyFromParent , CWBackPixmap | CWOverrideRedirect , & a ) ;
2001-02-16 18:05:27 +00:00
}
2003-09-16 19:28:03 +00:00
chngs . sibling = c - > frameId ( ) ;
chngs . stack_mode = Below ;
2005-07-28 14:59:42 +00:00
XConfigureWindow ( QX11Info : : display ( ) , obs_win , mask , & chngs ) ;
XMapWindow ( QX11Info : : display ( ) , obs_win ) ;
2003-09-16 19:28:03 +00:00
obscuring_windows . append ( obs_win ) ;
1999-11-28 20:10:58 +00:00
}
2003-09-16 19:28:03 +00:00
ObscuringWindows : : ~ ObscuringWindows ( )
{
2005-07-28 14:59:42 +00:00
max_cache_size = qMax ( ( int ) max_cache_size , obscuring_windows . count ( ) + 4 ) - 1 ;
for ( QList < Window > : : ConstIterator it = obscuring_windows . begin ( ) ;
2003-09-16 19:28:03 +00:00
it ! = obscuring_windows . end ( ) ;
2004-05-17 12:06:45 +00:00
+ + it )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
XUnmapWindow ( QX11Info : : display ( ) , * it ) ;
if ( cached - > count ( ) < ( int ) max_cache_size )
2003-09-16 19:28:03 +00:00
cached - > prepend ( * it ) ;
else
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , * it ) ;
2003-09-16 19:28:03 +00:00
}
}
1999-08-19 23:26:42 +00:00
2000-01-10 03:47:30 +00:00
/*!
2003-09-16 19:28:03 +00:00
Sets the current desktop to \ a new_desktop
2000-01-10 03:47:30 +00:00
2003-09-16 19:28:03 +00:00
Shows / Hides windows according to the stacking order and finally
propages the new desktop to the world
1999-11-28 20:55:52 +00:00
*/
2003-09-16 19:28:03 +00:00
bool Workspace : : setCurrentDesktop ( int new_desktop )
{
if ( new_desktop < 1 | | new_desktop > number_of_desktops )
return false ;
1999-11-28 20:55:52 +00:00
2005-01-10 09:56:21 +00:00
closeActivePopup ( ) ;
2004-01-09 17:35:21 +00:00
+ + block_focus ;
2003-11-20 09:05:32 +00:00
// TODO Q_ASSERT( block_stacking_updates == 0 ); // make sure stacking_order is up to date
2003-09-16 19:28:03 +00:00
StackingUpdatesBlocker blocker ( this ) ;
1999-11-28 20:55:52 +00:00
2005-05-06 09:24:51 +00:00
int old_desktop = current_desktop ;
2004-05-17 12:06:45 +00:00
if ( new_desktop ! = current_desktop )
2003-09-16 19:28:03 +00:00
{
2005-05-13 08:57:21 +00:00
+ + block_showing_desktop ;
2003-09-16 19:28:03 +00:00
/*
optimized Desktop switching : unmapping done from back to front
mapping done from front to back = > less exposure events
*/
Notify : : raise ( ( Notify : : Event ) ( Notify : : DesktopChange + new_desktop ) ) ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
ObscuringWindows obs_wins ;
2000-07-14 19:56:47 +00:00
2005-04-12 17:22:47 +00:00
current_desktop = new_desktop ; // change the desktop (so that Client::updateVisibility() works)
1999-11-29 14:19:32 +00:00
2003-09-16 19:28:03 +00:00
for ( ClientList : : ConstIterator it = stacking_order . begin ( ) ; it ! = stacking_order . end ( ) ; + + it )
if ( ! ( * it ) - > isOnDesktop ( new_desktop ) & & ( * it ) ! = movingClient )
2003-10-30 17:22:06 +00:00
{
if ( ( * it ) - > isShown ( true ) & & ( * it ) - > isOnDesktop ( old_desktop ) )
obs_wins . create ( * it ) ;
2005-04-12 17:22:47 +00:00
( * it ) - > updateVisibility ( ) ;
2003-10-30 17:22:06 +00:00
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
rootInfo - > setCurrentDesktop ( current_desktop ) ; // now propagate the change, after hiding, before showing
1999-08-19 23:26:42 +00:00
2003-10-30 17:22:06 +00:00
if ( movingClient & & ! movingClient - > isOnDesktop ( new_desktop ) )
movingClient - > setDesktop ( new_desktop ) ;
2005-07-28 14:59:42 +00:00
for ( int i = stacking_order . size ( ) - 1 ; i > = 0 ; - - i )
if ( stacking_order . at ( i ) - > isOnDesktop ( new_desktop ) )
stacking_order . at ( i ) - > updateVisibility ( ) ;
2005-05-13 08:57:21 +00:00
- - block_showing_desktop ;
if ( showingDesktop ( ) ) // do this only after desktop change to avoid flicker
resetShowingDesktop ( false ) ;
2003-09-16 19:28:03 +00:00
}
2000-08-30 14:27:30 +00:00
2003-09-16 19:28:03 +00:00
// restore the focus on this desktop
2004-01-09 17:35:21 +00:00
- - block_focus ;
2003-09-16 19:28:03 +00:00
Client * c = 0 ;
2000-08-30 14:27:30 +00:00
2004-05-17 12:06:45 +00:00
if ( options - > focusPolicyIsReasonable ( ) )
2003-09-16 19:28:03 +00:00
{
// Search in focus chain
1999-08-19 23:26:42 +00:00
2003-10-10 13:00:01 +00:00
if ( focus_chain . contains ( active_client ) & & active_client - > isShown ( true )
2003-09-16 19:28:03 +00:00
& & active_client - > isOnCurrentDesktop ( ) )
{
c = active_client ; // the requestFocus below will fail, as the client is already active
}
2000-07-09 20:29:53 +00:00
2004-05-17 12:06:45 +00:00
if ( ! c )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
for ( int i = focus_chain . size ( ) - 1 ;
i > = 0 ;
- - i )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
if ( focus_chain . at ( i ) - > isShown ( false ) & & ! focus_chain . at ( i ) - > isOnAllDesktops ( ) & & focus_chain . at ( i ) - > isOnCurrentDesktop ( ) )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
c = focus_chain . at ( i ) ;
2003-09-16 19:28:03 +00:00
break ;
}
}
}
2004-05-17 12:06:45 +00:00
if ( ! c )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
for ( int i = focus_chain . size ( ) - 1 ;
i > = 0 ;
- - i )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
if ( focus_chain . at ( i ) - > isShown ( false ) & & focus_chain . at ( i ) - > isOnCurrentDesktop ( ) )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
c = focus_chain . at ( i ) ;
2003-09-16 19:28:03 +00:00
break ;
}
2001-02-16 18:05:27 +00:00
}
}
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
//if "unreasonable focus policy"
// and active_client is on_all_desktops and under mouse (hence == old_active_client),
// conserve focus (thanks to Volker Schatz <V.Schatz at thphys.uni-heidelberg.de>)
2003-10-10 13:00:01 +00:00
else if ( active_client & & active_client - > isShown ( true ) & & active_client - > isOnCurrentDesktop ( ) )
2003-09-16 19:28:03 +00:00
c = active_client ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
if ( c ! = active_client )
setActiveClient ( NULL , Allowed ) ;
2002-08-22 17:16:47 +00:00
2004-05-17 12:06:45 +00:00
if ( c )
2003-09-16 19:28:03 +00:00
requestFocus ( c ) ;
2004-05-17 12:06:45 +00:00
else
2003-09-16 19:28:03 +00:00
focusToNull ( ) ;
2003-11-10 18:09:16 +00:00
2004-05-17 12:06:45 +00:00
if ( ! desktops . isEmpty ( ) )
2003-04-26 15:43:20 +00:00
{
2003-09-16 19:28:03 +00:00
Window w_tmp ;
int i_tmp ;
2005-07-28 14:59:42 +00:00
XGetInputFocus ( QX11Info : : display ( ) , & w_tmp , & i_tmp ) ;
2003-11-10 18:09:16 +00:00
if ( w_tmp = = null_focus_window ) // CHECKME?
2003-09-16 19:28:03 +00:00
requestFocus ( findDesktop ( true , currentDesktop ( ) ) ) ;
2003-04-26 15:43:20 +00:00
}
2000-03-21 20:02:27 +00:00
2004-08-16 13:52:21 +00:00
updateCurrentTopMenu ( ) ;
2003-09-16 19:28:03 +00:00
// Update focus chain:
// If input: chain = { 1, 2, 3, 4 } and current_desktop = 3,
// Output: chain = { 3, 1, 2, 4 }.
// kdDebug(1212) << QString("Switching to desktop #%1, at focus_chain index %2\n")
// .arg(current_desktop).arg(desktop_focus_chain.find( current_desktop ));
2005-07-28 14:59:42 +00:00
for ( int i = desktop_focus_chain . indexOf ( current_desktop ) ; i > 0 ; i - - )
2003-09-16 19:28:03 +00:00
desktop_focus_chain [ i ] = desktop_focus_chain [ i - 1 ] ;
desktop_focus_chain [ 0 ] = current_desktop ;
2000-03-21 20:02:27 +00:00
2003-09-16 19:28:03 +00:00
// QString s = "desktop_focus_chain[] = { ";
// for( uint i = 0; i < desktop_focus_chain.size(); i++ )
// s += QString::number(desktop_focus_chain[i]) + ", ";
// kdDebug(1212) << s << "}\n";
2005-05-06 09:24:51 +00:00
if ( old_desktop ! = 0 ) // not for the very first time
popupinfo - > showInfo ( desktopName ( currentDesktop ( ) ) ) ;
2003-09-16 19:28:03 +00:00
return true ;
1999-11-22 01:57:51 +00:00
}
2002-06-11 19:49:38 +00:00
2004-09-22 16:49:41 +00:00
// called only from DCOP
2003-09-16 19:28:03 +00:00
void Workspace : : nextDesktop ( )
{
int desktop = currentDesktop ( ) + 1 ;
setCurrentDesktop ( desktop > numberOfDesktops ( ) ? 1 : desktop ) ;
}
2002-06-11 19:49:38 +00:00
2004-09-22 16:49:41 +00:00
// called only from DCOP
2003-09-16 19:28:03 +00:00
void Workspace : : previousDesktop ( )
{
int desktop = currentDesktop ( ) - 1 ;
setCurrentDesktop ( desktop > 0 ? desktop : numberOfDesktops ( ) ) ;
}
2000-11-12 20:25:21 +00:00
2004-09-22 16:49:41 +00:00
int Workspace : : desktopToRight ( int desktop ) const
{
int x , y ;
calcDesktopLayout ( x , y ) ;
int dt = desktop - 1 ;
if ( layoutOrientation = = Qt : : Vertical )
{
dt + = y ;
if ( dt > = numberOfDesktops ( ) )
{
if ( options - > rollOverDesktops )
dt - = numberOfDesktops ( ) ;
else
return desktop ;
}
}
else
{
int d = ( dt % x ) + 1 ;
if ( d > = x )
{
if ( options - > rollOverDesktops )
d - = x ;
else
return desktop ;
}
dt = dt - ( dt % x ) + d ;
}
return dt + 1 ;
}
int Workspace : : desktopToLeft ( int desktop ) const
{
int x , y ;
calcDesktopLayout ( x , y ) ;
int dt = desktop - 1 ;
if ( layoutOrientation = = Qt : : Vertical )
{
dt - = y ;
if ( dt < 0 )
{
if ( options - > rollOverDesktops )
dt + = numberOfDesktops ( ) ;
else
return desktop ;
}
}
else
{
int d = ( dt % x ) - 1 ;
if ( d < 0 )
{
if ( options - > rollOverDesktops )
d + = x ;
else
return desktop ;
}
dt = dt - ( dt % x ) + d ;
}
return dt + 1 ;
}
int Workspace : : desktopUp ( int desktop ) const
{
int x , y ;
calcDesktopLayout ( x , y ) ;
int dt = desktop - 1 ;
if ( layoutOrientation = = Qt : : Horizontal )
{
dt - = x ;
if ( dt < 0 )
{
if ( options - > rollOverDesktops )
dt + = numberOfDesktops ( ) ;
else
return desktop ;
}
}
else
{
int d = ( dt % y ) - 1 ;
if ( d < 0 )
{
if ( options - > rollOverDesktops )
d + = y ;
else
return desktop ;
}
dt = dt - ( dt % y ) + d ;
}
return dt + 1 ;
}
int Workspace : : desktopDown ( int desktop ) const
{
int x , y ;
calcDesktopLayout ( x , y ) ;
int dt = desktop - 1 ;
if ( layoutOrientation = = Qt : : Horizontal )
{
dt + = x ;
if ( dt > = numberOfDesktops ( ) )
{
if ( options - > rollOverDesktops )
dt - = numberOfDesktops ( ) ;
else
return desktop ;
}
}
else
{
int d = ( dt % y ) + 1 ;
if ( d > = y )
{
if ( options - > rollOverDesktops )
d - = y ;
else
return desktop ;
}
dt = dt - ( dt % y ) + d ;
}
return dt + 1 ;
}
2003-09-16 19:28:03 +00:00
/*!
Sets the number of virtual desktops to \ a n
*/
void Workspace : : setNumberOfDesktops ( int n )
{
if ( n = = number_of_desktops )
2001-02-16 18:05:27 +00:00
return ;
2003-09-16 19:28:03 +00:00
int old_number_of_desktops = number_of_desktops ;
number_of_desktops = n ;
1999-11-29 14:19:32 +00:00
2003-09-16 19:28:03 +00:00
if ( currentDesktop ( ) > numberOfDesktops ( ) )
setCurrentDesktop ( numberOfDesktops ( ) ) ;
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
// if increasing the number, do the resizing now,
// otherwise after the moving of windows to still existing desktops
2004-05-17 12:06:45 +00:00
if ( old_number_of_desktops < number_of_desktops )
2003-09-16 19:28:03 +00:00
{
rootInfo - > setNumberOfDesktops ( number_of_desktops ) ;
NETPoint * viewports = new NETPoint [ number_of_desktops ] ;
rootInfo - > setDesktopViewport ( number_of_desktops , * viewports ) ;
delete [ ] viewports ;
updateClientArea ( true ) ;
}
1999-11-20 06:27:07 +00:00
2003-09-16 19:28:03 +00:00
// if the number of desktops decreased, move all
// windows that would be hidden to the last visible desktop
2004-05-17 12:06:45 +00:00
if ( old_number_of_desktops > number_of_desktops )
2003-09-16 19:28:03 +00:00
{
for ( ClientList : : ConstIterator it = clients . begin ( ) ;
it ! = clients . end ( ) ;
2004-05-17 12:06:45 +00:00
+ + it )
2003-09-16 19:28:03 +00:00
{
if ( ! ( * it ) - > isOnAllDesktops ( ) & & ( * it ) - > desktop ( ) > numberOfDesktops ( ) )
sendClientToDesktop ( * it , numberOfDesktops ( ) , true ) ;
}
}
2004-05-17 12:06:45 +00:00
if ( old_number_of_desktops > number_of_desktops )
2003-09-16 19:28:03 +00:00
{
rootInfo - > setNumberOfDesktops ( number_of_desktops ) ;
NETPoint * viewports = new NETPoint [ number_of_desktops ] ;
rootInfo - > setDesktopViewport ( number_of_desktops , * viewports ) ;
delete [ ] viewports ;
updateClientArea ( true ) ;
}
2002-10-18 11:26:55 +00:00
2003-09-16 19:28:03 +00:00
saveDesktopSettings ( ) ;
2000-06-22 14:12:13 +00:00
2003-09-16 19:28:03 +00:00
// Resize and reset the desktop focus chain.
desktop_focus_chain . resize ( n ) ;
for ( int i = 0 ; i < ( int ) desktop_focus_chain . size ( ) ; i + + )
desktop_focus_chain [ i ] = i + 1 ;
2001-01-14 20:16:04 +00:00
}
1999-12-03 21:08:07 +00:00
2000-06-23 16:26:44 +00:00
/*!
2003-09-16 19:28:03 +00:00
Sends client \ a c to desktop \ a desk .
Takes care of transients as well .
2000-06-22 14:12:13 +00:00
*/
2003-09-16 19:28:03 +00:00
void Workspace : : sendClientToDesktop ( Client * c , int desk , bool dont_activate )
{
2003-11-13 17:13:17 +00:00
bool was_on_desktop = c - > isOnDesktop ( desk ) | | c - > isOnAllDesktops ( ) ;
2003-09-16 19:28:03 +00:00
c - > setDesktop ( desk ) ;
2004-10-12 14:56:08 +00:00
if ( c - > desktop ( ) ! = desk ) // no change or desktop forced
2004-05-28 13:51:11 +00:00
return ;
2004-03-01 17:20:19 +00:00
desk = c - > desktop ( ) ; // Client did range checking
2000-06-08 17:05:51 +00:00
2003-09-16 19:28:03 +00:00
if ( c - > isOnDesktop ( currentDesktop ( ) ) )
{
if ( c - > wantsTabFocus ( ) & & options - > focusPolicyIsReasonable ( )
& & ! was_on_desktop // for stickyness changes
& & ! dont_activate )
requestFocus ( c ) ;
else
restackClientUnderActive ( c ) ;
}
2004-05-17 12:06:45 +00:00
else
2003-09-16 19:28:03 +00:00
{
raiseClient ( c ) ;
focus_chain . remove ( c ) ;
if ( c - > wantsTabFocus ( ) )
focus_chain . append ( c ) ;
}
2001-06-04 14:01:00 +00:00
2003-09-16 19:28:03 +00:00
ClientList transients_stacking_order = ensureStackingOrder ( c - > transients ( ) ) ;
for ( ClientList : : ConstIterator it = transients_stacking_order . begin ( ) ;
it ! = transients_stacking_order . end ( ) ;
+ + it )
sendClientToDesktop ( * it , desk , dont_activate ) ;
updateClientArea ( ) ;
}
2001-06-04 14:01:00 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : setDesktopLayout ( int o , int x , int y )
{
layoutOrientation = ( Qt : : Orientation ) o ;
layoutX = x ;
layoutY = y ;
}
2001-08-27 05:42:32 +00:00
2004-09-22 16:49:41 +00:00
void Workspace : : calcDesktopLayout ( int & x , int & y ) const
2003-09-16 19:28:03 +00:00
{
x = layoutX ;
y = layoutY ;
if ( ( x = = - 1 ) & & ( y > 0 ) )
x = ( numberOfDesktops ( ) + y - 1 ) / y ;
else if ( ( y = = - 1 ) & & ( x > 0 ) )
y = ( numberOfDesktops ( ) + x - 1 ) / x ;
2002-02-27 23:02:40 +00:00
2003-09-16 19:28:03 +00:00
if ( x = = - 1 )
x = 1 ;
if ( y = = - 1 )
y = 1 ;
}
2000-12-17 21:57:52 +00:00
2000-07-15 01:12:41 +00:00
/*!
2003-09-16 19:28:03 +00:00
Check whether \ a w is a system tray window . If so , add it to the respective
datastructures and propagate it to the world .
2000-07-15 01:12:41 +00:00
*/
2003-09-16 19:28:03 +00:00
bool Workspace : : addSystemTrayWin ( WId w )
{
if ( systemTrayWins . contains ( w ) )
return TRUE ;
2000-07-15 01:12:41 +00:00
2005-07-28 14:59:42 +00:00
NETWinInfo ni ( QX11Info : : display ( ) , w , root , NET : : WMKDESystemTrayWinFor ) ;
2003-09-16 19:28:03 +00:00
WId trayWinFor = ni . kdeSystemTrayWinFor ( ) ;
if ( ! trayWinFor )
return FALSE ;
systemTrayWins . append ( SystemTrayWindow ( w , trayWinFor ) ) ;
2005-07-28 14:59:42 +00:00
XSelectInput ( QX11Info : : display ( ) , w ,
2003-09-16 19:28:03 +00:00
StructureNotifyMask
) ;
2005-07-28 14:59:42 +00:00
XAddToSaveSet ( QX11Info : : display ( ) , w ) ;
2003-09-16 19:28:03 +00:00
propagateSystemTrayWins ( ) ;
return TRUE ;
2000-07-15 01:12:41 +00:00
}
2000-07-08 12:08:41 +00:00
/*!
2003-09-16 19:28:03 +00:00
Check whether \ a w is a system tray window . If so , remove it from
the respective datastructures and propagate this to the world .
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
*/
2003-10-30 10:10:54 +00:00
bool Workspace : : removeSystemTrayWin ( WId w , bool check )
2003-09-16 19:28:03 +00:00
{
if ( ! systemTrayWins . contains ( w ) )
return FALSE ;
2003-10-30 10:10:54 +00:00
if ( check )
{
// When getting UnmapNotify, it's not clear if it's the systray
// reparenting the window into itself, or if it's the window
// going away. This is obviously a flaw in the design, and we were
// just lucky it worked for so long. Kicker's systray temporarily
// sets _KDE_SYSTEM_TRAY_EMBEDDING property on the window while
// embedding it, allowing KWin to figure out. Kicker just mustn't
// crash before removing it again ... *shrug* .
int num_props ;
2005-07-28 14:59:42 +00:00
Atom * props = XListProperties ( QX11Info : : display ( ) , w , & num_props ) ;
2003-10-30 10:10:54 +00:00
if ( props ! = NULL )
{
for ( int i = 0 ;
i < num_props ;
+ + i )
if ( props [ i ] = = atoms - > kde_system_tray_embedding )
{
XFree ( props ) ;
return false ;
}
XFree ( props ) ;
}
}
2003-09-16 19:28:03 +00:00
systemTrayWins . remove ( w ) ;
propagateSystemTrayWins ( ) ;
return TRUE ;
2003-01-10 12:33:09 +00:00
}
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
2000-07-08 12:08:41 +00:00
/*!
2003-09-16 19:28:03 +00:00
Propagates the systemTrayWins to the world
1999-08-19 23:26:42 +00:00
*/
2003-09-16 19:28:03 +00:00
void Workspace : : propagateSystemTrayWins ( )
{
Window * cl = new Window [ systemTrayWins . count ( ) ] ;
2000-10-04 15:19:44 +00:00
2003-09-16 19:28:03 +00:00
int i = 0 ;
2004-05-17 12:06:45 +00:00
for ( SystemTrayWindowList : : ConstIterator it = systemTrayWins . begin ( ) ; it ! = systemTrayWins . end ( ) ; + + it )
2003-09-16 19:28:03 +00:00
{
cl [ i + + ] = ( * it ) . win ;
2001-02-16 18:05:27 +00:00
}
1999-11-13 02:35:15 +00:00
2003-09-16 19:28:03 +00:00
rootInfo - > setKDESystemTrayWindows ( cl , i ) ;
delete [ ] cl ;
2000-09-25 15:30:51 +00:00
}
2002-02-28 22:11:43 +00:00
2001-04-02 16:17:06 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : killWindowId ( Window window_to_kill )
2001-04-02 16:17:06 +00:00
{
2004-03-09 13:05:29 +00:00
if ( window_to_kill = = None )
return ;
2003-09-16 19:28:03 +00:00
Window window = window_to_kill ;
Client * client = NULL ;
2004-05-17 12:06:45 +00:00
for ( ; ; )
2003-09-16 19:28:03 +00:00
{
client = findClient ( FrameIdMatchPredicate ( window ) ) ;
if ( client ! = NULL ) // found the client
break ;
Window parent , root ;
Window * children ;
unsigned int children_count ;
2005-07-28 14:59:42 +00:00
XQueryTree ( QX11Info : : display ( ) , window , & root , & parent , & children , & children_count ) ;
2003-09-16 19:28:03 +00:00
if ( children ! = NULL )
XFree ( children ) ;
if ( window = = root ) // we didn't find the client, probably an override-redirect window
break ;
window = parent ; // go up
}
if ( client ! = NULL )
client - > killWindow ( ) ;
2001-04-02 16:17:06 +00:00
else
2005-07-28 14:59:42 +00:00
XKillClient ( QX11Info : : display ( ) , window_to_kill ) ;
2001-04-02 16:17:06 +00:00
}
1999-08-19 23:26:42 +00:00
2003-09-16 19:28:03 +00:00
void Workspace : : sendPingToWindow ( Window window , Time timestamp )
{
rootInfo - > sendPing ( window , timestamp ) ;
1999-08-19 23:26:42 +00:00
}
2004-04-22 12:30:57 +00:00
void Workspace : : sendTakeActivity ( Client * c , Time timestamp , long flags )
{
rootInfo - > takeActivity ( c - > window ( ) , timestamp , flags ) ;
pending_take_activity = c ;
}
2000-05-03 06:30:37 +00:00
2003-09-16 19:28:03 +00:00
/*!
Takes a screenshot of the current window and puts it in the clipboard .
*/
void Workspace : : slotGrabWindow ( )
{
2004-05-17 12:06:45 +00:00
if ( active_client )
2003-09-16 19:28:03 +00:00
{
QPixmap snapshot = QPixmap : : grabWindow ( active_client - > frameId ( ) ) ;
2000-06-28 13:20:42 +00:00
2003-09-16 19:28:03 +00:00
//No XShape - no work.
2004-05-17 12:06:45 +00:00
if ( Shape : : available ( ) )
2003-09-16 19:28:03 +00:00
{
//As the first step, get the mask from XShape.
int count , order ;
2005-07-28 14:59:42 +00:00
XRectangle * rects = XShapeGetRectangles ( QX11Info : : display ( ) , active_client - > frameId ( ) ,
2003-09-16 19:28:03 +00:00
ShapeBounding , & count , & order ) ;
//The ShapeBounding region is the outermost shape of the window;
//ShapeBounding - ShapeClipping is defined to be the border.
//Since the border area is part of the window, we use bounding
// to limit our work region
2004-05-17 12:06:45 +00:00
if ( rects )
2003-09-16 19:28:03 +00:00
{
//Create a QRegion from the rectangles describing the bounding mask.
QRegion contents ;
for ( int pos = 0 ; pos < count ; pos + + )
contents + = QRegion ( rects [ pos ] . x , rects [ pos ] . y ,
rects [ pos ] . width , rects [ pos ] . height ) ;
XFree ( rects ) ;
2000-06-28 13:20:42 +00:00
2003-09-16 19:28:03 +00:00
//Create the bounding box.
QRegion bbox ( 0 , 0 , snapshot . width ( ) , snapshot . height ( ) ) ;
2000-07-08 12:08:41 +00:00
2003-09-16 19:28:03 +00:00
//Get the masked away area.
QRegion maskedAway = bbox - contents ;
2005-07-28 14:59:42 +00:00
QVector < QRect > maskedAwayRects = maskedAway . rects ( ) ;
2003-09-16 19:28:03 +00:00
//Construct a bitmap mask from the rectangles
QBitmap mask ( snapshot . width ( ) , snapshot . height ( ) ) ;
QPainter p ( & mask ) ;
p . fillRect ( 0 , 0 , mask . width ( ) , mask . height ( ) , Qt : : color1 ) ;
2005-07-28 14:59:42 +00:00
for ( int pos = 0 ; pos < maskedAwayRects . count ( ) ; pos + + )
2003-09-16 19:28:03 +00:00
p . fillRect ( maskedAwayRects [ pos ] , Qt : : color0 ) ;
p . end ( ) ;
snapshot . setMask ( mask ) ;
}
}
2000-07-08 12:08:41 +00:00
2003-09-16 19:28:03 +00:00
QClipboard * cb = QApplication : : clipboard ( ) ;
cb - > setPixmap ( snapshot ) ;
}
else
slotGrabDesktop ( ) ;
2000-06-28 13:20:42 +00:00
}
1999-08-19 23:26:42 +00:00
/*!
2003-09-16 19:28:03 +00:00
Takes a screenshot of the whole desktop and puts it in the clipboard .
*/
void Workspace : : slotGrabDesktop ( )
{
2005-07-28 14:59:42 +00:00
QPixmap p = QPixmap : : grabWindow ( QX11Info : : appRootWindow ( ) ) ;
2003-09-16 19:28:03 +00:00
QClipboard * cb = QApplication : : clipboard ( ) ;
cb - > setPixmap ( p ) ;
}
1999-08-19 23:26:42 +00:00
2000-06-22 14:12:13 +00:00
2001-03-14 10:16:08 +00:00
/*!
2003-09-16 19:28:03 +00:00
Invokes keyboard mouse emulation
2001-03-14 10:16:08 +00:00
*/
2003-09-16 19:28:03 +00:00
void Workspace : : slotMouseEmulation ( )
{
2001-04-03 12:50:32 +00:00
2004-05-17 12:06:45 +00:00
if ( mouse_emulation )
2003-09-16 19:28:03 +00:00
{
2005-07-28 14:59:42 +00:00
XUngrabKeyboard ( QX11Info : : display ( ) , QX11Info : : appTime ( ) ) ;
2003-09-16 19:28:03 +00:00
mouse_emulation = FALSE ;
return ;
}
2001-04-03 12:50:32 +00:00
2005-07-28 14:59:42 +00:00
if ( XGrabKeyboard ( QX11Info : : display ( ) ,
2003-09-16 19:28:03 +00:00
root , FALSE ,
GrabModeAsync , GrabModeAsync ,
2005-07-28 14:59:42 +00:00
QX11Info : : appTime ( ) ) = = GrabSuccess )
2003-09-16 19:28:03 +00:00
{
mouse_emulation = TRUE ;
mouse_emulation_state = 0 ;
mouse_emulation_window = 0 ;
}
2001-04-03 12:50:32 +00:00
}
2000-06-22 14:12:13 +00:00
/*!
2003-09-16 19:28:03 +00:00
Returns the child window under the mouse and activates the
respective client if necessary .
2000-06-23 16:26:44 +00:00
2003-09-16 19:28:03 +00:00
Auxiliary function for the mouse emulation system .
2000-06-22 14:12:13 +00:00
*/
2003-09-16 19:28:03 +00:00
WId Workspace : : getMouseEmulationWindow ( )
{
Window root ;
2005-07-28 14:59:42 +00:00
Window child = QX11Info : : appRootWindow ( ) ;
2003-09-16 19:28:03 +00:00
int root_x , root_y , lx , ly ;
uint state ;
Window w ;
Client * c = 0 ;
2004-05-17 12:06:45 +00:00
do
2003-09-16 19:28:03 +00:00
{
w = child ;
if ( ! c )
c = findClient ( FrameIdMatchPredicate ( w ) ) ;
2005-07-28 14:59:42 +00:00
XQueryPointer ( QX11Info : : display ( ) , w , & root , & child ,
2003-09-16 19:28:03 +00:00
& root_x , & root_y , & lx , & ly , & state ) ;
} while ( child ! = None & & child ! = w ) ;
if ( c & & ! c - > isActive ( ) )
activateClient ( c ) ;
return ( WId ) w ;
2000-05-26 13:54:50 +00:00
}
2000-06-21 17:43:44 +00:00
2003-09-16 19:28:03 +00:00
/*!
Sends a faked mouse event to the specified window . Returns the new button state .
*/
unsigned int Workspace : : sendFakedMouseEvent ( QPoint pos , WId w , MouseEmulation type , int button , unsigned int state )
{
if ( ! w )
return state ;
QWidget * widget = QWidget : : find ( w ) ;
2004-05-17 12:06:45 +00:00
if ( ( ! widget | | widget - > inherits ( " QToolButton " ) ) & & ! findClient ( WindowMatchPredicate ( w ) ) )
2001-02-10 00:27:26 +00:00
{
2003-09-16 19:28:03 +00:00
int x , y ;
Window xw ;
2005-07-28 14:59:42 +00:00
XTranslateCoordinates ( QX11Info : : display ( ) , QX11Info : : appRootWindow ( ) , w , pos . x ( ) , pos . y ( ) , & x , & y , & xw ) ;
2004-05-17 12:06:45 +00:00
if ( type = = EmuMove )
2003-09-16 19:28:03 +00:00
{ // motion notify events
XMotionEvent e ;
e . type = MotionNotify ;
e . window = w ;
2005-07-28 14:59:42 +00:00
e . root = QX11Info : : appRootWindow ( ) ;
2003-09-16 19:28:03 +00:00
e . subwindow = w ;
2005-07-28 14:59:42 +00:00
e . time = QX11Info : : appTime ( ) ;
2003-09-16 19:28:03 +00:00
e . x = x ;
e . y = y ;
e . x_root = pos . x ( ) ;
e . y_root = pos . y ( ) ;
e . state = state ;
e . is_hint = NotifyNormal ;
2005-07-28 14:59:42 +00:00
XSendEvent ( QX11Info : : display ( ) , w , TRUE , ButtonMotionMask , ( XEvent * ) & e ) ;
2003-09-16 19:28:03 +00:00
}
2004-05-17 12:06:45 +00:00
else
2003-09-16 19:28:03 +00:00
{
XButtonEvent e ;
e . type = type = = EmuRelease ? ButtonRelease : ButtonPress ;
e . window = w ;
2005-07-28 14:59:42 +00:00
e . root = QX11Info : : appRootWindow ( ) ;
2003-09-16 19:28:03 +00:00
e . subwindow = w ;
2005-07-28 14:59:42 +00:00
e . time = QX11Info : : appTime ( ) ;
2003-09-16 19:28:03 +00:00
e . x = x ;
e . y = y ;
e . x_root = pos . x ( ) ;
e . y_root = pos . y ( ) ;
e . state = state ;
e . button = button ;
2005-07-28 14:59:42 +00:00
XSendEvent ( QX11Info : : display ( ) , w , TRUE , ButtonPressMask , ( XEvent * ) & e ) ;
2000-12-17 21:57:52 +00:00
2004-05-17 12:06:45 +00:00
if ( type = = EmuPress )
2003-09-16 19:28:03 +00:00
{
2004-05-17 12:06:45 +00:00
switch ( button )
2003-09-16 19:28:03 +00:00
{
case 2 :
state | = Button2Mask ;
break ;
case 3 :
state | = Button3Mask ;
break ;
default : // 1
state | = Button1Mask ;
break ;
}
}
2004-05-17 12:06:45 +00:00
else
2003-09-16 19:28:03 +00:00
{
2004-05-17 12:06:45 +00:00
switch ( button )
2003-09-16 19:28:03 +00:00
{
case 2 :
state & = ~ Button2Mask ;
break ;
case 3 :
state & = ~ Button3Mask ;
break ;
default : // 1
state & = ~ Button1Mask ;
break ;
}
}
}
2001-02-16 18:05:27 +00:00
}
2003-09-16 19:28:03 +00:00
return state ;
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
}
2000-06-22 14:12:13 +00:00
2000-06-23 16:26:44 +00:00
/*!
2003-09-16 19:28:03 +00:00
Handles keypress event during mouse emulation
2000-06-22 14:12:13 +00:00
*/
2003-09-16 19:28:03 +00:00
bool Workspace : : keyPressMouseEmulation ( XKeyEvent & ev )
{
2005-07-28 14:59:42 +00:00
if ( root ! = QX11Info : : appRootWindow ( ) )
2003-09-16 19:28:03 +00:00
return FALSE ;
2005-07-28 14:59:42 +00:00
int kc = XKeycodeToKeysym ( QX11Info : : display ( ) , ev . keycode , 0 ) ;
2003-09-16 19:28:03 +00:00
int km = ev . state & ( ControlMask | Mod1Mask | ShiftMask ) ;
bool is_control = km & ControlMask ;
bool is_alt = km & Mod1Mask ;
bool is_shift = km & ShiftMask ;
int delta = is_control ? 1 : is_alt ? 32 : 8 ;
QPoint pos = QCursor : : pos ( ) ;
2004-05-17 12:06:45 +00:00
switch ( kc )
2003-09-16 19:28:03 +00:00
{
case XK_Left :
case XK_KP_Left :
pos . rx ( ) - = delta ;
2001-12-09 04:17:36 +00:00
break ;
2003-09-16 19:28:03 +00:00
case XK_Right :
case XK_KP_Right :
pos . rx ( ) + = delta ;
2001-12-09 04:17:36 +00:00
break ;
2003-09-16 19:28:03 +00:00
case XK_Up :
case XK_KP_Up :
pos . ry ( ) - = delta ;
2001-12-09 04:17:36 +00:00
break ;
2003-09-16 19:28:03 +00:00
case XK_Down :
case XK_KP_Down :
pos . ry ( ) + = delta ;
break ;
case XK_F1 :
if ( ! mouse_emulation_state )
mouse_emulation_window = getMouseEmulationWindow ( ) ;
if ( ( mouse_emulation_state & Button1Mask ) = = 0 )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuPress , Button1 , mouse_emulation_state ) ;
if ( ! is_shift )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuRelease , Button1 , mouse_emulation_state ) ;
break ;
case XK_F2 :
if ( ! mouse_emulation_state )
mouse_emulation_window = getMouseEmulationWindow ( ) ;
if ( ( mouse_emulation_state & Button2Mask ) = = 0 )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuPress , Button2 , mouse_emulation_state ) ;
if ( ! is_shift )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuRelease , Button2 , mouse_emulation_state ) ;
break ;
case XK_F3 :
if ( ! mouse_emulation_state )
mouse_emulation_window = getMouseEmulationWindow ( ) ;
if ( ( mouse_emulation_state & Button3Mask ) = = 0 )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuPress , Button3 , mouse_emulation_state ) ;
if ( ! is_shift )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuRelease , Button3 , mouse_emulation_state ) ;
break ;
case XK_Return :
case XK_space :
case XK_KP_Enter :
2004-05-17 12:06:45 +00:00
case XK_KP_Space :
2003-09-16 19:28:03 +00:00
{
2004-05-17 12:06:45 +00:00
if ( ! mouse_emulation_state )
2003-09-16 19:28:03 +00:00
{
// nothing was pressed, fake a LMB click
mouse_emulation_window = getMouseEmulationWindow ( ) ;
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuPress , Button1 , mouse_emulation_state ) ;
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuRelease , Button1 , mouse_emulation_state ) ;
}
2004-05-17 12:06:45 +00:00
else
2003-09-16 19:28:03 +00:00
{ // release all
if ( mouse_emulation_state & Button1Mask )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuRelease , Button1 , mouse_emulation_state ) ;
if ( mouse_emulation_state & Button2Mask )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuRelease , Button2 , mouse_emulation_state ) ;
if ( mouse_emulation_state & Button3Mask )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuRelease , Button3 , mouse_emulation_state ) ;
}
}
// fall through
case XK_Escape :
2005-07-28 14:59:42 +00:00
XUngrabKeyboard ( QX11Info : : display ( ) , QX11Info : : appTime ( ) ) ;
2003-09-16 19:28:03 +00:00
mouse_emulation = FALSE ;
return TRUE ;
default :
return FALSE ;
}
2001-02-06 18:32:07 +00:00
2003-09-16 19:28:03 +00:00
QCursor : : setPos ( pos ) ;
if ( mouse_emulation_state )
mouse_emulation_state = sendFakedMouseEvent ( pos , mouse_emulation_window , EmuMove , 0 , mouse_emulation_state ) ;
return TRUE ;
2001-02-06 18:32:07 +00:00
2000-07-12 18:08:24 +00:00
}
2001-01-14 20:16:04 +00:00
2003-09-16 19:28:03 +00:00
/*!
Returns the workspace ' s desktop widget . The desktop widget is
sometimes required by clients to draw on it , for example outlines on
moving or resizing .
*/
QWidget * Workspace : : desktopWidget ( )
{
return desktop_widget ;
2000-07-12 18:08:24 +00:00
}
2004-05-28 08:53:44 +00:00
//Delayed focus functions
void Workspace : : delayFocus ( )
{
requestFocus ( delayfocus_client ) ;
cancelDelayFocus ( ) ;
}
void Workspace : : requestDelayFocus ( Client * c )
{
delayfocus_client = c ;
delete delayFocusTimer ;
delayFocusTimer = new QTimer ( this ) ;
connect ( delayFocusTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( delayFocus ( ) ) ) ;
delayFocusTimer - > start ( options - > delayFocusInterval , TRUE ) ;
}
void Workspace : : cancelDelayFocus ( )
{
delete delayFocusTimer ;
delayFocusTimer = 0 ;
}
2001-06-03 09:30:19 +00:00
2001-08-27 05:42:32 +00:00
// Electric Borders
//========================================================================//
// Electric Border Window management. Electric borders allow a user
// to change the virtual desktop by moving the mouse pointer to the
// borders. Technically this is done with input only windows. Since
// electric borders can be switched on and off, we have these two
// functions to create and destroy them.
2004-11-02 15:19:01 +00:00
void Workspace : : checkElectricBorders ( bool force )
2003-09-16 19:28:03 +00:00
{
2004-11-02 15:19:01 +00:00
if ( force )
destroyBorderWindows ( ) ;
2003-09-16 19:28:03 +00:00
electric_current_border = 0 ;
2001-08-27 05:42:32 +00:00
QRect r = QApplication : : desktop ( ) - > geometry ( ) ;
2003-09-16 19:28:03 +00:00
electricTop = r . top ( ) ;
electricBottom = r . bottom ( ) ;
electricLeft = r . left ( ) ;
electricRight = r . right ( ) ;
2001-08-27 05:42:32 +00:00
2004-05-17 12:06:45 +00:00
if ( options - > electricBorders ( ) = = Options : : ElectricAlways )
2004-05-15 02:38:47 +00:00
createBorderWindows ( ) ;
2004-05-17 12:06:45 +00:00
else
destroyBorderWindows ( ) ;
2004-04-16 16:17:32 +00:00
}
void Workspace : : createBorderWindows ( )
{
if ( electric_have_borders )
return ;
electric_have_borders = true ;
QRect r = QApplication : : desktop ( ) - > geometry ( ) ;
2001-08-27 05:42:32 +00:00
XSetWindowAttributes attributes ;
unsigned long valuemask ;
attributes . override_redirect = True ;
attributes . event_mask = ( EnterWindowMask | LeaveWindowMask |
2001-12-09 04:17:36 +00:00
VisibilityChangeMask ) ;
2001-08-27 05:42:32 +00:00
valuemask = ( CWOverrideRedirect | CWEventMask | CWCursor ) ;
2005-07-28 14:59:42 +00:00
attributes . cursor = XCreateFontCursor ( QX11Info : : display ( ) ,
2001-12-09 04:17:36 +00:00
XC_sb_up_arrow ) ;
2005-07-28 14:59:42 +00:00
electric_top_border = XCreateWindow ( QX11Info : : display ( ) , QX11Info : : appRootWindow ( ) ,
2001-12-09 04:17:36 +00:00
0 , 0 ,
r . width ( ) , 1 ,
0 ,
CopyFromParent , InputOnly ,
CopyFromParent ,
valuemask , & attributes ) ;
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , electric_top_border ) ;
2001-08-27 05:42:32 +00:00
2005-07-28 14:59:42 +00:00
attributes . cursor = XCreateFontCursor ( QX11Info : : display ( ) ,
2001-12-09 04:17:36 +00:00
XC_sb_down_arrow ) ;
2005-07-28 14:59:42 +00:00
electric_bottom_border = XCreateWindow ( QX11Info : : display ( ) , QX11Info : : appRootWindow ( ) ,
2001-12-09 04:17:36 +00:00
0 , r . height ( ) - 1 ,
r . width ( ) , 1 ,
0 ,
CopyFromParent , InputOnly ,
CopyFromParent ,
valuemask , & attributes ) ;
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , electric_bottom_border ) ;
2001-08-27 05:42:32 +00:00
2005-07-28 14:59:42 +00:00
attributes . cursor = XCreateFontCursor ( QX11Info : : display ( ) ,
2001-12-09 04:17:36 +00:00
XC_sb_left_arrow ) ;
2005-07-28 14:59:42 +00:00
electric_left_border = XCreateWindow ( QX11Info : : display ( ) , QX11Info : : appRootWindow ( ) ,
2001-12-09 04:17:36 +00:00
0 , 0 ,
1 , r . height ( ) ,
0 ,
CopyFromParent , InputOnly ,
CopyFromParent ,
valuemask , & attributes ) ;
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , electric_left_border ) ;
2001-08-27 05:42:32 +00:00
2005-07-28 14:59:42 +00:00
attributes . cursor = XCreateFontCursor ( QX11Info : : display ( ) ,
2001-12-09 04:17:36 +00:00
XC_sb_right_arrow ) ;
2005-07-28 14:59:42 +00:00
electric_right_border = XCreateWindow ( QX11Info : : display ( ) , QX11Info : : appRootWindow ( ) ,
2001-12-09 04:17:36 +00:00
r . width ( ) - 1 , 0 ,
1 , r . height ( ) ,
0 ,
CopyFromParent , InputOnly ,
CopyFromParent ,
valuemask , & attributes ) ;
2005-07-28 14:59:42 +00:00
XMapWindow ( QX11Info : : display ( ) , electric_right_border ) ;
2004-11-09 15:38:33 +00:00
// Set XdndAware on the windows, so that DND enter events are received (#86998)
Atom version = 4 ; // XDND version
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , electric_top_border , atoms - > xdnd_aware , XA_ATOM ,
2004-11-09 15:38:33 +00:00
32 , PropModeReplace , ( unsigned char * ) & version , 1 ) ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , electric_bottom_border , atoms - > xdnd_aware , XA_ATOM ,
2004-11-09 15:38:33 +00:00
32 , PropModeReplace , ( unsigned char * ) & version , 1 ) ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , electric_left_border , atoms - > xdnd_aware , XA_ATOM ,
2004-11-09 15:38:33 +00:00
32 , PropModeReplace , ( unsigned char * ) & version , 1 ) ;
2005-07-28 14:59:42 +00:00
XChangeProperty ( QX11Info : : display ( ) , electric_right_border , atoms - > xdnd_aware , XA_ATOM ,
2004-11-09 15:38:33 +00:00
32 , PropModeReplace , ( unsigned char * ) & version , 1 ) ;
2003-09-16 19:28:03 +00:00
}
2001-08-27 05:42:32 +00:00
// Electric Border Window management. Electric borders allow a user
// to change the virtual desktop by moving the mouse pointer to the
// borders. Technically this is done with input only windows. Since
// electric borders can be switched on and off, we have these two
// functions to create and destroy them.
void Workspace : : destroyBorderWindows ( )
2003-09-16 19:28:03 +00:00
{
if ( ! electric_have_borders )
return ;
electric_have_borders = false ;
if ( electric_top_border )
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , electric_top_border ) ;
2003-09-16 19:28:03 +00:00
if ( electric_bottom_border )
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , electric_bottom_border ) ;
2003-09-16 19:28:03 +00:00
if ( electric_left_border )
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , electric_left_border ) ;
2003-09-16 19:28:03 +00:00
if ( electric_right_border )
2005-07-28 14:59:42 +00:00
XDestroyWindow ( QX11Info : : display ( ) , electric_right_border ) ;
2003-09-16 19:28:03 +00:00
electric_top_border = None ;
electric_bottom_border = None ;
electric_left_border = None ;
electric_right_border = None ;
}
2001-08-27 05:42:32 +00:00
2003-10-10 12:48:09 +00:00
void Workspace : : clientMoved ( const QPoint & pos , Time now )
2003-09-16 19:28:03 +00:00
{
if ( options - > electricBorders ( ) = = Options : : ElectricDisabled )
return ;
if ( ( pos . x ( ) ! = electricLeft ) & &
( pos . x ( ) ! = electricRight ) & &
( pos . y ( ) ! = electricTop ) & &
( pos . y ( ) ! = electricBottom ) )
return ;
2003-10-10 12:48:09 +00:00
Time treshold_set = options - > electricBorderDelay ( ) ; // set timeout
2005-01-27 14:37:32 +00:00
Time treshold_reset = 250 ; // reset timeout
2004-11-09 15:39:41 +00:00
int distance_reset = 30 ; // Mouse should not move more than this many pixels
2003-09-16 19:28:03 +00:00
int border = 0 ;
if ( pos . x ( ) = = electricLeft )
border = 1 ;
else if ( pos . x ( ) = = electricRight )
border = 2 ;
else if ( pos . y ( ) = = electricTop )
border = 3 ;
else if ( pos . y ( ) = = electricBottom )
border = 4 ;
if ( ( electric_current_border = = border ) & &
2003-10-10 12:48:09 +00:00
( timestampDiff ( electric_time_last , now ) < treshold_reset ) & &
2003-09-16 19:28:03 +00:00
( ( pos - electric_push_point ) . manhattanLength ( ) < distance_reset ) )
{
electric_time_last = now ;
2003-10-10 12:48:09 +00:00
if ( timestampDiff ( electric_time_first , now ) > treshold_set )
2003-09-16 19:28:03 +00:00
{
electric_current_border = 0 ;
QRect r = QApplication : : desktop ( ) - > geometry ( ) ;
int offset ;
int desk_before = currentDesktop ( ) ;
switch ( border )
{
case 1 :
slotSwitchDesktopLeft ( ) ;
2004-05-17 12:06:45 +00:00
if ( currentDesktop ( ) ! = desk_before )
2003-09-16 19:28:03 +00:00
{
offset = r . width ( ) / 5 ;
QCursor : : setPos ( r . width ( ) - offset , pos . y ( ) ) ;
}
break ;
case 2 :
slotSwitchDesktopRight ( ) ;
2004-05-17 12:06:45 +00:00
if ( currentDesktop ( ) ! = desk_before )
2003-09-16 19:28:03 +00:00
{
offset = r . width ( ) / 5 ;
QCursor : : setPos ( offset , pos . y ( ) ) ;
}
break ;
case 3 :
slotSwitchDesktopUp ( ) ;
2004-05-17 12:06:45 +00:00
if ( currentDesktop ( ) ! = desk_before )
2003-09-16 19:28:03 +00:00
{
offset = r . height ( ) / 5 ;
QCursor : : setPos ( pos . x ( ) , r . height ( ) - offset ) ;
}
break ;
case 4 :
slotSwitchDesktopDown ( ) ;
2004-05-17 12:06:45 +00:00
if ( currentDesktop ( ) ! = desk_before )
2003-09-16 19:28:03 +00:00
{
offset = r . height ( ) / 5 ;
QCursor : : setPos ( pos . x ( ) , offset ) ;
}
break ;
}
return ;
}
}
2004-05-17 12:06:45 +00:00
else
2001-11-03 00:05:33 +00:00
{
2003-09-16 19:28:03 +00:00
electric_current_border = border ;
electric_time_first = now ;
electric_time_last = now ;
electric_push_point = pos ;
2001-08-27 05:42:32 +00:00
}
2003-09-16 19:28:03 +00:00
int mouse_warp = 1 ;
2001-08-27 05:42:32 +00:00
// reset the pointer to find out wether the user is really pushing
2003-09-16 19:28:03 +00:00
switch ( border )
{
case 1 : QCursor : : setPos ( pos . x ( ) + mouse_warp , pos . y ( ) ) ; break ;
case 2 : QCursor : : setPos ( pos . x ( ) - mouse_warp , pos . y ( ) ) ; break ;
case 3 : QCursor : : setPos ( pos . x ( ) , pos . y ( ) + mouse_warp ) ; break ;
case 4 : QCursor : : setPos ( pos . x ( ) , pos . y ( ) - mouse_warp ) ; break ;
}
}
2001-08-27 05:42:32 +00:00
2001-11-03 00:05:33 +00:00
// this function is called when the user entered an electric border
// with the mouse. It may switch to another virtual desktop
2004-11-09 15:38:33 +00:00
bool Workspace : : electricBorder ( XEvent * e )
2003-09-16 19:28:03 +00:00
{
2004-11-09 15:38:33 +00:00
if ( ! electric_have_borders )
return false ;
if ( e - > type = = EnterNotify )
{
if ( e - > xcrossing . window = = electric_top_border | |
e - > xcrossing . window = = electric_left_border | |
e - > xcrossing . window = = electric_bottom_border | |
e - > xcrossing . window = = electric_right_border )
// the user entered an electric border
{
clientMoved ( QPoint ( e - > xcrossing . x_root , e - > xcrossing . y_root ) , e - > xcrossing . time ) ;
return true ;
}
}
if ( e - > type = = ClientMessage )
{
if ( e - > xclient . message_type = = atoms - > xdnd_position
& & ( e - > xclient . window = = electric_top_border
| | e - > xclient . window = = electric_bottom_border
| | e - > xclient . window = = electric_left_border
| | e - > xclient . window = = electric_right_border ) )
{
updateXTime ( ) ;
2005-07-28 14:59:42 +00:00
clientMoved ( QPoint ( e - > xclient . data . l [ 2 ] > > 16 , e - > xclient . data . l [ 2 ] & 0xffff ) , QX11Info : : appTime ( ) ) ;
2004-11-09 15:38:33 +00:00
return true ;
}
}
return false ;
2003-09-16 19:28:03 +00:00
}
2001-11-03 00:05:33 +00:00
2001-08-27 05:42:32 +00:00
// electric borders (input only windows) have to be always on the
// top. For that reason kwm calls this function always after some
// windows have been raised.
2003-09-16 19:28:03 +00:00
void Workspace : : raiseElectricBorders ( )
{
if ( electric_have_borders )
{
2005-07-28 14:59:42 +00:00
XRaiseWindow ( QX11Info : : display ( ) , electric_top_border ) ;
XRaiseWindow ( QX11Info : : display ( ) , electric_left_border ) ;
XRaiseWindow ( QX11Info : : display ( ) , electric_bottom_border ) ;
XRaiseWindow ( QX11Info : : display ( ) , electric_right_border ) ;
2003-09-16 19:28:03 +00:00
}
}
2003-11-10 18:08:04 +00:00
void Workspace : : addTopMenu ( Client * c )
{
assert ( c - > isTopMenu ( ) ) ;
assert ( ! topmenus . contains ( c ) ) ;
topmenus . append ( c ) ;
2003-11-13 14:34:05 +00:00
if ( managingTopMenus ( ) )
2003-11-10 18:08:04 +00:00
{
2003-11-13 14:34:05 +00:00
int minsize = c - > minSize ( ) . height ( ) ;
if ( minsize > topMenuHeight ( ) )
2003-11-12 10:03:42 +00:00
{
2003-11-13 14:34:05 +00:00
topmenu_height = minsize ;
updateTopMenuGeometry ( ) ;
2003-11-12 10:03:42 +00:00
}
2003-11-13 14:34:05 +00:00
updateTopMenuGeometry ( c ) ;
2004-03-08 15:31:09 +00:00
updateCurrentTopMenu ( ) ;
2003-11-10 18:08:04 +00:00
}
// kdDebug() << "NEW TOPMENU:" << c << endl;
}
void Workspace : : removeTopMenu ( Client * c )
{
// if( c->isTopMenu())
// kdDebug() << "REMOVE TOPMENU:" << c << endl;
assert ( c - > isTopMenu ( ) ) ;
assert ( topmenus . contains ( c ) ) ;
topmenus . remove ( c ) ;
2004-03-08 15:31:09 +00:00
updateCurrentTopMenu ( ) ;
2003-11-10 18:08:04 +00:00
// TODO reduce topMenuHeight() if possible?
}
2003-09-16 19:28:03 +00:00
void Workspace : : lostTopMenuSelection ( )
{
// kdDebug() << "lost TopMenu selection" << endl;
2004-03-08 15:31:09 +00:00
// make sure this signal is always set when not owning the selection
disconnect ( topmenu_watcher , SIGNAL ( lostOwner ( ) ) , this , SLOT ( lostTopMenuOwner ( ) ) ) ;
connect ( topmenu_watcher , SIGNAL ( lostOwner ( ) ) , this , SLOT ( lostTopMenuOwner ( ) ) ) ;
2003-11-12 09:47:13 +00:00
if ( ! managing_topmenus )
return ;
2003-09-16 19:28:03 +00:00
connect ( topmenu_watcher , SIGNAL ( lostOwner ( ) ) , this , SLOT ( lostTopMenuOwner ( ) ) ) ;
disconnect ( topmenu_selection , SIGNAL ( lostOwnership ( ) ) , this , SLOT ( lostTopMenuSelection ( ) ) ) ;
managing_topmenus = false ;
2003-11-12 09:47:13 +00:00
delete topmenu_space ;
2003-11-12 10:03:42 +00:00
topmenu_space = NULL ;
2003-11-12 09:47:13 +00:00
updateClientArea ( ) ;
2003-09-16 19:28:03 +00:00
for ( ClientList : : ConstIterator it = topmenus . begin ( ) ;
it ! = topmenus . end ( ) ;
+ + it )
( * it ) - > checkWorkspacePosition ( ) ;
}
void Workspace : : lostTopMenuOwner ( )
{
2003-11-13 14:34:05 +00:00
if ( ! options - > topMenuEnabled ( ) )
return ;
2003-09-16 19:28:03 +00:00
// kdDebug() << "TopMenu selection lost owner" << endl;
if ( ! topmenu_selection - > claim ( false ) )
{
// kdDebug() << "Failed to claim TopMenu selection" << endl;
return ;
}
// kdDebug() << "claimed TopMenu selection" << endl;
2003-11-12 09:47:13 +00:00
setupTopMenuHandling ( ) ;
}
void Workspace : : setupTopMenuHandling ( )
{
if ( managing_topmenus )
return ;
2003-09-16 19:28:03 +00:00
connect ( topmenu_selection , SIGNAL ( lostOwnership ( ) ) , this , SLOT ( lostTopMenuSelection ( ) ) ) ;
disconnect ( topmenu_watcher , SIGNAL ( lostOwner ( ) ) , this , SLOT ( lostTopMenuOwner ( ) ) ) ;
managing_topmenus = true ;
2003-11-12 09:47:13 +00:00
topmenu_space = new QWidget ;
2004-07-19 15:00:37 +00:00
Window stack [ 2 ] ;
stack [ 0 ] = supportWindow - > winId ( ) ;
stack [ 1 ] = topmenu_space - > winId ( ) ;
2005-07-28 14:59:42 +00:00
XRestackWindows ( QX11Info : : display ( ) , stack , 2 ) ;
2003-11-13 14:34:05 +00:00
updateTopMenuGeometry ( ) ;
2003-11-12 09:47:13 +00:00
topmenu_space - > show ( ) ;
updateClientArea ( ) ;
2004-03-08 15:31:09 +00:00
updateCurrentTopMenu ( ) ;
2003-09-16 19:28:03 +00:00
}
int Workspace : : topMenuHeight ( ) const
{
if ( topmenu_height = = 0 )
{ // simply create a dummy menubar and use its preffered height as the menu height
KMenuBar tmpmenu ;
tmpmenu . insertItem ( " dummy " ) ;
topmenu_height = tmpmenu . sizeHint ( ) . height ( ) ;
}
return topmenu_height ;
}
KDecoration * Workspace : : createDecoration ( KDecorationBridge * bridge )
{
return mgr - > createDecoration ( bridge ) ;
}
QString Workspace : : desktopName ( int desk ) const
{
return QString : : fromUtf8 ( rootInfo - > desktopName ( desk ) ) ;
}
2004-05-26 09:24:14 +00:00
bool Workspace : : checkStartupNotification ( Window w , KStartupInfoId & id , KStartupInfoData & data )
2003-09-16 19:28:03 +00:00
{
2004-05-26 09:24:14 +00:00
return startup - > checkStartup ( w , id , data ) = = KStartupInfo : : Match ;
2003-09-16 19:28:03 +00:00
}
2001-08-27 05:42:32 +00:00
2003-09-16 19:28:03 +00:00
/*!
Puts the focus on a dummy window
Just using XSetInputFocus ( ) with None would block keyboard input
*/
void Workspace : : focusToNull ( )
{
2005-07-28 14:59:42 +00:00
XSetInputFocus ( QX11Info : : display ( ) , null_focus_window , RevertToPointerRoot , QX11Info : : appTime ( ) ) ;
2003-09-16 19:28:03 +00:00
}
2001-08-27 05:42:32 +00:00
2003-10-13 16:22:39 +00:00
void Workspace : : helperDialog ( const QString & message , const Client * c )
{
QStringList args ;
QString type ;
2003-10-23 13:38:42 +00:00
if ( message = = " noborderaltf3 " )
2003-10-13 16:22:39 +00:00
{
2004-02-23 14:25:55 +00:00
QString shortcut = QString ( " %1 (%2) " ) . arg ( keys - > label ( " Window Operations Menu " ) )
. arg ( keys - > shortcut ( " Window Operations Menu " ) . seq ( 0 ) . toString ( ) ) ;
2004-02-23 13:45:36 +00:00
args < < " --msgbox " < <
i18n ( " You have selected to show a window without its border. \n "
2004-05-19 14:32:18 +00:00
" Without the border, you will not be able to enable the border "
" again using the mouse: use the window operations menu instead, "
2003-10-23 13:38:42 +00:00
" activated using the %1 keyboard shortcut. " )
2004-02-23 14:25:55 +00:00
. arg ( shortcut ) ;
2003-10-23 13:38:42 +00:00
type = " altf3warning " ;
}
else if ( message = = " fullscreenaltf3 " )
{
2004-02-23 14:25:55 +00:00
QString shortcut = QString ( " %1 (%2) " ) . arg ( keys - > label ( " Window Operations Menu " ) )
. arg ( keys - > shortcut ( " Window Operations Menu " ) . seq ( 0 ) . toString ( ) ) ;
2004-02-23 13:45:36 +00:00
args < < " --msgbox " < <
i18n ( " You have selected to show a window in fullscreen mode. \n "
2004-05-19 14:32:18 +00:00
" If the application itself does not have an option to turn the fullscreen "
" mode off you will not be able to disable it "
" again using the mouse: use the window operations menu instead, "
2003-10-23 13:38:42 +00:00
" activated using the %1 keyboard shortcut. " )
2004-02-23 14:25:55 +00:00
. arg ( shortcut ) ;
2003-10-13 16:22:39 +00:00
type = " altf3warning " ;
}
else
2003-10-23 13:38:42 +00:00
assert ( false ) ;
2003-10-13 16:22:39 +00:00
KProcess proc ;
2003-10-23 13:38:42 +00:00
proc < < " kdialog " < < args ;
2003-10-13 16:22:39 +00:00
if ( ! type . isEmpty ( ) )
{
2003-10-23 13:38:42 +00:00
KConfig cfg ( " kwin_dialogsrc " ) ;
2003-10-13 16:22:39 +00:00
cfg . setGroup ( " Notification Messages " ) ; // this depends on KMessageBox
if ( ! cfg . readBoolEntry ( type , true ) ) // has don't show again checked
2003-10-23 13:38:42 +00:00
return ; // save launching kdialog
proc < < " --dontagain " < < " kwin_dialogsrc: " + type ;
2003-10-13 16:22:39 +00:00
}
if ( c ! = NULL )
2003-10-23 13:38:42 +00:00
proc < < " --embed " < < QString : : number ( c - > window ( ) ) ;
2003-10-13 16:22:39 +00:00
proc . start ( KProcess : : DontCare ) ;
}
2001-08-27 05:42:32 +00:00
2005-01-15 17:07:48 +00:00
// kompmgr stuff
void Workspace : : startKompmgr ( )
{
if ( ! kompmgr | | kompmgr - > isRunning ( ) )
return ;
if ( ! kompmgr - > start ( KProcess : : OwnGroup , KProcess : : Stderr ) )
{
options - > useTranslucency = FALSE ;
2005-01-17 17:32:27 +00:00
KProcess proc ;
proc < < " kdialog " < < " --error "
< < i18n ( " The Composite Manager could not be started. \\ nMake sure you have \" kompmgr \" in a $PATH directory. " )
2005-01-20 21:09:28 +00:00
< < " --title " < < " Composite Manager Failure " ;
2005-01-17 17:32:27 +00:00
proc . start ( KProcess : : DontCare ) ;
2005-01-15 17:07:48 +00:00
}
else
{
connect ( kompmgr , SIGNAL ( processExited ( KProcess * ) ) , SLOT ( restartKompmgr ( ) ) ) ;
options - > useTranslucency = TRUE ;
allowKompmgrRestart = FALSE ;
QTimer : : singleShot ( 60000 , this , SLOT ( unblockKompmgrRestart ( ) ) ) ;
2005-01-21 04:58:54 +00:00
QByteArray ba ;
2005-11-10 11:50:13 +00:00
QDataStream arg ( & ba , QIODevice : : WriteOnly ) ;
2005-01-21 04:58:54 +00:00
arg < < " " ;
kapp - > dcopClient ( ) - > emitDCOPSignal ( " default " , " kompmgrStarted() " , ba ) ;
2005-01-15 17:07:48 +00:00
}
if ( popup ) { delete popup ; popup = 0L ; } // to add/remove opacity slider
}
void Workspace : : stopKompmgr ( )
{
2005-01-17 23:16:28 +00:00
if ( ! kompmgr | | ! kompmgr - > isRunning ( ) )
2005-01-17 16:42:34 +00:00
return ;
2005-01-15 17:07:48 +00:00
kompmgr - > disconnect ( this , SLOT ( restartKompmgr ( ) ) ) ;
options - > useTranslucency = FALSE ;
if ( popup ) { delete popup ; popup = 0L ; } // to add/remove opacity slider
kompmgr - > kill ( ) ;
2005-01-21 04:58:54 +00:00
QByteArray ba ;
2005-11-10 11:50:13 +00:00
QDataStream arg ( & ba , QIODevice : : WriteOnly ) ;
2005-01-21 04:58:54 +00:00
arg < < " " ;
kapp - > dcopClient ( ) - > emitDCOPSignal ( " default " , " kompmgrStopped() " , ba ) ;
}
bool Workspace : : kompmgrIsRunning ( )
{
2005-04-07 10:20:44 +00:00
return kompmgr & & kompmgr - > isRunning ( ) ;
2005-01-15 17:07:48 +00:00
}
void Workspace : : unblockKompmgrRestart ( )
{
allowKompmgrRestart = TRUE ;
}
void Workspace : : restartKompmgr ( )
// this is for inernal purpose (crashhandling) only, usually you want to use workspace->stopKompmgr(); QTimer::singleShot(200, workspace, SLOT(startKompmgr()));
{
if ( ! allowKompmgrRestart ) // uh-ohh
{
options - > useTranslucency = FALSE ;
2005-01-17 17:32:27 +00:00
KProcess proc ;
proc < < " kdialog " < < " --error "
< < i18n ( " The Composite Manager crashed twice within a minute and is therefore disabled for this session. " )
< < " --title " < < i18n ( " Composite Manager Failure " ) ;
proc . start ( KProcess : : DontCare ) ;
2005-01-15 17:07:48 +00:00
return ;
}
if ( ! kompmgr )
return ;
// this should be useless, i keep it for maybe future need
// if (!kcompmgr)
// {
// kompmgr = new KProcess;
// kompmgr->clearArguments();
// *kompmgr << "kompmgr";
// }
// -------------------
if ( ! kompmgr - > start ( KProcess : : NotifyOnExit , KProcess : : Stderr ) )
{
options - > useTranslucency = FALSE ;
2005-01-17 17:32:27 +00:00
KProcess proc ;
proc < < " kdialog " < < " --error "
< < i18n ( " The Composite Manager could not be started. \\ nMake sure you have \" kompmgr \" in a $PATH directory. " )
2005-01-20 21:09:28 +00:00
< < " --title " < < i18n ( " Composite Manager Failure " ) ;
2005-01-17 17:32:27 +00:00
proc . start ( KProcess : : DontCare ) ;
2005-01-15 17:07:48 +00:00
}
else
{
allowKompmgrRestart = FALSE ;
QTimer : : singleShot ( 60000 , this , SLOT ( unblockKompmgrRestart ( ) ) ) ;
}
}
2005-01-17 17:32:27 +00:00
void Workspace : : handleKompmgrOutput ( KProcess * , char * buffer , int buflen )
2005-01-15 17:07:48 +00:00
{
2005-01-17 17:32:27 +00:00
QString message ;
QString output = QString : : fromLocal8Bit ( buffer , buflen ) ;
if ( output . contains ( " Started " , false ) )
; // don't do anything, just pass to the connection release
else if ( output . contains ( " Can't open display " , false ) )
message = i18n ( " <qt><b>kompmgr failed to open the display</b><br>There is probably an invalid display entry in your ~/.xcompmgrrc.</qt> " ) ;
else if ( output . contains ( " No render extension " , false ) )
message = i18n ( " <qt><b>kompmgr cannot find the Xrender extension</b><br>You are using either an outdated or a crippled version of XOrg.<br>Get XOrg ≥ 6.8 from www.freedesktop.org.<br></qt> " ) ;
else if ( output . contains ( " No composite extension " , false ) )
message = i18n ( " <qt><b>Composite extension not found</b><br>You <i>must</i> use XOrg ≥ 6.8 for translucency and shadows to work.<br>Additionally, you need to add a new section to your X config file:<br> "
2005-01-15 17:07:48 +00:00
" <i>Section \" Extensions \" <br> "
" Option \" Composite \" \" Enable \" <br> "
2005-01-17 17:32:27 +00:00
" EndSection</i></qt> " ) ;
else if ( output . contains ( " No damage extension " , false ) )
message = i18n ( " <qt><b>Damage extension not found</b><br>You <i>must</i> use XOrg ≥ 6.8 for translucency and shadows to work.</qt> " ) ;
else if ( output . contains ( " No XFixes extension " , false ) )
message = i18n ( " <qt><b>XFixes extension not found</b><br>You <i>must</i> use XOrg ≥ 6.8 for translucency and shadows to work.</qt> " ) ;
2005-01-15 17:07:48 +00:00
else return ; //skip others
// kompmgr startup failed or succeeded, release connection
kompmgr - > closeStderr ( ) ;
disconnect ( kompmgr , SIGNAL ( receivedStderr ( KProcess * , char * , int ) ) , this , SLOT ( handleKompmgrOutput ( KProcess * , char * , int ) ) ) ;
2005-01-17 17:32:27 +00:00
if ( ! message . isEmpty ( ) )
{
KProcess proc ;
proc < < " kdialog " < < " --error "
< < message
2005-01-20 21:09:28 +00:00
< < " --title " < < i18n ( " Composite Manager Failure " ) ;
2005-01-17 17:32:27 +00:00
proc . start ( KProcess : : DontCare ) ;
}
2005-01-15 17:07:48 +00:00
}
void Workspace : : setOpacity ( unsigned long winId , unsigned int opacityPercent )
{
if ( opacityPercent > 100 ) opacityPercent = 100 ;
for ( ClientList : : ConstIterator it = stackingOrder ( ) . begin ( ) ; it ! = stackingOrder ( ) . end ( ) ; it + + )
if ( winId = = ( * it ) - > window ( ) )
{
( * it ) - > setOpacity ( opacityPercent < 100 , ( unsigned int ) ( ( opacityPercent / 100.0 ) * 0xFFFFFFFF ) ) ;
return ;
}
}
void Workspace : : setShadowSize ( unsigned long winId , unsigned int shadowSizePercent )
{
//this is open to the user by dcop - to avoid stupid trials, we limit the max shadow size to 400%
if ( shadowSizePercent > 400 ) shadowSizePercent = 400 ;
for ( ClientList : : ConstIterator it = stackingOrder ( ) . begin ( ) ; it ! = stackingOrder ( ) . end ( ) ; it + + )
if ( winId = = ( * it ) - > window ( ) )
{
( * it ) - > setShadowSize ( shadowSizePercent ) ;
return ;
}
}
void Workspace : : setUnshadowed ( unsigned long winId )
{
for ( ClientList : : ConstIterator it = stackingOrder ( ) . begin ( ) ; it ! = stackingOrder ( ) . end ( ) ; it + + )
if ( winId = = ( * it ) - > window ( ) )
{
( * it ) - > setShadowSize ( 0 ) ;
return ;
}
}
2005-05-13 08:57:21 +00:00
void Workspace : : setShowingDesktop ( bool showing )
{
rootInfo - > setShowingDesktop ( showing ) ;
showing_desktop = showing ;
+ + block_showing_desktop ;
if ( showing_desktop )
{
showing_desktop_clients . clear ( ) ;
+ + block_focus ;
ClientList cls = stackingOrder ( ) ;
// find them first, then minimize, otherwise transients may get minimized with the window
// they're transient for
for ( ClientList : : ConstIterator it = cls . begin ( ) ;
it ! = cls . end ( ) ;
+ + it )
{
if ( ( * it ) - > isOnCurrentDesktop ( ) & & ( * it ) - > isShown ( true ) & & ! ( * it ) - > isSpecialWindow ( ) )
showing_desktop_clients . prepend ( * it ) ; // topmost first to reduce flicker
}
for ( ClientList : : ConstIterator it = showing_desktop_clients . begin ( ) ;
it ! = showing_desktop_clients . end ( ) ;
+ + it )
( * it ) - > minimize ( ) ;
- - block_focus ;
if ( Client * desk = findDesktop ( true , currentDesktop ( ) ) )
requestFocus ( desk ) ;
}
else
{
for ( ClientList : : ConstIterator it = showing_desktop_clients . begin ( ) ;
it ! = showing_desktop_clients . end ( ) ;
+ + it )
( * it ) - > unminimize ( ) ;
if ( showing_desktop_clients . count ( ) > 0 )
requestFocus ( showing_desktop_clients . first ( ) ) ;
showing_desktop_clients . clear ( ) ;
}
- - block_showing_desktop ;
}
// Following Kicker's behavior:
// Changing a virtual desktop resets the state and shows the windows again.
// Unminimizing a window resets the state but keeps the windows hidden (except
// the one that was unminimized).
// A new window resets the state and shows the windows again, with the new window
// being active.
void Workspace : : resetShowingDesktop ( bool keep_hidden )
{
if ( block_showing_desktop > 0 )
return ;
rootInfo - > setShowingDesktop ( false ) ;
showing_desktop = false ;
+ + block_showing_desktop ;
if ( ! keep_hidden )
{
for ( ClientList : : ConstIterator it = showing_desktop_clients . begin ( ) ;
it ! = showing_desktop_clients . end ( ) ;
+ + it )
( * it ) - > unminimize ( ) ;
}
showing_desktop_clients . clear ( ) ;
- - block_showing_desktop ;
}
2005-08-02 13:25:20 +00:00
// Activating/deactivating this feature works like this:
// When nothing is active, and the shortcut is pressed, global shortcuts are disabled
// (using global_shortcuts_disabled)
// When a window that has disabling forced is activated, global shortcuts are disabled.
// (using global_shortcuts_disabled_for_client)
// When a shortcut is pressed and global shortcuts are disabled (either by a shortcut
// or for a client), they are enabled again.
void Workspace : : slotDisableGlobalShortcuts ( )
{
if ( global_shortcuts_disabled | | global_shortcuts_disabled_for_client )
disableGlobalShortcuts ( false ) ;
else
disableGlobalShortcuts ( true ) ;
}
static bool pending_dfc = false ;
void Workspace : : disableGlobalShortcutsForClient ( bool disable )
{
if ( global_shortcuts_disabled_for_client = = disable )
return ;
if ( ! global_shortcuts_disabled )
{
if ( disable )
pending_dfc = true ;
KIPC : : sendMessageAll ( KIPC : : BlockShortcuts , disable ) ;
// kwin will get the kipc message too
}
}
void Workspace : : disableGlobalShortcuts ( bool disable )
{
KIPC : : sendMessageAll ( KIPC : : BlockShortcuts , disable ) ;
// kwin will get the kipc message too
}
void Workspace : : kipcMessage ( int id , int data )
{
if ( id ! = KIPC : : BlockShortcuts )
return ;
if ( pending_dfc & & data )
{
global_shortcuts_disabled_for_client = true ;
pending_dfc = false ;
}
else
{
global_shortcuts_disabled = data ;
global_shortcuts_disabled_for_client = false ;
}
// update also Alt+LMB actions etc.
for ( ClientList : : ConstIterator it = clients . begin ( ) ;
it ! = clients . end ( ) ;
+ + it )
( * it ) - > updateMouseGrab ( ) ;
}
2003-09-16 19:28:03 +00:00
} // namespace
2001-08-27 05:42:32 +00:00
2000-06-09 00:20:21 +00:00
# include "workspace.moc"