2007-11-27 19:40:25 +00:00
/********************************************************************
2007-04-29 17:35:43 +00:00
KWin - the KDE window manager
This file is part of the KDE project .
Copyright ( C ) 1999 , 2000 Matthias Ettrich < ettrich @ kde . org >
Copyright ( C ) 2003 Lubos Lunak < l . lunak @ kde . org >
2007-11-27 19:40:25 +00:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-04-29 17:35:43 +00:00
//#define QT_CLEAN_NAMESPACE
# include "workspace.h"
# include <kapplication.h>
# include <kstartupinfo.h>
# include <fixx11h.h>
# include <kconfig.h>
# include <kglobal.h>
# include <klocale.h>
2012-03-27 17:14:53 +00:00
# include <QtGui/QDesktopWidget>
2007-04-29 17:35:43 +00:00
# include <QRegExp>
# include <QPainter>
# include <QBitmap>
# include <QClipboard>
# include <kmenubar.h>
2007-06-17 17:09:40 +00:00
# include <kprocess.h>
2007-04-29 17:35:43 +00:00
# include <kglobalaccel.h>
# include <QToolButton>
# include <kactioncollection.h>
# include <kaction.h>
# include <kconfiggroup.h>
2009-02-12 10:01:40 +00:00
# include <kcmdlineargs.h>
2007-04-29 17:35:43 +00:00
# include <QtDBus/QtDBus>
# include "client.h"
2011-06-30 11:02:30 +00:00
# ifdef KWIN_BUILD_TABBOX
2007-04-29 17:35:43 +00:00
# include "tabbox.h"
2011-06-30 11:02:30 +00:00
# endif
2007-04-29 17:35:43 +00:00
# include "atoms.h"
# include "placement.h"
# include "notifications.h"
2011-04-28 09:16:27 +00:00
# include "outline.h"
2007-04-29 17:35:43 +00:00
# include "group.h"
# include "rules.h"
# include "kwinadaptor.h"
# include "unmanaged.h"
# include "deleted.h"
# include "effects.h"
2011-07-06 09:58:23 +00:00
# include "overlaywindow.h"
2012-03-04 14:13:22 +00:00
# include <kwinglplatform.h>
# include <kwinglutils.h>
2012-04-12 13:19:38 +00:00
# ifdef KWIN_BUILD_SCRIPTING
# include "scripting/scripting.h"
# endif
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-28 11:36:25 +00:00
# include "tiling/tile.h"
# include "tiling/tilinglayout.h"
2011-07-13 16:48:56 +00:00
# include "tiling/tiling.h"
2011-07-20 11:25:00 +00:00
# endif
2010-09-21 14:31:40 +00:00
2007-04-29 17:35:43 +00:00
# include <X11/extensions/shape.h>
# include <X11/keysym.h>
# include <X11/keysymdef.h>
# include <X11/cursorfont.h>
# include <QX11Info>
# include <stdio.h>
# include <kauthorized.h>
# include <ktoolinvocation.h>
# include <kglobalsettings.h>
2010-09-21 14:31:40 +00:00
# include <kwindowsystem.h>
# include <kwindowinfo.h>
2007-04-29 17:35:43 +00:00
namespace KWin
{
extern int screen_number ;
2011-01-13 19:05:28 +00:00
static const int KWIN_MAX_NUMBER_DESKTOPS = 20 ;
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
Workspace * Workspace : : _self = 0 ;
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
//-----------------------------------------------------------------------------
2007-04-29 17:35:43 +00:00
// Rikkus: This class is too complex. It needs splitting further.
// It's a nightmare to understand, especially with so few comments :(
2008-12-18 13:50:57 +00:00
//
2007-04-29 17:35:43 +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.
2008-12-18 13:50:57 +00:00
//-----------------------------------------------------------------------------
2011-01-30 14:34:42 +00:00
Workspace : : Workspace ( bool restore )
: QObject ( 0 )
2009-02-14 15:40:52 +00:00
// Desktop layout
2011-01-30 14:34:42 +00:00
, desktopCount_ ( 0 ) // This is an invalid state
, desktopGridSize_ ( 1 , 2 ) // Default to two rows
, desktopGrid_ ( new int [ 2 ] )
, currentDesktop_ ( 0 )
2012-05-03 20:54:16 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
2012-05-03 17:48:20 +00:00
, m_screenEdgeOrientation ( 0 )
2012-05-03 20:54:16 +00:00
# endif
2009-02-14 15:40:52 +00:00
// Unsorted
2012-03-29 20:11:28 +00:00
, m_nextFrameDelay ( 0 )
2011-01-30 14:34:42 +00:00
, active_popup ( NULL )
, active_popup_client ( NULL )
, temporaryRulesMessages ( " _KDE_NET_WM_TEMPORARY_RULES " , NULL , false )
, rules_updates_disabled ( false )
, active_client ( 0 )
, last_active_client ( 0 )
, most_recently_raised ( 0 )
, movingClient ( 0 )
, pending_take_activity ( NULL )
, active_screen ( 0 )
, delayfocus_client ( 0 )
, force_restacking ( false )
, x_stacking_dirty ( true )
, showing_desktop ( false )
, block_showing_desktop ( 0 )
, was_user_interaction ( false )
, session_saving ( false )
, block_focus ( 0 )
2011-06-30 11:02:30 +00:00
# ifdef KWIN_BUILD_TABBOX
2011-01-30 14:34:42 +00:00
, tab_box ( 0 )
2011-07-11 13:39:39 +00:00
# endif
2011-01-30 14:34:42 +00:00
, popup ( 0 )
, advanced_popup ( 0 )
, desk_popup ( 0 )
, activity_popup ( 0 )
, add_tabs_popup ( 0 )
, switch_to_tab_popup ( 0 )
, keys ( 0 )
, client_keys ( NULL )
2011-07-08 19:50:01 +00:00
, disable_shortcuts_keys ( NULL )
2011-01-30 14:34:42 +00:00
, client_keys_dialog ( NULL )
, client_keys_client ( NULL )
, global_shortcuts_disabled ( false )
, global_shortcuts_disabled_for_client ( false )
, workspaceInit ( true )
, startup ( 0 )
, set_active_client_recursion ( 0 )
, block_stacking_updates ( 0 )
, forced_global_mouse_grab ( false )
, cm_selection ( NULL )
, compositingSuspended ( false )
2011-03-20 14:42:05 +00:00
, compositingBlocked ( false )
2011-01-30 14:34:42 +00:00
, xrrRefreshRate ( 0 )
, transSlider ( NULL )
, transButton ( NULL )
, forceUnredirectCheck ( true )
2011-05-15 11:22:28 +00:00
, m_finishingCompositing ( false )
2012-04-12 13:19:38 +00:00
, m_scripting ( NULL )
2011-01-30 14:34:42 +00:00
{
2012-04-12 17:42:49 +00:00
// If KWin was already running it saved its configuration after loosing the selection -> Reread
QFuture < void > reparseConfigFuture = QtConcurrent : : run ( options , & Options : : reparseConfiguration ) ;
2011-01-30 14:34:42 +00:00
( void ) new KWinAdaptor ( this ) ;
2008-12-18 13:50:57 +00:00
2007-04-30 09:57:03 +00:00
QDBusConnection dbus = QDBusConnection : : sessionBus ( ) ;
2011-01-30 14:34:42 +00:00
dbus . registerObject ( " /KWin " , this ) ;
dbus . connect ( QString ( ) , " /KWin " , " org.kde.KWin " , " reloadConfig " ,
this , SLOT ( slotReloadConfig ( ) ) ) ;
dbus . connect ( QString ( ) , " /KWin " , " org.kde.KWin " , " reinitCompositing " ,
this , SLOT ( slotReinitCompositing ( ) ) ) ;
2008-12-18 13:50:57 +00:00
2009-02-14 15:40:52 +00:00
// Initialize desktop grid array
desktopGrid_ [ 0 ] = 0 ;
desktopGrid_ [ 1 ] = 0 ;
2007-04-29 17:35:43 +00:00
_self = this ;
2012-04-13 06:39:04 +00:00
// first initialize the extensions
Extensions : : init ( ) ;
2012-04-12 17:42:49 +00:00
// PluginMgr needs access to the config file, so we need to wait for it for finishing
reparseConfigFuture . waitForFinished ( ) ;
options - > loadConfig ( ) ;
options - > loadCompositingConfig ( false ) ;
2007-04-29 17:35:43 +00:00
mgr = new PluginMgr ;
2007-07-19 16:24:51 +00:00
QX11Info info ;
2011-01-30 14:34:42 +00:00
default_colormap = DefaultColormap ( display ( ) , info . screen ( ) ) ;
2007-04-29 17:35:43 +00:00
installed_colormap = default_colormap ;
2011-08-17 21:51:55 +00:00
connect ( & temporaryRulesMessages , SIGNAL ( gotMessage ( QString ) ) ,
this , SLOT ( gotTemporaryRulesMessage ( QString ) ) ) ;
2011-01-30 14:34:42 +00:00
connect ( & rulesUpdatedTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( writeWindowRules ( ) ) ) ;
connect ( & unredirectTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( delayedCheckUnredirect ( ) ) ) ;
connect ( & compositeResetTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( resetCompositing ( ) ) ) ;
unredirectTimer . setSingleShot ( true ) ;
compositeResetTimer . setSingleShot ( true ) ;
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
updateXTime ( ) ; // Needed for proper initialization of user_time in Client ctor
2007-04-29 17:35:43 +00:00
delayFocusTimer = 0 ;
2011-07-29 08:57:02 +00:00
# ifdef KWIN_BUILD_TILING
m_tiling = new Tiling ( this ) ;
# endif
2011-01-30 14:34:42 +00:00
if ( restore )
2008-12-18 13:50:57 +00:00
loadSessionInfo ( ) ;
2007-04-29 17:35:43 +00:00
loadWindowRules ( ) ;
2008-12-18 13:50:57 +00:00
// Call this before XSelectInput() on the root window
2007-04-29 17:35:43 +00:00
startup = new KStartupInfo (
2011-01-30 14:34:42 +00:00
KStartupInfo : : DisableKWinModule | KStartupInfo : : AnnounceSilenceChanges , this ) ;
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
// Select windowmanager privileges
2011-01-30 14:34:42 +00:00
XSelectInput ( display ( ) , rootWindow ( ) ,
KeyPressMask |
PropertyChangeMask |
ColormapChangeMask |
SubstructureRedirectMask |
SubstructureNotifyMask |
FocusChangeMask | // For NotifyDetailNone
ExposureMask
) ;
2007-04-29 17:35:43 +00:00
2012-02-20 09:25:13 +00:00
compositingSuspended = ! options - > isUseCompositing ( ) ;
2011-06-30 11:02:30 +00:00
# ifdef KWIN_BUILD_TABBOX
2011-03-06 11:15:16 +00:00
// need to create the tabbox before compositing scene is setup
2011-06-30 11:02:30 +00:00
tab_box = new TabBox : : TabBox ( this ) ;
# endif
2011-10-29 14:55:56 +00:00
2007-04-29 17:35:43 +00:00
setupCompositing ( ) ;
2008-12-18 13:50:57 +00:00
// Compatibility
2007-04-29 17:35:43 +00:00
long data = 1 ;
XChangeProperty (
2008-12-18 13:50:57 +00:00
display ( ) ,
rootWindow ( ) ,
atoms - > kwin_running ,
atoms - > kwin_running ,
32 ,
PropModeAppend ,
2011-01-30 14:34:42 +00:00
( unsigned char * ) ( & data ) ,
2008-12-18 13:50:57 +00:00
1
2011-01-30 14:34:42 +00:00
) ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
client_keys = new KActionCollection ( this ) ;
2011-07-13 16:48:56 +00:00
2011-04-28 09:16:27 +00:00
m_outline = new Outline ( ) ;
2011-07-13 16:48:56 +00:00
initShortcuts ( ) ;
2007-04-29 17:35:43 +00:00
init ( ) ;
2012-03-27 17:14:53 +00:00
connect ( QApplication : : desktop ( ) , SIGNAL ( screenCountChanged ( int ) ) , & screenChangedTimer , SLOT ( start ( ) ) ) ;
connect ( QApplication : : desktop ( ) , SIGNAL ( resized ( int ) ) , & screenChangedTimer , SLOT ( start ( ) ) ) ;
2010-05-11 20:30:20 +00:00
2012-02-26 10:38:16 +00:00
# ifdef KWIN_BUILD_ACTIVITIES
2011-01-30 14:34:42 +00:00
connect ( & activityController_ , SIGNAL ( currentActivityChanged ( QString ) ) , SLOT ( updateCurrentActivity ( QString ) ) ) ;
2012-06-21 18:37:23 +00:00
connect ( & activityController_ , SIGNAL ( activityRemoved ( QString ) ) , SLOT ( slotActivityRemoved ( QString ) ) ) ;
connect ( & activityController_ , SIGNAL ( activityRemoved ( QString ) ) , SIGNAL ( activityRemoved ( QString ) ) ) ;
connect ( & activityController_ , SIGNAL ( activityAdded ( QString ) ) , SLOT ( slotActivityAdded ( QString ) ) ) ;
connect ( & activityController_ , SIGNAL ( activityAdded ( QString ) ) , SIGNAL ( activityAdded ( QString ) ) ) ;
connect ( & activityController_ , SIGNAL ( currentActivityChanged ( QString ) ) , SIGNAL ( currentActivityChanged ( QString ) ) ) ;
2012-02-26 10:38:16 +00:00
# endif
2011-07-24 20:56:55 +00:00
connect ( & screenChangedTimer , SIGNAL ( timeout ( ) ) , SLOT ( screenChangeTimeout ( ) ) ) ;
screenChangedTimer . setSingleShot ( true ) ;
screenChangedTimer . setInterval ( 100 ) ;
}
void Workspace : : screenChangeTimeout ( )
{
kDebug ( ) < < " It is time to call desktopResized " ;
desktopResized ( ) ;
}
2007-04-29 17:35:43 +00:00
void Workspace : : init ( )
2011-01-30 14:34:42 +00:00
{
2011-07-07 16:29:11 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
2011-06-23 17:54:14 +00:00
m_screenEdge . init ( ) ;
2011-07-07 16:29:11 +00:00
# endif
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
// Not used yet
//topDock = 0L;
//maximizedWindowCounter = 0;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
supportWindow = new QWidget ( NULL , Qt : : X11BypassWindowManagerHint ) ;
XLowerWindow ( display ( ) , supportWindow - > winId ( ) ) ; // See usage in layers.cpp
2007-04-29 17:35:43 +00:00
XSetWindowAttributes attr ;
attr . override_redirect = 1 ;
2011-01-30 14:34:42 +00:00
null_focus_window = XCreateWindow ( display ( ) , rootWindow ( ) , - 1 , - 1 , 1 , 1 , 0 , CopyFromParent ,
InputOnly , CopyFromParent , CWOverrideRedirect , & attr ) ;
XMapWindow ( display ( ) , null_focus_window ) ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
unsigned long protocols [ 5 ] = {
2007-04-29 17:35:43 +00:00
NET : : Supported |
NET : : SupportingWMCheck |
NET : : ClientList |
NET : : ClientListStacking |
NET : : DesktopGeometry |
NET : : NumberOfDesktops |
NET : : CurrentDesktop |
NET : : ActiveWindow |
NET : : WorkArea |
NET : : CloseWindow |
NET : : DesktopNames |
NET : : WMName |
NET : : WMVisibleName |
NET : : WMDesktop |
NET : : WMWindowType |
NET : : WMState |
NET : : WMStrut |
NET : : WMIconGeometry |
NET : : WMIcon |
NET : : WMPid |
NET : : WMMoveResize |
NET : : WMFrameExtents |
NET : : WMPing
,
NET : : NormalMask |
NET : : DesktopMask |
NET : : DockMask |
NET : : ToolbarMask |
NET : : MenuMask |
NET : : DialogMask |
NET : : OverrideMask |
NET : : UtilityMask |
NET : : SplashMask |
2008-12-18 13:50:57 +00:00
// No compositing window types here unless we support them also as managed window types
2007-04-29 17:35:43 +00:00
0
,
NET : : Modal |
2008-12-18 13:50:57 +00:00
//NET::Sticky | // Large desktops not supported (and probably never will be)
2007-04-29 17:35:43 +00:00
NET : : MaxVert |
NET : : MaxHoriz |
NET : : Shaded |
NET : : SkipTaskbar |
NET : : KeepAbove |
2008-12-18 13:50:57 +00:00
//NET::StaysOnTop | // The same like KeepAbove
2007-04-29 17:35:43 +00:00
NET : : SkipPager |
NET : : Hidden |
NET : : FullScreen |
NET : : KeepBelow |
NET : : DemandsAttention |
0
,
NET : : WM2UserTime |
NET : : WM2StartupId |
NET : : WM2AllowedActions |
NET : : WM2RestackWindow |
NET : : WM2MoveResizeWindow |
NET : : WM2ExtendedStrut |
NET : : WM2KDETemporaryRules |
NET : : WM2ShowingDesktop |
2007-04-30 12:00:32 +00:00
NET : : WM2DesktopLayout |
2007-05-07 12:37:12 +00:00
NET : : WM2FullPlacement |
2009-01-02 00:40:05 +00:00
NET : : WM2FullscreenMonitors |
2011-03-27 10:33:07 +00:00
NET : : WM2KDEShadow |
2007-04-29 17:35:43 +00:00
0
,
NET : : ActionMove |
NET : : ActionResize |
NET : : ActionMinimize |
NET : : ActionShade |
2008-12-18 13:50:57 +00:00
//NET::ActionStick | // Sticky state is not supported
2007-04-29 17:35:43 +00:00
NET : : ActionMaxVert |
NET : : ActionMaxHoriz |
NET : : ActionFullScreen |
NET : : ActionChangeDesktop |
NET : : ActionClose |
0
,
2011-01-30 14:34:42 +00:00
} ;
2007-04-29 17:35:43 +00:00
2011-04-28 13:56:50 +00:00
if ( hasDecorationPlugin ( ) & & mgr - > factory ( ) - > supports ( AbilityExtendIntoClientArea ) )
2009-12-16 18:03:15 +00:00
protocols [ NETRootInfo : : PROTOCOLS2 ] | = NET : : WM2FrameOverlap ;
2008-12-18 13:50:57 +00:00
QX11Info info ;
2011-01-30 14:34:42 +00:00
rootInfo = new RootInfo ( this , display ( ) , supportWindow - > winId ( ) , " KWin " , protocols , 5 , info . screen ( ) ) ;
2007-04-29 17:35:43 +00:00
2012-05-01 16:34:38 +00:00
// Create an entry with empty activity name, it will be used if activities are not supported. Otherwise, it will be removed.
m_desktopFocusChain = m_activitiesDesktopFocusChain . insert ( QString ( ) , QVector < int > ( numberOfDesktops ( ) ) ) ;
2012-05-26 19:06:40 +00:00
// Now we know how many desktops we'll have, thus we initialize the positioning object
initPositioning = new Placement ( this ) ;
2007-04-29 17:35:43 +00:00
loadDesktopSettings ( ) ;
2007-05-30 18:17:18 +00:00
updateDesktopLayout ( ) ;
2008-12-18 13:50:57 +00:00
// Extra NETRootInfo instance in Client mode is needed to get the values of the properties
2011-01-30 14:34:42 +00:00
NETRootInfo client_info ( display ( ) , NET : : ActiveWindow | NET : : CurrentDesktop ) ;
2007-04-29 17:35:43 +00:00
int initial_desktop ;
2011-01-30 14:34:42 +00:00
if ( ! kapp - > isSessionRestored ( ) )
2007-04-29 17:35:43 +00:00
initial_desktop = client_info . currentDesktop ( ) ;
2011-01-30 14:34:42 +00:00
else {
KConfigGroup group ( kapp - > sessionConfig ( ) , " Session " ) ;
initial_desktop = group . readEntry ( " desktop " , 1 ) ;
}
if ( ! setCurrentDesktop ( initial_desktop ) )
setCurrentDesktop ( 1 ) ;
2012-02-26 10:38:16 +00:00
# ifdef KWIN_BUILD_ACTIVITIES
2012-04-12 19:52:44 +00:00
updateActivityList ( false , true ) ;
2012-02-26 10:38:16 +00:00
# endif
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
reconfigureTimer . setSingleShot ( true ) ;
updateToolWindowsTimer . setSingleShot ( true ) ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
connect ( & reconfigureTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( slotReconfigure ( ) ) ) ;
connect ( & updateToolWindowsTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( slotUpdateToolWindows ( ) ) ) ;
connect ( & mousePollingTimer , SIGNAL ( timeout ( ) ) , SLOT ( performMousePoll ( ) ) ) ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
connect ( KGlobalSettings : : self ( ) , SIGNAL ( appearanceChanged ( ) ) , this , SLOT ( reconfigure ( ) ) ) ;
connect ( KGlobalSettings : : self ( ) , SIGNAL ( settingsChanged ( int ) ) , this , SLOT ( slotSettingsChanged ( int ) ) ) ;
connect ( KGlobalSettings : : self ( ) , SIGNAL ( blockShortcuts ( int ) ) , this , SLOT ( slotBlockShortcuts ( int ) ) ) ;
2007-04-29 17:35:43 +00:00
active_client = NULL ;
2011-01-30 14:34:42 +00:00
rootInfo - > setActiveWindow ( None ) ;
2007-04-29 17:35:43 +00:00
focusToNull ( ) ;
2011-01-30 14:34:42 +00:00
if ( ! kapp - > isSessionRestored ( ) )
2008-12-18 13:50:57 +00:00
+ + block_focus ; // Because it will be set below
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
{
// Begin updates blocker block
StackingUpdatesBlocker blocker ( this ) ;
2007-04-29 17:35:43 +00:00
unsigned int i , nwins ;
2008-12-18 13:50:57 +00:00
Window root_return , parent_return ;
Window * wins ;
2011-01-30 14:34:42 +00:00
XQueryTree ( display ( ) , rootWindow ( ) , & root_return , & parent_return , & wins , & nwins ) ;
bool fixoffset = KCmdLineArgs : : parsedArgs ( ) - > getOption ( " crashes " ) . toInt ( ) > 0 ;
for ( i = 0 ; i < nwins ; i + + ) {
2007-04-29 17:35:43 +00:00
XWindowAttributes attr ;
2011-01-30 14:34:42 +00:00
XGetWindowAttributes ( display ( ) , wins [ i ] , & attr ) ;
if ( attr . override_redirect ) {
createUnmanaged ( wins [ i ] ) ;
2007-04-29 17:35:43 +00:00
continue ;
2011-01-30 14:34:42 +00:00
}
if ( attr . map_state ! = IsUnmapped ) {
if ( fixoffset )
fixPositionAfterCrash ( wins [ i ] , attr ) ;
createClient ( wins [ i ] , true ) ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
}
if ( wins )
XFree ( ( void * ) ( wins ) ) ;
2008-12-18 13:50:57 +00:00
// Propagate clients, will really happen at the end of the updates blocker block
2011-01-30 14:34:42 +00:00
updateStackingOrder ( true ) ;
2007-04-29 17:35:43 +00:00
2011-09-30 11:22:39 +00:00
saveOldScreenSizes ( ) ;
2007-04-29 17:35:43 +00:00
updateClientArea ( ) ;
2008-12-18 13:50:57 +00:00
// NETWM spec says we have to set it to (0,0) if we don't support it
2009-02-14 09:46:12 +00:00
NETPoint * viewports = new NETPoint [ numberOfDesktops ( ) ] ;
2011-01-30 14:34:42 +00:00
rootInfo - > setDesktopViewport ( numberOfDesktops ( ) , * viewports ) ;
2007-04-29 17:35:43 +00:00
delete [ ] viewports ;
2012-03-27 17:14:53 +00:00
QRect geom ;
for ( int i = 0 ; i < QApplication : : desktop ( ) - > screenCount ( ) ; i + + ) {
geom | = QApplication : : desktop ( ) - > screenGeometry ( i ) ;
}
2007-04-29 17:35:43 +00:00
NETSize desktop_geometry ;
desktop_geometry . width = geom . width ( ) ;
desktop_geometry . height = geom . height ( ) ;
2011-01-30 14:34:42 +00:00
rootInfo - > setDesktopGeometry ( - 1 , desktop_geometry ) ;
setShowingDesktop ( false ) ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
} // End updates blocker block
2007-04-29 17:35:43 +00:00
Client * new_active_client = NULL ;
2011-01-30 14:34:42 +00:00
if ( ! kapp - > isSessionRestored ( ) ) {
2007-04-29 17:35:43 +00:00
- - block_focus ;
2011-01-30 14:34:42 +00:00
new_active_client = findClient ( WindowMatchPredicate ( client_info . activeWindow ( ) ) ) ;
}
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 ( ) , - 1 ) ;
if ( new_active_client = = NULL & & ! desktops . isEmpty ( ) )
new_active_client = findDesktop ( true , currentDesktop ( ) ) ;
}
if ( new_active_client ! = NULL )
activateClient ( new_active_client ) ;
2009-09-08 20:01:08 +00:00
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2010-04-25 16:43:14 +00:00
// Enable/disable tiling
2012-02-20 09:25:13 +00:00
m_tiling - > setEnabled ( options - > isTilingOn ( ) ) ;
2011-07-20 11:25:00 +00:00
# endif
2010-04-25 16:43:14 +00:00
2012-04-12 13:19:38 +00:00
# ifdef KWIN_BUILD_SCRIPTING
m_scripting = new Scripting ( this ) ;
# endif
2008-12-18 13:50:57 +00:00
// SELI TODO: This won't work with unreasonable focus policies,
2007-04-29 17:35:43 +00:00
// and maybe in rare cases also if the selected client doesn't
// want focus
workspaceInit = false ;
2008-12-18 13:50:57 +00:00
2012-04-13 09:27:50 +00:00
// broadcast that Workspace is ready, but first process all events.
QMetaObject : : invokeMethod ( this , " workspaceInitialized " , Qt : : QueuedConnection ) ;
2008-12-18 13:50:57 +00:00
// TODO: ungrabXServer()
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
Workspace : : ~ Workspace ( )
2011-01-30 14:34:42 +00:00
{
2007-04-29 17:35:43 +00:00
finishCompositing ( ) ;
2011-01-30 14:34:42 +00:00
blockStackingUpdates ( true ) ;
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-18 09:09:12 +00:00
delete m_tiling ;
2011-07-20 11:25:00 +00:00
# endif
2008-12-18 13:50:57 +00:00
// TODO: grabXServer();
// Use stacking_order, so that kwin --replace keeps stacking order
2012-04-08 08:07:35 +00:00
for ( ToplevelList : : iterator it = stacking_order . begin ( ) , end = stacking_order . end ( ) ; it ! = end ; + + it ) {
Client * c = qobject_cast < Client * > ( * it ) ;
if ( ! c ) {
continue ;
}
2008-12-18 13:50:57 +00:00
// Only release the window
2012-04-08 08:07:35 +00:00
c - > releaseWindow ( true ) ;
2007-04-30 09:46:31 +00:00
// No removeClient() is called, it does more than just removing.
// However, remove from some lists to e.g. prevent performTransiencyCheck()
// from crashing.
2012-04-08 08:07:35 +00:00
clients . removeAll ( c ) ;
desktops . removeAll ( c ) ;
2011-01-30 14:34:42 +00:00
}
2011-11-01 20:20:31 +00:00
for ( UnmanagedList : : iterator it = unmanaged . begin ( ) , end = unmanaged . end ( ) ; it ! = end ; + + it )
2012-04-22 07:27:53 +00:00
( * it ) - > release ( true ) ;
2011-04-28 09:16:27 +00:00
delete m_outline ;
2008-08-07 11:51:20 +00:00
discardPopup ( ) ;
2011-01-30 14:34:42 +00:00
XDeleteProperty ( display ( ) , rootWindow ( ) , atoms - > kwin_running ) ;
2007-04-29 17:35:43 +00:00
writeWindowRules ( ) ;
KGlobal : : config ( ) - > sync ( ) ;
delete rootInfo ;
delete supportWindow ;
delete mgr ;
delete startup ;
delete initPositioning ;
2007-11-01 19:24:35 +00:00
delete client_keys_dialog ;
2011-01-30 14:34:42 +00:00
while ( ! rules . isEmpty ( ) ) {
2007-04-29 17:35:43 +00:00
delete rules . front ( ) ;
rules . pop_front ( ) ;
2011-01-30 14:34:42 +00:00
}
foreach ( SessionInfo * s , session )
delete s ;
XDestroyWindow ( display ( ) , null_focus_window ) ;
2008-12-18 13:50:57 +00:00
// TODO: ungrabXServer();
2009-02-14 15:40:52 +00:00
delete [ ] desktopGrid_ ;
2007-04-29 17:35:43 +00:00
_self = 0 ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
Client * Workspace : : createClient ( Window w , bool is_mapped )
{
StackingUpdatesBlocker blocker ( this ) ;
Client * c = new Client ( this ) ;
if ( ! c - > manage ( w , is_mapped ) ) {
Client : : deleteClient ( c , Allowed ) ;
2007-04-29 17:35:43 +00:00
return NULL ;
2011-01-30 14:34:42 +00:00
}
addClient ( c , Allowed ) ;
2011-08-02 12:13:08 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-13 16:48:56 +00:00
m_tiling - > createTile ( c ) ;
2011-08-02 12:13:08 +00:00
# endif
2007-04-29 17:35:43 +00:00
return c ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
Unmanaged * Workspace : : createUnmanaged ( Window w )
{
2011-07-09 23:25:41 +00:00
if ( compositing ( ) & & w = = scene - > overlayWindow ( ) - > window ( ) )
2007-04-29 17:35:43 +00:00
return NULL ;
2011-01-30 14:34:42 +00:00
Unmanaged * c = new Unmanaged ( this ) ;
if ( ! c - > track ( w ) ) {
Unmanaged : : deleteUnmanaged ( c , Allowed ) ;
2007-04-29 17:35:43 +00:00
return NULL ;
}
2011-01-30 14:34:42 +00:00
addUnmanaged ( c , Allowed ) ;
2011-02-25 21:06:02 +00:00
emit unmanagedAdded ( c ) ;
2011-01-30 14:34:42 +00:00
return c ;
}
void Workspace : : addClient ( Client * c , allowed_t )
{
Group * grp = findGroup ( c - > window ( ) ) ;
2007-04-29 17:35:43 +00:00
2010-09-21 14:31:40 +00:00
KWindowInfo info = KWindowSystem : : windowInfo ( c - > window ( ) , - 1U , NET : : WM2WindowClass ) ;
2011-01-30 14:34:42 +00:00
2010-09-21 14:31:40 +00:00
emit clientAdded ( c ) ;
2011-01-30 14:34:42 +00:00
if ( grp ! = NULL )
grp - > gotLeader ( c ) ;
if ( c - > isDesktop ( ) ) {
desktops . append ( c ) ;
if ( active_client = = NULL & & should_get_focus . isEmpty ( ) & & c - > isOnCurrentDesktop ( ) )
requestFocus ( c ) ; // TODO: Make sure desktop is active after startup if there's no other window active
} else {
updateFocusChains ( c , FocusChainUpdate ) ; // Add to focus chain if not already there
clients . append ( c ) ;
}
if ( ! unconstrained_stacking_order . contains ( c ) )
unconstrained_stacking_order . append ( c ) ; // Raise if it hasn't got any stacking position yet
if ( ! stacking_order . contains ( c ) ) // It'll be updated later, and updateToolWindows() requires
stacking_order . append ( c ) ; // c to be in stacking_order
2008-08-24 10:35:45 +00:00
x_stacking_dirty = true ;
2008-12-18 13:50:57 +00:00
updateClientArea ( ) ; // This cannot be in manage(), because the client got added only now
2011-01-30 14:34:42 +00:00
updateClientLayer ( c ) ;
if ( c - > isDesktop ( ) ) {
raiseClient ( c ) ;
2008-12-18 13:50:57 +00:00
// If there's no active client, make this desktop the active one
2011-01-30 14:34:42 +00:00
if ( activeClient ( ) = = NULL & & should_get_focus . count ( ) = = 0 )
activateClient ( findDesktop ( true , currentDesktop ( ) ) ) ;
}
2007-04-29 17:35:43 +00:00
c - > checkActiveModal ( ) ;
2011-01-30 14:34:42 +00:00
checkTransients ( c - > window ( ) ) ; // SELI TODO: Does this really belong here?
updateStackingOrder ( true ) ; // Propagate new client
if ( c - > isUtility ( ) | | c - > isMenu ( ) | | c - > isToolbar ( ) )
updateToolWindows ( true ) ;
2007-04-30 09:47:59 +00:00
checkNonExistentClients ( ) ;
2011-06-30 11:02:30 +00:00
# ifdef KWIN_BUILD_TABBOX
2011-12-01 10:06:19 +00:00
if ( tabBox ( ) - > isDisplayed ( ) )
2011-01-30 14:34:42 +00:00
tab_box - > reset ( true ) ;
2011-06-30 11:02:30 +00:00
# endif
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : addUnmanaged ( Unmanaged * c , allowed_t )
{
unmanaged . append ( c ) ;
2008-08-24 10:35:45 +00:00
x_stacking_dirty = true ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Destroys the client \ a c
2007-04-29 17:35:43 +00:00
*/
2011-01-30 14:34:42 +00:00
void Workspace : : removeClient ( Client * c , allowed_t )
{
2010-09-21 14:31:40 +00:00
emit clientRemoved ( c ) ;
2011-01-30 14:34:42 +00:00
2007-04-29 17:35:43 +00:00
if ( c = = active_popup_client )
closeActivePopup ( ) ;
2012-01-12 06:42:55 +00:00
c - > untab ( ) ;
2011-01-30 14:34:42 +00:00
if ( client_keys_client = = c )
setupWindowShortcutDone ( false ) ;
if ( ! c - > shortcut ( ) . isEmpty ( ) ) {
c - > setShortcut ( QString ( ) ) ; // Remove from client_keys
clientShortcutUpdated ( c ) ; // Needed, since this is otherwise delayed by setShortcut() and wouldn't run
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
if ( c - > isDialog ( ) )
Notify : : raise ( Notify : : TransDelete ) ;
if ( c - > isNormalWindow ( ) )
Notify : : raise ( Notify : : Delete ) ;
2007-04-29 17:35:43 +00:00
2011-06-30 11:02:30 +00:00
# ifdef KWIN_BUILD_TABBOX
2011-12-01 10:06:19 +00:00
if ( tabBox ( ) - > isDisplayed ( ) & & tabBox ( ) - > currentClient ( ) = = c )
2011-01-30 14:34:42 +00:00
tab_box - > nextPrev ( true ) ;
2011-06-30 11:02:30 +00:00
# endif
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
Q_ASSERT ( clients . contains ( c ) | | desktops . contains ( c ) ) ;
2010-04-25 16:43:14 +00:00
// TODO: if marked client is removed, notify the marked list
2011-01-30 14:34:42 +00:00
clients . removeAll ( c ) ;
desktops . removeAll ( c ) ;
2008-08-24 10:35:45 +00:00
x_stacking_dirty = true ;
2011-01-30 14:34:42 +00:00
for ( int i = 1 ; i < = numberOfDesktops ( ) ; + + i )
focus_chain [ i ] . removeAll ( c ) ;
global_focus_chain . removeAll ( c ) ;
attention_chain . removeAll ( c ) ;
showing_desktop_clients . removeAll ( c ) ;
Group * group = findGroup ( c - > window ( ) ) ;
if ( group ! = NULL )
2007-04-29 17:35:43 +00:00
group - > lostLeader ( ) ;
2011-01-30 14:34:42 +00:00
if ( c = = most_recently_raised )
2007-04-29 17:35:43 +00:00
most_recently_raised = 0 ;
2011-01-30 14:34:42 +00:00
should_get_focus . removeAll ( c ) ;
Q_ASSERT ( c ! = active_client ) ;
if ( c = = last_active_client )
2007-04-29 17:35:43 +00:00
last_active_client = 0 ;
2011-01-30 14:34:42 +00:00
if ( c = = pending_take_activity )
2007-04-29 17:35:43 +00:00
pending_take_activity = NULL ;
2011-01-30 14:34:42 +00:00
if ( c = = delayfocus_client )
2007-04-29 17:35:43 +00:00
cancelDelayFocus ( ) ;
2011-01-30 14:34:42 +00:00
updateStackingOrder ( true ) ;
2007-04-29 17:35:43 +00:00
2011-03-20 14:42:05 +00:00
updateCompositeBlocking ( ) ;
2011-06-30 11:02:30 +00:00
# ifdef KWIN_BUILD_TABBOX
2011-12-01 10:06:19 +00:00
if ( tabBox ( ) - > isDisplayed ( ) )
2011-01-30 14:34:42 +00:00
tab_box - > reset ( true ) ;
2011-06-30 11:02:30 +00:00
# endif
2007-04-29 17:35:43 +00:00
updateClientArea ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : removeUnmanaged ( Unmanaged * c , allowed_t )
{
assert ( unmanaged . contains ( c ) ) ;
unmanaged . removeAll ( c ) ;
2008-08-24 10:35:45 +00:00
x_stacking_dirty = true ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2012-04-09 09:06:44 +00:00
void Workspace : : addDeleted ( Deleted * c , Toplevel * orig , allowed_t )
2011-01-30 14:34:42 +00:00
{
assert ( ! deleted . contains ( c ) ) ;
deleted . append ( c ) ;
2012-04-09 09:06:44 +00:00
const int unconstraintedIndex = unconstrained_stacking_order . indexOf ( orig ) ;
if ( unconstraintedIndex ! = - 1 ) {
unconstrained_stacking_order . replace ( unconstraintedIndex , c ) ;
} else {
unconstrained_stacking_order . append ( c ) ;
}
const int index = stacking_order . indexOf ( orig ) ;
if ( index ! = - 1 ) {
stacking_order . replace ( index , c ) ;
} else {
stacking_order . append ( c ) ;
}
2008-08-24 10:35:45 +00:00
x_stacking_dirty = true ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : removeDeleted ( Deleted * c , allowed_t )
{
assert ( deleted . contains ( c ) ) ;
if ( scene )
scene - > windowDeleted ( c ) ;
2011-02-27 09:47:42 +00:00
emit deletedRemoved ( c ) ;
2011-01-30 14:34:42 +00:00
deleted . removeAll ( c ) ;
2012-04-09 09:06:44 +00:00
unconstrained_stacking_order . removeAll ( c ) ;
stacking_order . removeAll ( c ) ;
2008-08-24 10:35:45 +00:00
x_stacking_dirty = true ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : updateFocusChains ( Client * c , FocusChainChange change )
{
if ( ! c - > wantsTabFocus ( ) ) { // Doesn't want tab focus, remove
for ( int i = 1 ; i < = numberOfDesktops ( ) ; + + i )
focus_chain [ i ] . removeAll ( c ) ;
global_focus_chain . removeAll ( c ) ;
2007-04-29 17:35:43 +00:00
return ;
2011-01-30 14:34:42 +00:00
}
if ( c - > desktop ( ) = = NET : : OnAllDesktops ) {
// Now on all desktops, add it to focus_chains it is not already in
for ( int i = 1 ; i < = numberOfDesktops ( ) ; i + + ) {
// Making first/last works only on current desktop, don't affect all desktops
if ( i = = currentDesktop ( )
& & ( change = = FocusChainMakeFirst | | change = = FocusChainMakeLast ) ) {
focus_chain [ i ] . removeAll ( c ) ;
if ( change = = FocusChainMakeFirst )
focus_chain [ i ] . append ( c ) ;
2007-04-29 17:35:43 +00:00
else
2011-01-30 14:34:42 +00:00
focus_chain [ i ] . prepend ( c ) ;
} else if ( ! focus_chain [ i ] . contains ( c ) ) {
// Add it after the active one
if ( active_client ! = NULL & & active_client ! = c & &
! focus_chain [ i ] . isEmpty ( ) & & focus_chain [ i ] . last ( ) = = active_client )
focus_chain [ i ] . insert ( focus_chain [ i ] . size ( ) - 1 , c ) ;
2007-04-29 22:33:55 +00:00
else
2011-01-30 14:34:42 +00:00
focus_chain [ i ] . append ( c ) ; // Otherwise add as the first one
2007-04-29 17:35:43 +00:00
}
}
2011-01-30 14:34:42 +00:00
} else { // Now only on desktop, remove it anywhere else
for ( int i = 1 ; i < = numberOfDesktops ( ) ; i + + ) {
if ( i = = c - > desktop ( ) ) {
if ( change = = FocusChainMakeFirst ) {
focus_chain [ i ] . removeAll ( c ) ;
focus_chain [ i ] . append ( c ) ;
} else if ( change = = FocusChainMakeLast ) {
focus_chain [ i ] . removeAll ( c ) ;
focus_chain [ i ] . prepend ( c ) ;
} else if ( ! focus_chain [ i ] . contains ( c ) ) {
// Add it after the active one
if ( active_client ! = NULL & & active_client ! = c & &
! focus_chain [ i ] . isEmpty ( ) & & focus_chain [ i ] . last ( ) = = active_client )
focus_chain [ i ] . insert ( focus_chain [ i ] . size ( ) - 1 , c ) ;
2007-04-29 22:33:55 +00:00
else
2011-01-30 14:34:42 +00:00
focus_chain [ i ] . append ( c ) ; // Otherwise add as the first one
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
} else
focus_chain [ i ] . removeAll ( c ) ;
}
}
if ( change = = FocusChainMakeFirst ) {
global_focus_chain . removeAll ( c ) ;
global_focus_chain . append ( c ) ;
} else if ( change = = FocusChainMakeLast ) {
global_focus_chain . removeAll ( c ) ;
global_focus_chain . prepend ( c ) ;
} else if ( ! global_focus_chain . contains ( c ) ) {
// Add it after the active one
if ( active_client ! = NULL & & active_client ! = c & &
! global_focus_chain . isEmpty ( ) & & global_focus_chain . last ( ) = = active_client )
global_focus_chain . insert ( global_focus_chain . size ( ) - 1 , c ) ;
2007-04-29 22:33:55 +00:00
else
2011-01-30 14:34:42 +00:00
global_focus_chain . append ( c ) ; // Otherwise add as the first one
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : updateToolWindows ( bool also_hide )
{
2008-12-18 13:50:57 +00:00
// TODO: What if Client's transiency/group changes? should this be called too? (I'm paranoid, am I not?)
2012-02-20 09:25:13 +00:00
if ( ! options - > isHideUtilityWindowsForInactive ( ) ) {
2011-09-25 15:52:05 +00:00
for ( ClientList : : ConstIterator it = clients . constBegin ( ) ; it ! = clients . constEnd ( ) ; + + it )
2012-01-12 06:42:55 +00:00
if ( ! ( * it ) - > tabGroup ( ) | | ( * it ) - > tabGroup ( ) - > current ( ) = = * it )
2011-09-25 15:52:05 +00:00
( * it ) - > hideClient ( false ) ;
2007-04-29 17:35:43 +00:00
return ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
const Group * group = NULL ;
const Client * client = active_client ;
2008-12-18 13:50:57 +00:00
// 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
2011-01-30 14:34:42 +00:00
while ( client ! = NULL ) {
if ( ! client - > isTransient ( ) )
2007-04-29 17:35:43 +00:00
break ;
2011-01-30 14:34:42 +00:00
if ( client - > groupTransient ( ) ) {
2007-04-29 17:35:43 +00:00
group = client - > group ( ) ;
break ;
}
2011-01-30 14:34:42 +00:00
client = client - > transientFor ( ) ;
}
2008-12-18 13:50:57 +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
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
// SELI TODO: But maybe it should - what if a new client has been added that's not in stacking order yet?
2007-04-29 17:35:43 +00:00
ClientList to_show , to_hide ;
2012-04-08 08:07:35 +00:00
for ( ToplevelList : : ConstIterator it = stacking_order . constBegin ( ) ;
2011-01-30 14:34:42 +00:00
it ! = stacking_order . constEnd ( ) ;
+ + it ) {
2012-04-08 08:07:35 +00:00
Client * c = qobject_cast < Client * > ( * it ) ;
if ( ! c ) {
continue ;
}
if ( c - > isUtility ( ) | | c - > isMenu ( ) | | c - > isToolbar ( ) ) {
2007-04-29 17:35:43 +00:00
bool show = true ;
2012-04-08 08:07:35 +00:00
if ( ! c - > isTransient ( ) ) {
if ( c - > group ( ) - > members ( ) . count ( ) = = 1 ) // Has its own group, keep always visible
2007-04-29 17:35:43 +00:00
show = true ;
2012-04-08 08:07:35 +00:00
else if ( client ! = NULL & & c - > group ( ) = = client - > group ( ) )
2007-04-29 17:35:43 +00:00
show = true ;
else
show = false ;
2011-01-30 14:34:42 +00:00
} else {
2012-04-08 08:07:35 +00:00
if ( group ! = NULL & & c - > group ( ) = = group )
2007-04-29 17:35:43 +00:00
show = true ;
2012-04-08 08:07:35 +00:00
else if ( client ! = NULL & & client - > hasTransient ( c , true ) )
2007-04-29 17:35:43 +00:00
show = true ;
else
show = false ;
2011-01-30 14:34:42 +00:00
}
if ( ! show & & also_hide ) {
2012-04-08 08:07:35 +00:00
const ClientList mainclients = c - > mainClients ( ) ;
2008-12-18 13:50:57 +00:00
// Don't hide utility windows which are standalone(?) or
2007-04-29 17:35:43 +00:00
// have e.g. kicker as mainwindow
2011-01-30 14:34:42 +00:00
if ( mainclients . isEmpty ( ) )
2007-04-29 17:35:43 +00:00
show = true ;
2011-01-30 14:34:42 +00:00
for ( ClientList : : ConstIterator it2 = mainclients . constBegin ( ) ;
it2 ! = mainclients . constEnd ( ) ;
+ + it2 ) {
2012-04-08 08:07:35 +00:00
if ( c - > isSpecialWindow ( ) )
2007-04-29 17:35:43 +00:00
show = true ;
}
2011-01-30 14:34:42 +00:00
if ( ! show )
2012-04-08 08:07:35 +00:00
to_hide . append ( c ) ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
if ( show )
2012-04-08 08:07:35 +00:00
to_show . append ( c ) ;
2011-01-30 14:34:42 +00:00
}
} // First show new ones, then hide
for ( int i = to_show . size ( ) - 1 ;
i > = 0 ;
- - i ) // From topmost
2008-12-18 13:50:57 +00:00
// TODO: Since this is in stacking order, the order of taskbar entries changes :(
2011-01-30 14:34:42 +00:00
to_show . at ( i ) - > hideClient ( false ) ;
if ( also_hide ) {
for ( ClientList : : ConstIterator it = to_hide . constBegin ( ) ;
it ! = to_hide . constEnd ( ) ;
+ + it ) // From bottommost
( * it ) - > hideClient ( true ) ;
2007-04-29 17:35:43 +00:00
updateToolWindowsTimer . stop ( ) ;
2011-01-30 14:34:42 +00:00
} else // setActiveClient() is after called with NULL client, quickly followed
// by setting a new client, which would result in flickering
2010-12-31 13:44:17 +00:00
resetUpdateToolWindowsTimer ( ) ;
2011-01-30 14:34:42 +00:00
}
2010-12-31 13:44:17 +00:00
void Workspace : : resetUpdateToolWindowsTimer ( )
2011-01-30 14:34:42 +00:00
{
updateToolWindowsTimer . start ( 200 ) ;
}
2007-04-29 17:35:43 +00:00
void Workspace : : slotUpdateToolWindows ( )
2011-01-30 14:34:42 +00:00
{
updateToolWindows ( true ) ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Updates the current colormap according to the currently active client
2007-04-29 17:35:43 +00:00
*/
void Workspace : : updateColormap ( )
2011-01-30 14:34:42 +00:00
{
2007-04-29 17:35:43 +00:00
Colormap cmap = default_colormap ;
2011-01-30 14:34:42 +00:00
if ( activeClient ( ) & & activeClient ( ) - > colormap ( ) ! = None )
2007-04-29 17:35:43 +00:00
cmap = activeClient ( ) - > colormap ( ) ;
2011-01-30 14:34:42 +00:00
if ( cmap ! = installed_colormap ) {
XInstallColormap ( display ( ) , cmap ) ;
2007-04-29 17:35:43 +00:00
installed_colormap = cmap ;
}
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2008-01-30 16:08:23 +00:00
void Workspace : : slotReloadConfig ( )
2011-01-30 14:34:42 +00:00
{
2008-12-18 13:50:57 +00:00
reconfigure ( ) ;
2011-01-30 14:34:42 +00:00
}
2008-01-30 16:08:23 +00:00
2007-04-29 17:35:43 +00:00
void Workspace : : reconfigure ( )
2011-01-30 14:34:42 +00:00
{
reconfigureTimer . start ( 200 ) ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* This D - Bus call is used by the compositing kcm . Since the reconfigure ( )
* D - Bus call delays the actual reconfiguring , it is not possible to immediately
* call compositingActive ( ) . Therefore the kcm will instead call this to ensure
* the reconfiguring has already happened .
*/
2008-12-08 05:08:31 +00:00
bool Workspace : : waitForCompositingSetup ( )
2011-01-30 14:34:42 +00:00
{
if ( reconfigureTimer . isActive ( ) ) {
2009-04-28 16:20:26 +00:00
reconfigureTimer . stop ( ) ;
slotReconfigure ( ) ;
2008-12-08 05:08:31 +00:00
}
2011-01-30 14:34:42 +00:00
return compositingActive ( ) ;
}
2008-12-08 05:08:31 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : slotSettingsChanged ( int category )
{
kDebug ( 1212 ) < < " Workspace::slotSettingsChanged() " ;
if ( category = = KGlobalSettings : : SETTINGS_SHORTCUTS )
2011-06-25 16:05:07 +00:00
discardPopup ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Reread settings
2007-04-29 17:35:43 +00:00
*/
2011-01-30 14:34:42 +00:00
KWIN_PROCEDURE ( CheckBorderSizesProcedure , Client , cl - > checkBorderSizes ( true ) ) ;
2007-04-29 17:35:43 +00:00
void Workspace : : slotReconfigure ( )
2011-01-30 14:34:42 +00:00
{
kDebug ( 1212 ) < < " Workspace::slotReconfigure() " ;
2007-04-29 17:35:43 +00:00
reconfigureTimer . stop ( ) ;
2011-07-07 16:29:11 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
2011-06-27 11:02:53 +00:00
m_screenEdge . reserveActions ( false ) ;
2011-01-30 14:34:42 +00:00
if ( options - > electricBorders ( ) = = Options : : ElectricAlways )
2012-05-03 17:48:20 +00:00
m_screenEdge . reserveDesktopSwitching ( false , m_screenEdgeOrientation ) ;
2011-07-07 16:29:11 +00:00
# endif
2007-04-29 17:35:43 +00:00
2010-10-26 14:43:29 +00:00
bool borderlessMaximizedWindows = options - > borderlessMaximizedWindows ( ) ;
2007-04-29 17:35:43 +00:00
KGlobal : : config ( ) - > reparseConfiguration ( ) ;
unsigned long changed = options - > updateSettings ( ) ;
2008-11-25 01:45:09 +00:00
2011-07-13 09:36:49 +00:00
emit configChanged ( ) ;
2011-06-25 16:05:07 +00:00
discardPopup ( ) ;
2011-01-30 14:34:42 +00:00
updateToolWindows ( true ) ;
2007-04-29 17:35:43 +00:00
2011-04-28 13:56:50 +00:00
if ( hasDecorationPlugin ( ) & & mgr - > reset ( changed ) ) {
2011-01-30 14:34:42 +00:00
// Decorations need to be recreated
2008-12-18 13:50:57 +00:00
// This actually seems to make things worse now
//QWidget curtain;
//curtain.setBackgroundMode( NoBackground );
//curtain.setGeometry( Kephal::ScreenUtils::desktopGeometry() );
//curtain.show();
2012-01-12 06:42:55 +00:00
for ( ClientList : : ConstIterator it = clients . constBegin ( ) ; it ! = clients . constEnd ( ) ; + + it )
2011-01-30 14:34:42 +00:00
( * it ) - > updateDecoration ( true , true ) ;
2009-11-15 03:24:04 +00:00
// If the new decoration doesn't supports tabs then ungroup clients
2012-01-12 06:42:55 +00:00
if ( ! decorationSupportsTabbing ( ) ) {
foreach ( Client * c , clients )
c - > untab ( ) ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
mgr - > destroyPreviousPlugin ( ) ;
} else {
forEachClient ( CheckBorderSizesProcedure ( ) ) ;
foreach ( Client * c , clients )
2012-01-12 06:42:55 +00:00
c - > triggerDecorationRepaint ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-07-07 16:29:11 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
2011-06-27 11:02:53 +00:00
m_screenEdge . reserveActions ( true ) ;
2012-05-03 17:48:20 +00:00
if ( options - > electricBorders ( ) = = Options : : ElectricAlways ) {
QSize desktopMatrix = rootInfo - > desktopLayoutColumnsRows ( ) ;
m_screenEdgeOrientation = 0 ;
if ( desktopMatrix . width ( ) > 1 )
m_screenEdgeOrientation | = Qt : : Horizontal ;
if ( desktopMatrix . height ( ) > 1 )
m_screenEdgeOrientation | = Qt : : Vertical ;
m_screenEdge . reserveDesktopSwitching ( true , m_screenEdgeOrientation ) ;
}
2011-06-27 11:02:53 +00:00
m_screenEdge . update ( ) ;
2011-07-07 16:29:11 +00:00
# endif
2007-04-29 17:35:43 +00:00
2011-02-27 22:39:32 +00:00
if ( ! compositingSuspended ) {
2007-04-29 17:35:43 +00:00
setupCompositing ( ) ;
2011-01-30 14:34:42 +00:00
if ( effects ) // setupCompositing() may fail
2007-06-03 19:48:27 +00:00
effects - > reconfigure ( ) ;
2008-12-08 05:08:31 +00:00
addRepaintFull ( ) ;
2011-01-30 14:34:42 +00:00
} else
2007-04-29 17:35:43 +00:00
finishCompositing ( ) ;
loadWindowRules ( ) ;
2011-01-30 14:34:42 +00:00
for ( ClientList : : Iterator it = clients . begin ( ) ;
it ! = clients . end ( ) ;
+ + it ) {
( * it ) - > setupWindowRules ( true ) ;
2007-04-29 17:35:43 +00:00
( * it ) - > applyWindowRules ( ) ;
2011-01-30 14:34:42 +00:00
discardUsedWindowRules ( * it , false ) ;
}
2010-04-25 16:43:14 +00:00
2011-01-30 14:34:42 +00:00
if ( borderlessMaximizedWindows ! = options - > borderlessMaximizedWindows ( ) & &
! options - > borderlessMaximizedWindows ( ) ) {
2010-10-26 14:43:29 +00:00
// in case borderless maximized windows option changed and new option
// is to have borders, we need to unset the borders for all maximized windows
2011-01-30 14:34:42 +00:00
for ( ClientList : : Iterator it = clients . begin ( ) ;
it ! = clients . end ( ) ;
+ + it ) {
if ( ( * it ) - > maximizeMode ( ) = = MaximizeFull )
2010-10-26 14:43:29 +00:00
( * it ) - > checkNoBorder ( ) ;
}
2011-01-30 14:34:42 +00:00
}
2010-10-26 14:43:29 +00:00
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2012-02-20 09:25:13 +00:00
m_tiling - > setEnabled ( options - > isTilingOn ( ) ) ;
2011-01-30 14:34:42 +00:00
// just so that we reset windows in the right manner, 'activate' the current active window
2011-07-13 16:48:56 +00:00
m_tiling - > notifyTilingWindowActivated ( activeClient ( ) ) ;
2011-07-20 11:25:00 +00:00
# endif
2011-04-28 13:56:50 +00:00
if ( hasDecorationPlugin ( ) ) {
rootInfo - > setSupported ( NET : : WM2FrameOverlap , mgr - > factory ( ) - > supports ( AbilityExtendIntoClientArea ) ) ;
} else {
rootInfo - > setSupported ( NET : : WM2FrameOverlap , false ) ;
}
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-12-16 16:36:27 +00:00
void Workspace : : restartKWin ( const QString & reason )
{
kDebug ( 1212 ) < < " restarting kwin for: " < < reason ;
char cmd [ 1024 ] ; // copied from crashhandler - maybe not the best way to do?
sprintf ( cmd , " %s --replace & " , QFile : : encodeName ( QCoreApplication : : applicationFilePath ( ) ) . constData ( ) ) ;
system ( cmd ) ;
}
2008-12-08 05:08:31 +00:00
void Workspace : : slotReinitCompositing ( )
2011-01-30 14:34:42 +00:00
{
2008-12-08 05:08:31 +00:00
// Reparse config. Config options will be reloaded by setupCompositing()
2007-09-20 17:19:19 +00:00
KGlobal : : config ( ) - > reparseConfiguration ( ) ;
2012-04-27 09:37:21 +00:00
const QString graphicsSystem = KConfigGroup ( KGlobal : : config ( ) , " Compositing " ) . readEntry ( " GraphicsSystem " , " " ) ;
2011-12-16 16:36:27 +00:00
if ( ( Extensions : : nonNativePixmaps ( ) & & graphicsSystem = = " native " ) | |
2012-03-29 14:23:06 +00:00
( ! Extensions : : nonNativePixmaps ( ) & & ( graphicsSystem = = " raster " | | graphicsSystem = = " opengl " ) ) ) {
2011-12-16 16:36:27 +00:00
restartKWin ( " explicitly reconfigured graphicsSystem change " ) ;
return ;
}
2007-09-20 17:19:19 +00:00
2008-11-25 01:42:30 +00:00
// Update any settings that can be set in the compositing kcm.
2011-07-07 16:29:11 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
2011-06-27 11:02:53 +00:00
m_screenEdge . update ( ) ;
2011-07-07 16:29:11 +00:00
# endif
2008-11-25 01:42:30 +00:00
2008-12-18 13:50:57 +00:00
// Restart compositing
2007-09-20 17:19:19 +00:00
finishCompositing ( ) ;
2011-01-30 14:34:42 +00:00
2009-04-30 12:51:55 +00:00
// resume compositing if suspended
compositingSuspended = false ;
2012-02-20 09:25:13 +00:00
options - > setCompositingInitialized ( false ) ;
2007-09-20 17:19:19 +00:00
setupCompositing ( ) ;
2011-04-28 13:56:50 +00:00
if ( hasDecorationPlugin ( ) ) {
KDecorationFactory * factory = mgr - > factory ( ) ;
factory - > reset ( SettingCompositing ) ;
}
2011-01-30 14:34:42 +00:00
if ( effects ) { // setupCompositing() may fail
2007-09-20 17:19:19 +00:00
effects - > reconfigure ( ) ;
2011-01-30 14:34:42 +00:00
emit compositingToggled ( true ) ;
2007-09-20 17:19:19 +00:00
}
2011-01-30 14:34:42 +00:00
}
2007-09-20 17:19:19 +00:00
2011-05-08 15:14:45 +00:00
static bool _loading_desktop_settings = false ;
2007-04-29 17:35:43 +00:00
void Workspace : : loadDesktopSettings ( )
2011-01-30 14:34:42 +00:00
{
2011-05-08 15:14:45 +00:00
_loading_desktop_settings = true ;
2007-04-29 17:35:43 +00:00
KSharedConfig : : Ptr c = KGlobal : : config ( ) ;
QString groupname ;
2011-01-30 14:34:42 +00:00
if ( screen_number = = 0 )
2007-04-29 17:35:43 +00:00
groupname = " Desktops " ;
else
2011-01-30 14:34:42 +00:00
groupname . sprintf ( " Desktops-screen-%d " , screen_number ) ;
KConfigGroup group ( c , groupname ) ;
2011-04-26 20:28:19 +00:00
const int n = group . readEntry ( " Number " , 1 ) ;
2011-03-07 17:41:17 +00:00
setNumberOfDesktops ( n ) ;
2011-01-30 14:34:42 +00:00
for ( int i = 1 ; i < = n ; i + + ) {
QString s = group . readEntry ( QString ( " Name_%1 " ) . arg ( i ) , i18n ( " Desktop %1 " , i ) ) ;
rootInfo - > setDesktopName ( i , s . toUtf8 ( ) . data ( ) ) ;
2012-05-01 16:34:38 +00:00
m_desktopFocusChain . value ( ) [ i - 1 ] = i ;
2007-04-29 17:35:43 +00:00
}
2011-07-24 12:59:39 +00:00
int rows = group . readEntry < int > ( " Rows " , 2 ) ;
rows = qBound ( 1 , rows , n ) ;
// avoid weird cases like having 3 rows for 4 desktops, where the last row is unused
int columns = n / rows ;
if ( n % rows > 0 ) {
columns + + ;
}
rootInfo - > setDesktopLayout ( NET : : OrientationHorizontal , columns , rows , NET : : DesktopLayoutCornerTopLeft ) ;
rootInfo - > activate ( ) ;
2011-05-08 15:14:45 +00:00
_loading_desktop_settings = false ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
void Workspace : : saveDesktopSettings ( )
2011-01-30 14:34:42 +00:00
{
2011-05-08 15:14:45 +00:00
if ( _loading_desktop_settings )
return ;
2007-04-29 17:35:43 +00:00
KSharedConfig : : Ptr c = KGlobal : : config ( ) ;
QString groupname ;
if ( screen_number = = 0 )
groupname = " Desktops " ;
else
2011-01-30 14:34:42 +00:00
groupname . sprintf ( " Desktops-screen-%d " , screen_number ) ;
KConfigGroup group ( c , groupname ) ;
group . writeEntry ( " Number " , numberOfDesktops ( ) ) ;
for ( int i = 1 ; i < = numberOfDesktops ( ) ; i + + ) {
QString s = desktopName ( i ) ;
QString defaultvalue = i18n ( " Desktop %1 " , i ) ;
if ( s . isEmpty ( ) ) {
2007-04-29 17:35:43 +00:00
s = defaultvalue ;
2011-01-30 14:34:42 +00:00
rootInfo - > setDesktopName ( i , s . toUtf8 ( ) . data ( ) ) ;
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
if ( s ! = defaultvalue ) {
group . writeEntry ( QString ( " Name_%1 " ) . arg ( i ) , s ) ;
} else {
QString currentvalue = group . readEntry ( QString ( " Name_%1 " ) . arg ( i ) , QString ( ) ) ;
if ( currentvalue ! = defaultvalue )
group . writeEntry ( QString ( " Name_%1 " ) . arg ( i ) , " " ) ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
}
2008-12-14 11:09:32 +00:00
// Save to disk
group . sync ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
QStringList Workspace : : configModules ( bool controlCenter )
{
2007-04-29 17:35:43 +00:00
QStringList args ;
2007-09-06 20:34:44 +00:00
args < < " kwindecoration " ;
2011-01-30 14:34:42 +00:00
if ( controlCenter )
2007-09-06 20:34:44 +00:00
args < < " kwinoptions " ;
2011-01-30 14:34:42 +00:00
else if ( KAuthorized : : authorizeControlModule ( " kde-kwinoptions.desktop " ) )
2008-12-18 13:50:57 +00:00
args < < " kwinactions " < < " kwinfocus " < < " kwinmoving " < < " kwinadvanced "
2011-06-30 11:02:30 +00:00
< < " kwinrules " < < " kwincompositing "
# ifdef KWIN_BUILD_TABBOX
< < " kwintabbox "
# endif
2011-07-07 16:29:11 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
< < " kwinscreenedges "
2011-12-21 06:28:51 +00:00
# endif
# ifdef KWIN_BUILD_SCRIPTING
< < " kwinscripts "
2011-07-07 16:29:11 +00:00
# endif
;
2007-04-29 17:35:43 +00:00
return args ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
void Workspace : : configureWM ( )
2011-01-30 14:34:42 +00:00
{
2008-12-18 13:50:57 +00:00
QStringList args ;
2011-01-30 14:34:42 +00:00
args < < " --icon " < < " preferences-system-windows " < < configModules ( false ) ;
KToolInvocation : : kdeinitExec ( " kcmshell4 " , args ) ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Avoids managing a window with title \ a title
2007-04-29 17:35:43 +00:00
*/
2011-01-30 14:34:42 +00:00
void Workspace : : doNotManage ( const QString & title )
{
doNotManageList . append ( title ) ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Hack for java applets
2007-04-29 17:35:43 +00:00
*/
2011-01-30 14:34:42 +00:00
bool Workspace : : isNotManaged ( const QString & title )
{
for ( QStringList : : Iterator it = doNotManageList . begin ( ) ; it ! = doNotManageList . end ( ) ; + + it ) {
QRegExp r ( ( * it ) ) ;
if ( r . indexIn ( title ) ! = - 1 ) {
doNotManageList . erase ( it ) ;
2007-04-29 17:35:43 +00:00
return true ;
}
}
2011-01-30 14:34:42 +00:00
return false ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +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
*/
2007-04-29 17:35:43 +00:00
class ObscuringWindows
2011-01-30 14:34:42 +00:00
{
public :
~ ObscuringWindows ( ) ;
void create ( Client * c ) ;
private :
QList < Window > obscuring_windows ;
static QList < Window > * cached ;
static unsigned int max_cache_size ;
} ;
2007-04-29 17:35:43 +00:00
QList < Window > * ObscuringWindows : : cached = 0 ;
unsigned int ObscuringWindows : : max_cache_size = 0 ;
2011-01-30 14:34:42 +00:00
void ObscuringWindows : : create ( Client * c )
{
if ( compositing ( ) )
2008-12-18 13:50:57 +00:00
return ; // Not needed with compositing
2011-01-30 14:34:42 +00:00
if ( cached = = 0 )
2007-04-29 17:35:43 +00:00
cached = new QList < Window > ;
Window obs_win ;
XWindowChanges chngs ;
int mask = CWSibling | CWStackMode ;
2011-01-30 14:34:42 +00:00
if ( cached - > count ( ) > 0 ) {
cached - > removeAll ( obs_win = cached - > first ( ) ) ;
2007-04-29 17:35:43 +00:00
chngs . x = c - > x ( ) ;
chngs . y = c - > y ( ) ;
chngs . width = c - > width ( ) ;
chngs . height = c - > height ( ) ;
mask | = CWX | CWY | CWWidth | CWHeight ;
2011-01-30 14:34:42 +00:00
} else {
2007-04-29 17:35:43 +00:00
XSetWindowAttributes a ;
a . background_pixmap = None ;
a . override_redirect = True ;
2011-01-30 14:34:42 +00:00
obs_win = XCreateWindow ( display ( ) , rootWindow ( ) , c - > x ( ) , c - > y ( ) ,
c - > width ( ) , c - > height ( ) , 0 , CopyFromParent , InputOutput ,
CopyFromParent , CWBackPixmap | CWOverrideRedirect , & a ) ;
}
2007-04-29 17:35:43 +00:00
chngs . sibling = c - > frameId ( ) ;
chngs . stack_mode = Below ;
2011-01-30 14:34:42 +00:00
XConfigureWindow ( display ( ) , obs_win , mask , & chngs ) ;
XMapWindow ( display ( ) , obs_win ) ;
obscuring_windows . append ( obs_win ) ;
}
2007-04-29 17:35:43 +00:00
ObscuringWindows : : ~ ObscuringWindows ( )
2011-01-30 14:34:42 +00:00
{
max_cache_size = qMax ( int ( max_cache_size ) , obscuring_windows . count ( ) + 4 ) - 1 ;
for ( QList < Window > : : ConstIterator it = obscuring_windows . constBegin ( ) ;
it ! = obscuring_windows . constEnd ( ) ;
+ + it ) {
XUnmapWindow ( display ( ) , * it ) ;
if ( cached - > count ( ) < int ( max_cache_size ) )
cached - > prepend ( * it ) ;
2007-04-29 17:35:43 +00:00
else
2011-01-30 14:34:42 +00:00
XDestroyWindow ( display ( ) , * it ) ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Sets the current desktop to \ a new_desktop
*
* Shows / Hides windows according to the stacking order and finally
* propages the new desktop to the world
2007-04-29 17:35:43 +00:00
*/
2011-01-30 14:34:42 +00:00
bool Workspace : : setCurrentDesktop ( int new_desktop )
{
if ( new_desktop < 1 | | new_desktop > numberOfDesktops ( ) )
2007-04-29 17:35:43 +00:00
return false ;
closeActivePopup ( ) ;
+ + block_focus ;
2008-12-18 13:50:57 +00:00
// TODO: Q_ASSERT( block_stacking_updates == 0 ); // Make sure stacking_order is up to date
2011-01-30 14:34:42 +00:00
StackingUpdatesBlocker blocker ( this ) ;
2007-04-29 17:35:43 +00:00
2009-02-14 09:46:12 +00:00
int old_desktop = currentDesktop ( ) ;
2011-09-30 17:24:00 +00:00
int old_active_screen = activeScreen ( ) ;
2011-01-30 14:34:42 +00:00
if ( new_desktop ! = currentDesktop ( ) ) {
2007-04-29 17:35:43 +00:00
+ + block_showing_desktop ;
2008-12-18 13:50:57 +00:00
// Optimized Desktop switching: unmapping done from back to front
// mapping done from front to back => less exposure events
2011-01-30 14:34:42 +00:00
Notify : : raise ( ( Notify : : Event ) ( Notify : : DesktopChange + new_desktop ) ) ;
2007-04-29 17:35:43 +00:00
ObscuringWindows obs_wins ;
2009-02-14 15:40:52 +00:00
currentDesktop_ = new_desktop ; // Change the desktop (so that Client::updateVisibility() works)
2007-04-29 17:35:43 +00:00
2012-04-08 08:07:35 +00:00
for ( ToplevelList : : ConstIterator it = stacking_order . constBegin ( ) ;
2011-01-30 14:34:42 +00:00
it ! = stacking_order . constEnd ( ) ;
2012-04-08 08:07:35 +00:00
+ + it ) {
Client * c = qobject_cast < Client * > ( * it ) ;
if ( ! c ) {
continue ;
2011-01-30 14:34:42 +00:00
}
2012-04-08 08:07:35 +00:00
if ( ! c - > isOnDesktop ( new_desktop ) & & c ! = movingClient & & c - > isOnCurrentActivity ( ) ) {
if ( c - > isShown ( true ) & & c - > isOnDesktop ( old_desktop ) )
obs_wins . create ( c ) ;
( c ) - > updateVisibility ( ) ;
}
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
// Now propagate the change, after hiding, before showing
2011-01-30 14:34:42 +00:00
rootInfo - > setCurrentDesktop ( currentDesktop ( ) ) ;
2007-04-29 17:35:43 +00:00
2010-05-09 06:15:40 +00:00
// if the client is moved to another desktop, that desktop may
// not have an existing layout. In addition this tiling layout
// will require rearrangement, so notify about desktop changes.
2011-01-30 14:34:42 +00:00
if ( movingClient & & ! movingClient - > isOnDesktop ( new_desktop ) ) {
2010-04-25 16:43:14 +00:00
int old_desktop = movingClient - > desktop ( ) ;
2011-01-30 14:34:42 +00:00
movingClient - > setDesktop ( new_desktop ) ;
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-28 11:48:57 +00:00
if ( m_tiling - > isEnabled ( ) ) {
2011-07-13 16:48:56 +00:00
m_tiling - > notifyTilingWindowDesktopChanged ( movingClient , old_desktop ) ;
2010-04-25 16:43:14 +00:00
}
2011-07-20 11:25:00 +00:00
# else
Q_UNUSED ( old_desktop )
# endif
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2012-04-08 08:07:35 +00:00
for ( int i = stacking_order . size ( ) - 1 ; i > = 0 ; - - i ) {
Client * c = qobject_cast < Client * > ( stacking_order . at ( i ) ) ;
if ( ! c ) {
continue ;
}
if ( c - > isOnDesktop ( new_desktop ) & & c - > isOnCurrentActivity ( ) )
c - > updateVisibility ( ) ;
}
2007-04-29 17:35:43 +00:00
- - block_showing_desktop ;
2011-01-30 14:34:42 +00:00
if ( showingDesktop ( ) ) // Do this only after desktop change to avoid flicker
resetShowingDesktop ( false ) ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
// Restore the focus on this desktop
2007-04-29 17:35:43 +00:00
- - block_focus ;
Client * c = 0 ;
2011-01-30 14:34:42 +00:00
if ( options - > focusPolicyIsReasonable ( ) ) {
// Search in focus chain
if ( movingClient ! = NULL & & active_client = = movingClient & &
focus_chain [ currentDesktop ( ) ] . contains ( active_client ) & &
active_client - > isShown ( true ) & & active_client - > isOnCurrentDesktop ( ) )
2008-12-18 13:50:57 +00:00
c = active_client ; // The requestFocus below will fail, as the client is already active
2011-08-22 11:53:03 +00:00
// from actiavtion.cpp
2012-02-20 09:25:13 +00:00
if ( ! c & & options - > isNextFocusPrefersMouse ( ) ) {
2012-04-08 08:07:35 +00:00
ToplevelList : : const_iterator it = stackingOrder ( ) . constEnd ( ) ;
2011-08-22 11:53:03 +00:00
while ( it ! = stackingOrder ( ) . constBegin ( ) ) {
2012-04-08 08:07:35 +00:00
Client * client = qobject_cast < Client * > ( * ( - - it ) ) ;
if ( ! client ) {
continue ;
}
2011-08-22 11:53:03 +00:00
if ( ! ( client - > isShown ( false ) & & client - > isOnDesktop ( new_desktop ) & &
client - > isOnCurrentActivity ( ) & & client - > isOnScreen ( activeScreen ( ) ) ) )
continue ;
if ( client - > geometry ( ) . contains ( QCursor : : pos ( ) ) ) {
if ( ! client - > isDesktop ( ) )
c = client ;
break ; // unconditional break - we do not pass the focus to some client below an unusable one
}
}
}
2011-01-30 14:34:42 +00:00
if ( ! c ) {
for ( int i = focus_chain [ currentDesktop ( ) ] . size ( ) - 1 ; i > = 0 ; - - i ) {
2011-09-30 17:24:00 +00:00
Client * tmp = focus_chain [ currentDesktop ( ) ] . at ( i ) ;
if ( tmp - > isShown ( false ) & & tmp - > isOnCurrentActivity ( )
2012-02-20 09:25:13 +00:00
& & ( ! options - > isSeparateScreenFocus ( ) | | tmp - > screen ( ) = = old_active_screen ) ) {
2011-09-30 17:24:00 +00:00
c = tmp ;
2007-04-29 17:35:43 +00:00
break ;
}
}
}
2011-01-30 14:34:42 +00:00
}
2008-12-18 13:50:57 +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>)
2011-01-30 14:34:42 +00:00
else if ( active_client & & active_client - > isShown ( true ) & & active_client - > isOnCurrentDesktop ( ) )
2008-12-18 13:50:57 +00:00
c = active_client ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
if ( c = = NULL & & ! desktops . isEmpty ( ) )
c = findDesktop ( true , currentDesktop ( ) ) ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
if ( c ! = active_client )
setActiveClient ( NULL , Allowed ) ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
if ( c )
requestFocus ( c ) ;
else if ( ! desktops . isEmpty ( ) )
requestFocus ( findDesktop ( true , currentDesktop ( ) ) ) ;
2007-04-29 17:35:43 +00:00
else
focusToNull ( ) ;
// Update focus chain:
// If input: chain = { 1, 2, 3, 4 } and currentDesktop() = 3,
// Output: chain = { 3, 1, 2, 4 }.
2008-12-18 13:50:57 +00:00
//kDebug(1212) << QString("Switching to desktop #%1, at focus_chain index %2\n")
// .arg(currentDesktop()).arg(desktop_focus_chain.find( currentDesktop() ));
2012-05-01 16:34:38 +00:00
QVector < int > & chain = m_desktopFocusChain . value ( ) ;
for ( int i = chain . indexOf ( currentDesktop ( ) ) ; i > 0 ; - - i )
chain [ i ] = chain [ i - 1 ] ;
chain [ 0 ] = currentDesktop ( ) ;
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
//QString s = "desktop_focus_chain[] = { ";
2011-01-30 14:34:42 +00:00
//for ( uint i = 0; i < desktop_focus_chain.size(); i++ )
2008-12-18 13:50:57 +00:00
// s += QString::number( desktop_focus_chain[i] ) + ", ";
//kDebug( 1212 ) << s << "}\n";
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
if ( compositing ( ) )
2007-04-29 17:35:43 +00:00
addRepaintFull ( ) ;
2011-01-30 14:34:42 +00:00
2012-05-02 19:16:16 +00:00
emit currentDesktopChanged ( old_desktop , movingClient ) ;
2007-04-29 17:35:43 +00:00
return true ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2012-04-29 15:32:34 +00:00
int Workspace : : maxNumberOfDesktops ( ) const
{
return KWIN_MAX_NUMBER_DESKTOPS ;
}
2012-04-12 19:52:44 +00:00
# ifdef KWIN_BUILD_ACTIVITIES
//BEGIN threaded activity list fetching
typedef QPair < QStringList * , QStringList > AssignedList ;
typedef QPair < QString , QStringList > CurrentAndList ;
static AssignedList
fetchActivityList ( KActivities : : Controller * controller , QStringList * target , bool running ) // could be member function, but actually it's much simpler this way
{
return AssignedList ( target , running ? controller - > listActivities ( KActivities : : Info : : Running ) :
controller - > listActivities ( ) ) ;
}
static CurrentAndList
fetchActivityListAndCurrent ( KActivities : : Controller * controller )
{
QStringList l = controller - > listActivities ( ) ;
QString c = controller - > currentActivity ( ) ;
return CurrentAndList ( c , l ) ;
}
void Workspace : : updateActivityList ( bool running , bool updateCurrent , QString slot )
{
if ( updateCurrent ) {
QFutureWatcher < CurrentAndList > * watcher = new QFutureWatcher < CurrentAndList > ;
connect ( watcher , SIGNAL ( finished ( ) ) , SLOT ( handleActivityReply ( ) ) ) ;
if ( ! slot . isEmpty ( ) )
watcher - > setProperty ( " activityControllerCallback " , slot ) ; // "activity reply trigger"
watcher - > setFuture ( QtConcurrent : : run ( fetchActivityListAndCurrent , & activityController_ ) ) ;
} else {
QFutureWatcher < AssignedList > * watcher = new QFutureWatcher < AssignedList > ;
connect ( watcher , SIGNAL ( finished ( ) ) , SLOT ( handleActivityReply ( ) ) ) ;
if ( ! slot . isEmpty ( ) )
watcher - > setProperty ( " activityControllerCallback " , slot ) ; // "activity reply trigger"
QStringList * target = running ? & openActivities_ : & allActivities_ ;
watcher - > setFuture ( QtConcurrent : : run ( fetchActivityList , & activityController_ , target , running ) ) ;
}
}
void Workspace : : handleActivityReply ( )
{
QObject * watcherObject = 0 ;
if ( QFutureWatcher < AssignedList > * watcher = dynamic_cast < QFutureWatcher < AssignedList > * > ( sender ( ) ) ) {
* ( watcher - > result ( ) . first ) = watcher - > result ( ) . second ; // cool trick, ehh? :-)
watcherObject = watcher ;
}
if ( ! watcherObject ) {
if ( QFutureWatcher < CurrentAndList > * watcher = dynamic_cast < QFutureWatcher < CurrentAndList > * > ( sender ( ) ) ) {
allActivities_ = watcher - > result ( ) . second ;
updateCurrentActivity ( watcher - > result ( ) . first ) ;
watcherObject = watcher ;
}
}
if ( watcherObject ) {
QString slot = watcherObject - > property ( " activityControllerCallback " ) . toString ( ) ;
watcherObject - > deleteLater ( ) ; // has done it's job
if ( ! slot . isEmpty ( ) )
QMetaObject : : invokeMethod ( this , slot . toAscii ( ) . data ( ) , Qt : : DirectConnection ) ;
}
}
//END threaded activity list fetching
# else // make gcc happy - stupd moc cannot handle preproc defs so we MUST define
void Workspace : : handleActivityReply ( ) { }
# endif // KWIN_BUILD_ACTIVITIES
2010-05-11 20:30:20 +00:00
/**
* Updates the current activity when it changes
* do * not * call this directly ; it does not set the activity .
*
* Shows / Hides windows according to the stacking order
*/
2012-04-12 19:52:44 +00:00
2010-05-11 20:30:20 +00:00
void Workspace : : updateCurrentActivity ( const QString & new_activity )
2011-01-30 14:34:42 +00:00
{
2010-05-11 20:30:20 +00:00
//closeActivePopup();
+ + block_focus ;
// TODO: Q_ASSERT( block_stacking_updates == 0 ); // Make sure stacking_order is up to date
2011-01-30 14:34:42 +00:00
StackingUpdatesBlocker blocker ( this ) ;
2010-05-11 20:30:20 +00:00
2011-01-30 14:34:42 +00:00
if ( new_activity ! = activity_ ) {
2010-05-11 20:30:20 +00:00
+ + block_showing_desktop ; //FIXME should I be using that?
// 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));
ObscuringWindows obs_wins ;
QString old_activity = activity_ ;
activity_ = new_activity ;
2012-04-08 08:07:35 +00:00
for ( ToplevelList : : ConstIterator it = stacking_order . constBegin ( ) ;
2011-01-30 14:34:42 +00:00
it ! = stacking_order . constEnd ( ) ;
2012-04-08 08:07:35 +00:00
+ + it ) {
Client * c = qobject_cast < Client * > ( * it ) ;
if ( ! c ) {
continue ;
}
if ( ! c - > isOnActivity ( new_activity ) & & c ! = movingClient & & c - > isOnCurrentDesktop ( ) ) {
if ( c - > isShown ( true ) & & c - > isOnActivity ( old_activity ) )
obs_wins . create ( c ) ;
c - > updateVisibility ( ) ;
2011-01-30 14:34:42 +00:00
}
2012-04-08 08:07:35 +00:00
}
2010-05-11 20:30:20 +00:00
// Now propagate the change, after hiding, before showing
//rootInfo->setCurrentDesktop( currentDesktop() );
/* TODO someday enable dragging windows to other activities
2011-01-30 14:34:42 +00:00
if ( movingClient & & ! movingClient - > isOnDesktop ( new_desktop ) )
2010-05-11 20:30:20 +00:00
{
int old_desktop = movingClient - > desktop ( ) ;
movingClient - > setDesktop ( new_desktop ) ;
2011-01-30 14:34:42 +00:00
if ( tilingEnabled ( ) )
2010-05-11 20:30:20 +00:00
{
notifyWindowDesktopChanged ( movingClient , old_desktop ) ;
}
}
*/
2012-04-08 08:07:35 +00:00
for ( int i = stacking_order . size ( ) - 1 ; i > = 0 ; - - i ) {
Client * c = qobject_cast < Client * > ( stacking_order . at ( i ) ) ;
if ( ! c ) {
continue ;
}
if ( c - > isOnActivity ( new_activity ) )
c - > updateVisibility ( ) ;
}
2010-05-11 20:30:20 +00:00
- - block_showing_desktop ;
//FIXME not sure if I should do this either
2011-01-30 14:34:42 +00:00
if ( showingDesktop ( ) ) // Do this only after desktop change to avoid flicker
resetShowingDesktop ( false ) ;
}
2010-05-11 20:30:20 +00:00
// Restore the focus on this desktop
- - block_focus ;
Client * c = 0 ;
//FIXME below here is a lot of focuschain stuff, probably all wrong now
2011-01-30 14:34:42 +00:00
if ( options - > focusPolicyIsReasonable ( ) ) {
// Search in focus chain
if ( movingClient ! = NULL & & active_client = = movingClient & &
focus_chain [ currentDesktop ( ) ] . contains ( active_client ) & &
active_client - > isShown ( true ) & & active_client - > isOnCurrentDesktop ( ) )
2010-05-11 20:30:20 +00:00
c = active_client ; // The requestFocus below will fail, as the client is already active
2011-01-30 14:34:42 +00:00
if ( ! c ) {
for ( int i = focus_chain [ currentDesktop ( ) ] . size ( ) - 1 ; i > = 0 ; - - i ) {
if ( focus_chain [ currentDesktop ( ) ] . at ( i ) - > isShown ( false ) & &
focus_chain [ currentDesktop ( ) ] . at ( i ) - > isOnCurrentActivity ( ) ) {
c = focus_chain [ currentDesktop ( ) ] . at ( i ) ;
2010-05-11 20:30:20 +00:00
break ;
}
}
}
2011-01-30 14:34:42 +00:00
}
2010-05-11 20:30:20 +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>)
2011-01-30 14:34:42 +00:00
else if ( active_client & & active_client - > isShown ( true ) & & active_client - > isOnCurrentDesktop ( ) & & active_client - > isOnCurrentActivity ( ) )
2010-05-11 20:30:20 +00:00
c = active_client ;
2011-01-30 14:34:42 +00:00
if ( c = = NULL & & ! desktops . isEmpty ( ) )
c = findDesktop ( true , currentDesktop ( ) ) ;
2010-05-11 20:30:20 +00:00
2011-01-30 14:34:42 +00:00
if ( c ! = active_client )
setActiveClient ( NULL , Allowed ) ;
2010-05-11 20:30:20 +00:00
2011-01-30 14:34:42 +00:00
if ( c )
requestFocus ( c ) ;
else if ( ! desktops . isEmpty ( ) )
requestFocus ( findDesktop ( true , currentDesktop ( ) ) ) ;
2010-05-11 20:30:20 +00:00
else
focusToNull ( ) ;
// Update focus chain:
2012-05-01 16:34:38 +00:00
# ifdef KWIN_BUILD_ACTIVITIES
// Replace initial dummy with actual activity, preserving the current chain.
if ( m_desktopFocusChain . key ( ) . isNull ( ) ) {
QVector < int > val ( m_desktopFocusChain . value ( ) ) ;
m_activitiesDesktopFocusChain . erase ( m_desktopFocusChain ) ;
m_desktopFocusChain = m_activitiesDesktopFocusChain . insert ( activity_ , val ) ;
} else {
m_desktopFocusChain = m_activitiesDesktopFocusChain . find ( activity_ ) ;
if ( m_desktopFocusChain = = m_activitiesDesktopFocusChain . end ( ) ) {
m_desktopFocusChain = m_activitiesDesktopFocusChain . insert ( activity_ , QVector < int > ( numberOfDesktops ( ) ) ) ;
2010-05-11 20:30:20 +00:00
2012-05-01 16:34:38 +00:00
for ( int i = 0 ; i < numberOfDesktops ( ) ; + + i ) {
m_desktopFocusChain . value ( ) [ i ] = i + 1 ;
}
}
}
# endif
2010-05-11 20:30:20 +00:00
// Not for the very first time, only if something changed and there are more than 1 desktops
2011-01-30 14:34:42 +00:00
//if ( effects != NULL && old_desktop != 0 && old_desktop != new_desktop )
2010-05-11 20:30:20 +00:00
// static_cast<EffectsHandlerImpl*>( effects )->desktopChanged( old_desktop );
2011-01-30 14:34:42 +00:00
if ( compositing ( ) )
2010-05-11 20:30:20 +00:00
addRepaintFull ( ) ;
2011-01-30 14:34:42 +00:00
}
2010-05-11 20:30:20 +00:00
2010-05-13 04:06:27 +00:00
/**
* updates clients when an activity is destroyed .
* this ensures that a client does not get ' lost ' if the only activity it ' s on is removed .
*/
2012-06-21 18:37:23 +00:00
void Workspace : : slotActivityRemoved ( const QString & activity )
2011-01-30 14:34:42 +00:00
{
2010-09-24 12:03:22 +00:00
allActivities_ . removeOne ( activity ) ;
2012-04-08 08:07:35 +00:00
foreach ( Toplevel * toplevel , stacking_order ) {
if ( Client * client = qobject_cast < Client * > ( toplevel ) ) {
client - > setOnActivity ( activity , false ) ;
}
2011-01-30 14:34:42 +00:00
}
2010-11-01 19:53:20 +00:00
//toss out any session data for it
KConfigGroup cg ( KGlobal : : config ( ) , QString ( " SubSession: " ) + activity ) ;
cg . deleteGroup ( ) ;
2011-01-30 14:34:42 +00:00
}
2010-05-13 04:06:27 +00:00
2012-06-21 18:37:23 +00:00
void Workspace : : slotActivityAdded ( const QString & activity )
2011-01-30 14:34:42 +00:00
{
2010-09-24 12:03:22 +00:00
allActivities_ < < activity ;
2011-01-30 14:34:42 +00:00
}
2010-09-24 12:03:22 +00:00
2008-12-18 13:50:57 +00:00
/**
* Called only from D - Bus
*/
2007-04-29 17:35:43 +00:00
void Workspace : : nextDesktop ( )
2011-01-30 14:34:42 +00:00
{
2007-04-29 17:35:43 +00:00
int desktop = currentDesktop ( ) + 1 ;
2011-01-30 14:34:42 +00:00
setCurrentDesktop ( desktop > numberOfDesktops ( ) ? 1 : desktop ) ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Called only from D - Bus
*/
2007-04-29 17:35:43 +00:00
void Workspace : : previousDesktop ( )
2011-01-30 14:34:42 +00:00
{
2007-04-29 17:35:43 +00:00
int desktop = currentDesktop ( ) - 1 ;
2011-01-30 14:34:42 +00:00
setCurrentDesktop ( desktop > 0 ? desktop : numberOfDesktops ( ) ) ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Sets the number of virtual desktops to \ a n
2007-04-29 17:35:43 +00:00
*/
2011-01-30 14:34:42 +00:00
void Workspace : : setNumberOfDesktops ( int n )
{
if ( n > KWIN_MAX_NUMBER_DESKTOPS )
2011-01-13 19:05:28 +00:00
n = KWIN_MAX_NUMBER_DESKTOPS ;
2011-01-30 14:34:42 +00:00
if ( n < 1 | | n = = numberOfDesktops ( ) )
2007-04-29 17:35:43 +00:00
return ;
2009-02-14 09:46:12 +00:00
int old_number_of_desktops = numberOfDesktops ( ) ;
2009-02-14 15:40:52 +00:00
desktopCount_ = n ;
2012-05-26 19:06:40 +00:00
initPositioning - > reinitCascading ( 0 ) ;
2009-02-14 15:40:52 +00:00
updateDesktopLayout ( ) ; // Make sure the layout is still valid
2007-04-29 17:35:43 +00:00
2011-03-07 17:41:17 +00:00
if ( currentDesktop ( ) > n )
setCurrentDesktop ( n ) ;
2007-04-29 17:35:43 +00:00
2011-03-07 17:41:17 +00:00
// move all windows that would be hidden to the last visible desktop
2011-01-30 14:34:42 +00:00
if ( old_number_of_desktops > numberOfDesktops ( ) ) {
2011-03-07 17:41:17 +00:00
for ( ClientList : : ConstIterator it = clients . constBegin ( ) ; it ! = clients . constEnd ( ) ; + + it ) {
2011-01-30 14:34:42 +00:00
if ( ! ( * it ) - > isOnAllDesktops ( ) & & ( * it ) - > desktop ( ) > numberOfDesktops ( ) )
sendClientToDesktop ( * it , numberOfDesktops ( ) , true ) ;
2011-03-07 17:41:17 +00:00
// TODO: Tile should have a method allClients, push them into other tiles
}
2011-01-30 14:34:42 +00:00
}
2011-03-07 17:41:17 +00:00
rootInfo - > setNumberOfDesktops ( n ) ;
NETPoint * viewports = new NETPoint [ n ] ;
rootInfo - > setDesktopViewport ( n , * viewports ) ;
delete [ ] viewports ;
2007-04-29 17:35:43 +00:00
2011-03-07 17:41:17 +00:00
// Make it +1, so that it can be accessed as [1..numberofdesktops]
focus_chain . resize ( n + 1 ) ;
workarea . clear ( ) ;
workarea . resize ( n + 1 ) ;
restrictedmovearea . clear ( ) ;
restrictedmovearea . resize ( n + 1 ) ;
screenarea . clear ( ) ;
2007-04-29 17:35:43 +00:00
2011-04-14 15:39:16 +00:00
updateClientArea ( true ) ;
2012-05-01 16:34:38 +00:00
// Resize the desktop focus chain.
for ( DesktopFocusChains : : iterator it = m_activitiesDesktopFocusChain . begin ( ) , end = m_activitiesDesktopFocusChain . end ( ) ; it ! = end ; + + it ) {
QVector < int > & chain = it . value ( ) ;
chain . resize ( n ) ;
// We do not destroy the chain in case new desktops are added;
if ( n > = old_number_of_desktops ) {
for ( int i = old_number_of_desktops ; i < n ; + + i )
chain [ i ] = i + 1 ;
// But when desktops are removed, we may have to modify the chain a bit,
// otherwise invalid desktops may show up.
} else {
for ( int i = 0 ; i < chain . size ( ) ; + + i )
chain [ i ] = qMin ( chain [ i ] , n ) ;
}
}
2009-04-06 16:09:34 +00:00
2011-03-07 17:41:17 +00:00
saveDesktopSettings ( ) ;
2011-03-06 19:10:11 +00:00
emit numberDesktopsChanged ( old_number_of_desktops ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Sends client \ a c to desktop \ a desk .
*
* Takes care of transients as well .
2007-04-29 17:35:43 +00:00
*/
2011-01-30 14:34:42 +00:00
void Workspace : : sendClientToDesktop ( Client * c , int desk , bool dont_activate )
{
2011-05-27 14:47:45 +00:00
if ( ( desk < 1 & & desk ! = NET : : OnAllDesktops ) | | desk > numberOfDesktops ( ) )
2011-02-16 18:23:54 +00:00
return ;
2010-04-25 16:43:14 +00:00
int old_desktop = c - > desktop ( ) ;
2011-01-30 14:34:42 +00:00
bool was_on_desktop = c - > isOnDesktop ( desk ) | | c - > isOnAllDesktops ( ) ;
c - > setDesktop ( desk ) ;
if ( c - > desktop ( ) ! = desk ) // No change or desktop forced
2007-04-29 17:35:43 +00:00
return ;
desk = c - > desktop ( ) ; // Client did range checking
2011-01-30 14:34:42 +00:00
2010-09-21 14:31:40 +00:00
emit desktopPresenceChanged ( c , old_desktop ) ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
if ( c - > isOnDesktop ( currentDesktop ( ) ) ) {
if ( c - > wantsTabFocus ( ) & & options - > focusPolicyIsReasonable ( ) & &
! was_on_desktop & & // for stickyness changes
! dont_activate )
requestFocus ( c ) ;
2007-04-29 17:35:43 +00:00
else
2011-01-30 14:34:42 +00:00
restackClientUnderActive ( c ) ;
} else
raiseClient ( c ) ;
2007-04-29 17:35:43 +00:00
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-13 16:48:56 +00:00
m_tiling - > notifyTilingWindowDesktopChanged ( c , old_desktop ) ;
2011-07-20 11:25:00 +00:00
# endif
2011-09-29 15:52:19 +00:00
c - > checkWorkspacePosition ( QRect ( ) , old_desktop ) ;
2010-04-25 16:43:14 +00:00
2011-01-30 14:34:42 +00:00
ClientList transients_stacking_order = ensureStackingOrder ( c - > transients ( ) ) ;
for ( ClientList : : ConstIterator it = transients_stacking_order . constBegin ( ) ;
it ! = transients_stacking_order . constEnd ( ) ;
+ + it )
sendClientToDesktop ( * it , desk , dont_activate ) ;
2007-04-29 17:35:43 +00:00
updateClientArea ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2010-05-11 20:30:20 +00:00
/**
2010-05-19 21:02:40 +00:00
* Adds / removes client \ a c to / from \ a activity .
2010-05-11 20:30:20 +00:00
*
* Takes care of transients as well .
*/
2011-01-30 14:34:42 +00:00
void Workspace : : toggleClientOnActivity ( Client * c , const QString & activity , bool dont_activate )
{
2010-05-11 20:30:20 +00:00
//int old_desktop = c->desktop();
bool was_on_activity = c - > isOnActivity ( activity ) ;
bool was_on_all = c - > isOnAllActivities ( ) ;
//note: all activities === no activities
bool enable = was_on_all | | ! was_on_activity ;
2011-01-30 14:34:42 +00:00
c - > setOnActivity ( activity , enable ) ;
if ( c - > isOnActivity ( activity ) = = was_on_activity & & c - > isOnAllActivities ( ) = = was_on_all ) // No change
2010-05-11 20:30:20 +00:00
return ;
2011-01-30 14:34:42 +00:00
if ( c - > isOnCurrentActivity ( ) ) {
if ( c - > wantsTabFocus ( ) & & options - > focusPolicyIsReasonable ( ) & &
! was_on_activity & & // for stickyness changes
//FIXME not sure if the line above refers to the correct activity
! dont_activate )
requestFocus ( c ) ;
2010-05-11 20:30:20 +00:00
else
2011-01-30 14:34:42 +00:00
restackClientUnderActive ( c ) ;
} else
raiseClient ( c ) ;
2010-05-11 20:30:20 +00:00
//notifyWindowDesktopChanged( c, old_desktop );
//FIXME does tiling break?
2011-01-30 14:34:42 +00:00
ClientList transients_stacking_order = ensureStackingOrder ( c - > transients ( ) ) ;
for ( ClientList : : ConstIterator it = transients_stacking_order . constBegin ( ) ;
it ! = transients_stacking_order . constEnd ( ) ;
+ + it )
toggleClientOnActivity ( * it , activity , dont_activate ) ;
2010-05-11 20:30:20 +00:00
updateClientArea ( ) ;
2011-01-30 14:34:42 +00:00
}
2010-05-11 20:30:20 +00:00
2007-05-07 12:18:19 +00:00
int Workspace : : numScreens ( ) const
2011-01-30 14:34:42 +00:00
{
2012-03-27 17:14:53 +00:00
return QApplication : : desktop ( ) - > screenCount ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-05-07 12:18:19 +00:00
2009-02-21 08:33:13 +00:00
int Workspace : : activeScreen ( ) const
2011-01-30 14:34:42 +00:00
{
2012-02-20 09:25:13 +00:00
if ( ! options - > isActiveMouseScreen ( ) ) {
2011-01-30 14:34:42 +00:00
if ( activeClient ( ) ! = NULL & & ! activeClient ( ) - > isOnScreen ( active_screen ) )
2009-02-18 04:05:37 +00:00
return activeClient ( ) - > screen ( ) ;
return active_screen ;
2007-05-07 12:18:19 +00:00
}
2012-03-27 17:14:53 +00:00
return QApplication : : desktop ( ) - > screenNumber ( cursorPos ( ) ) ;
2011-01-30 14:34:42 +00:00
}
2007-05-07 12:18:19 +00:00
2008-12-18 13:50:57 +00:00
/**
* Check whether a client moved completely out of what ' s considered the active screen ,
* if yes , set a new active screen .
*/
2011-01-30 14:34:42 +00:00
void Workspace : : checkActiveScreen ( const Client * c )
{
if ( ! c - > isActive ( ) )
2007-05-09 12:26:32 +00:00
return ;
2011-01-30 14:34:42 +00:00
if ( ! c - > isOnScreen ( active_screen ) )
2007-05-09 12:26:32 +00:00
active_screen = c - > screen ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-05-09 12:26:32 +00:00
2008-12-18 13:50:57 +00:00
/**
* Called e . g . when a user clicks on a window , set active screen to be the screen
* where the click occurred
*/
2011-01-30 14:34:42 +00:00
void Workspace : : setActiveScreenMouse ( const QPoint & mousepos )
{
2012-03-27 17:14:53 +00:00
active_screen = QApplication : : desktop ( ) - > screenNumber ( mousepos ) ;
2011-01-30 14:34:42 +00:00
}
2007-05-09 12:30:29 +00:00
2011-01-30 14:34:42 +00:00
QRect Workspace : : screenGeometry ( int screen ) const
{
2012-03-27 17:14:53 +00:00
return QApplication : : desktop ( ) - > screenGeometry ( screen ) ;
2011-01-30 14:34:42 +00:00
}
2007-05-07 12:18:19 +00:00
2011-01-30 14:34:42 +00:00
int Workspace : : screenNumber ( const QPoint & pos ) const
{
2012-03-27 17:14:53 +00:00
return QApplication : : desktop ( ) - > screenNumber ( pos ) ;
2011-01-30 14:34:42 +00:00
}
2007-05-07 12:18:19 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : sendClientToScreen ( Client * c , int screen )
{
if ( c - > screen ( ) = = screen ) // Don't use isOnScreen(), that's true even when only partially
2007-05-07 13:13:48 +00:00
return ;
2011-01-30 14:34:42 +00:00
GeometryUpdatesBlocker blocker ( c ) ;
QRect old_sarea = clientArea ( MaximizeArea , c ) ;
QRect sarea = clientArea ( MaximizeArea , screen , c - > desktop ( ) ) ;
2011-09-29 15:52:19 +00:00
QRect oldgeom = c - > geometry ( ) ;
2011-09-30 14:37:42 +00:00
QRect geom = c - > geometry ( ) ;
// move the window to have the same relative position to the center of the screen
// (i.e. one near the middle of the right edge will also end up near the middle of the right edge)
geom . moveCenter (
QPoint ( ( geom . center ( ) . x ( ) - old_sarea . center ( ) . x ( ) ) * sarea . width ( ) / old_sarea . width ( ) + sarea . center ( ) . x ( ) ,
( geom . center ( ) . y ( ) - old_sarea . center ( ) . y ( ) ) * sarea . height ( ) / old_sarea . height ( ) + sarea . center ( ) . y ( ) ) ) ;
c - > setGeometry ( geom ) ;
2011-10-04 09:40:16 +00:00
// If the window was inside the old screen area, explicitly make sure its inside also the new screen area.
// Calling checkWorkspacePosition() should ensure that, but when moving to a small screen the window could
// be big enough to overlap outside of the new screen area, making struts from other screens come into effect,
// which could alter the resulting geometry.
if ( old_sarea . contains ( oldgeom ) )
c - > keepInArea ( sarea ) ;
2011-09-29 15:52:19 +00:00
c - > checkWorkspacePosition ( oldgeom ) ;
2011-01-30 14:34:42 +00:00
ClientList transients_stacking_order = ensureStackingOrder ( c - > transients ( ) ) ;
for ( ClientList : : ConstIterator it = transients_stacking_order . constBegin ( ) ;
it ! = transients_stacking_order . constEnd ( ) ;
+ + it )
sendClientToScreen ( * it , screen ) ;
if ( c - > isActive ( ) )
2007-05-09 12:26:32 +00:00
active_screen = screen ;
2011-01-30 14:34:42 +00:00
}
2007-05-07 13:13:48 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : killWindowId ( Window window_to_kill )
{
if ( window_to_kill = = None )
2007-04-29 17:35:43 +00:00
return ;
Window window = window_to_kill ;
Client * client = NULL ;
2011-01-30 14:34:42 +00:00
for ( ; ; ) {
client = findClient ( FrameIdMatchPredicate ( window ) ) ;
if ( client ! = NULL )
2008-12-18 13:50:57 +00:00
break ; // Found the client
2007-04-29 17:35:43 +00:00
Window parent , root ;
Window * children ;
unsigned int children_count ;
2011-01-30 14:34:42 +00:00
XQueryTree ( display ( ) , window , & root , & parent , & children , & children_count ) ;
if ( children ! = NULL )
XFree ( children ) ;
if ( window = = root ) // We didn't find the client, probably an override-redirect window
2007-04-29 17:35:43 +00:00
break ;
2008-12-18 13:50:57 +00:00
window = parent ; // Go up
2011-01-30 14:34:42 +00:00
}
if ( client ! = NULL )
2007-04-29 17:35:43 +00:00
client - > killWindow ( ) ;
else
2011-01-30 14:34:42 +00:00
XKillClient ( display ( ) , window_to_kill ) ;
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : sendPingToWindow ( Window window , Time timestamp )
{
rootInfo - > sendPing ( window , timestamp ) ;
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : sendTakeActivity ( Client * c , Time timestamp , long flags )
{
rootInfo - > takeActivity ( c - > window ( ) , timestamp , flags ) ;
2007-04-29 17:35:43 +00:00
pending_take_activity = c ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Delayed focus functions
*/
2007-04-29 17:35:43 +00:00
void Workspace : : delayFocus ( )
2011-01-30 14:34:42 +00:00
{
requestFocus ( delayfocus_client ) ;
2007-04-29 17:35:43 +00:00
cancelDelayFocus ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : requestDelayFocus ( Client * c )
{
2011-12-06 13:22:21 +00:00
delayfocus_client = c ;
delete delayFocusTimer ;
2011-01-30 14:34:42 +00:00
delayFocusTimer = new QTimer ( this ) ;
connect ( delayFocusTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( delayFocus ( ) ) ) ;
delayFocusTimer - > setSingleShot ( true ) ;
2012-02-20 09:25:13 +00:00
delayFocusTimer - > start ( options - > delayFocusInterval ( ) ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
void Workspace : : cancelDelayFocus ( )
2011-01-30 14:34:42 +00:00
{
2007-04-29 17:35:43 +00:00
delete delayFocusTimer ;
delayFocusTimer = 0 ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
KDecoration * Workspace : : createDecoration ( KDecorationBridge * bridge )
{
2011-04-28 13:56:50 +00:00
if ( ! hasDecorationPlugin ( ) ) {
return NULL ;
}
2011-01-30 14:34:42 +00:00
return mgr - > createDecoration ( bridge ) ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Returns a list of all colors ( KDecorationDefines : : ColorType ) the current
* decoration supports
*/
QList < int > Workspace : : decorationSupportedColors ( ) const
2011-01-30 14:34:42 +00:00
{
2008-12-18 13:50:57 +00:00
QList < int > ret ;
2011-04-28 13:56:50 +00:00
if ( ! hasDecorationPlugin ( ) ) {
return ret ;
}
KDecorationFactory * factory = mgr - > factory ( ) ;
2011-01-30 14:34:42 +00:00
for ( Ability ab = ABILITYCOLOR_FIRST ;
ab < ABILITYCOLOR_END ;
ab = static_cast < Ability > ( ab + 1 ) )
if ( factory - > supports ( ab ) )
2008-03-21 22:17:10 +00:00
ret < < ab ;
return ret ;
2011-01-30 14:34:42 +00:00
}
2008-03-21 22:17:10 +00:00
2011-01-30 14:34:42 +00:00
QString Workspace : : desktopName ( int desk ) const
{
return QString : : fromUtf8 ( rootInfo - > desktopName ( desk ) ) ;
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
bool Workspace : : checkStartupNotification ( Window w , KStartupInfoId & id , KStartupInfoData & data )
{
return startup - > checkStartup ( w , id , data ) = = KStartupInfo : : Match ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Puts the focus on a dummy window
* Just using XSetInputFocus ( ) with None would block keyboard input
2007-04-29 17:35:43 +00:00
*/
void Workspace : : focusToNull ( )
2011-01-30 14:34:42 +00:00
{
XSetInputFocus ( display ( ) , null_focus_window , RevertToPointerRoot , xTime ( ) ) ;
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : helperDialog ( const QString & message , const Client * c )
{
2007-04-29 17:35:43 +00:00
QStringList args ;
QString type ;
2011-01-30 14:34:42 +00:00
if ( message = = " noborderaltf3 " ) {
KAction * action = qobject_cast < KAction * > ( keys - > action ( " Window Operations Menu " ) ) ;
assert ( action ! = NULL ) ;
QString shortcut = QString ( " %1 (%2) " ) . arg ( action - > text ( ) )
. arg ( action - > globalShortcut ( ) . primary ( ) . toString ( QKeySequence : : NativeText ) ) ;
2008-12-18 13:50:57 +00:00
args < < " --msgbox " < < i18n (
2011-01-30 14:34:42 +00:00
" You have selected to show a window without its border. \n "
" Without the border, you will not be able to enable the border "
" again using the mouse: use the window operations menu instead, "
" activated using the %1 keyboard shortcut. " ,
shortcut ) ;
2007-04-29 17:35:43 +00:00
type = " altf3warning " ;
2011-01-30 14:34:42 +00:00
} else if ( message = = " fullscreenaltf3 " ) {
KAction * action = qobject_cast < KAction * > ( keys - > action ( " Window Operations Menu " ) ) ;
assert ( action ! = NULL ) ;
QString shortcut = QString ( " %1 (%2) " ) . arg ( action - > text ( ) )
. arg ( action - > globalShortcut ( ) . primary ( ) . toString ( QKeySequence : : NativeText ) ) ;
2008-12-18 13:50:57 +00:00
args < < " --msgbox " < < i18n (
2011-01-30 14:34:42 +00:00
" You have selected to show a window in fullscreen mode. \n "
" 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, "
" activated using the %1 keyboard shortcut. " ,
shortcut ) ;
2007-04-29 17:35:43 +00:00
type = " altf3warning " ;
2011-01-30 14:34:42 +00:00
} else
2008-09-17 11:44:51 +00:00
abort ( ) ;
2011-01-30 14:34:42 +00:00
if ( ! type . isEmpty ( ) ) {
KConfig cfg ( " kwin_dialogsrc " ) ;
KConfigGroup cg ( & cfg , " Notification Messages " ) ; // Depends on KMessageBox
if ( ! cg . readEntry ( type , true ) )
2008-12-18 13:50:57 +00:00
return ;
args < < " --dontagain " < < " kwin_dialogsrc: " + type ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
if ( c ! = NULL )
args < < " --embed " < < QString : : number ( c - > window ( ) ) ;
KProcess : : startDetached ( " kdialog " , args ) ;
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : setShowingDesktop ( bool showing )
{
rootInfo - > setShowingDesktop ( showing ) ;
2007-04-29 17:35:43 +00:00
showing_desktop = showing ;
+ + block_showing_desktop ;
2011-01-30 14:34:42 +00:00
if ( showing_desktop ) {
2007-04-29 17:35:43 +00:00
showing_desktop_clients . clear ( ) ;
+ + block_focus ;
2012-04-08 08:07:35 +00:00
ToplevelList cls = stackingOrder ( ) ;
2008-12-18 13:50:57 +00:00
// Find them first, then minimize, otherwise transients may get minimized with the window
2007-04-29 17:35:43 +00:00
// they're transient for
2012-04-08 08:07:35 +00:00
for ( ToplevelList : : ConstIterator it = cls . constBegin ( ) ;
2011-01-30 14:34:42 +00:00
it ! = cls . constEnd ( ) ;
2012-04-08 08:07:35 +00:00
+ + it ) {
Client * c = qobject_cast < Client * > ( * it ) ;
if ( ! c ) {
continue ;
}
if ( c - > isOnCurrentActivity ( ) & & c - > isOnCurrentDesktop ( ) & & c - > isShown ( true ) & & ! c - > isSpecialWindow ( ) )
showing_desktop_clients . prepend ( c ) ; // Topmost first to reduce flicker
}
2011-01-30 14:34:42 +00:00
for ( ClientList : : ConstIterator it = showing_desktop_clients . constBegin ( ) ;
it ! = showing_desktop_clients . constEnd ( ) ;
+ + it )
2007-04-29 17:35:43 +00:00
( * it ) - > minimize ( ) ;
- - block_focus ;
2011-01-30 14:34:42 +00:00
if ( Client * desk = findDesktop ( true , currentDesktop ( ) ) )
requestFocus ( desk ) ;
} else {
for ( ClientList : : ConstIterator it = showing_desktop_clients . constBegin ( ) ;
it ! = showing_desktop_clients . constEnd ( ) ;
+ + it )
2007-04-29 17:35:43 +00:00
( * it ) - > unminimize ( ) ;
2011-01-30 14:34:42 +00:00
if ( showing_desktop_clients . count ( ) > 0 )
requestFocus ( showing_desktop_clients . first ( ) ) ;
2007-04-29 17:35:43 +00:00
showing_desktop_clients . clear ( ) ;
}
2011-01-30 14:34:42 +00:00
- - block_showing_desktop ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* 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 . Due to popular demand ( # 67406 ) by people who apparently
* don ' t see a difference between " show desktop " and " minimize all " , this is not
* true if " showDesktopIsMinimizeAll " is set in kwinrc . In such case showing
* a new window resets the state but doesn ' t show windows .
*/
2011-01-30 14:34:42 +00:00
void Workspace : : resetShowingDesktop ( bool keep_hidden )
{
if ( block_showing_desktop > 0 )
2007-04-29 17:35:43 +00:00
return ;
2011-01-30 14:34:42 +00:00
rootInfo - > setShowingDesktop ( false ) ;
2007-04-29 17:35:43 +00:00
showing_desktop = false ;
+ + block_showing_desktop ;
2011-01-30 14:34:42 +00:00
if ( ! keep_hidden ) {
for ( ClientList : : ConstIterator it = showing_desktop_clients . constBegin ( ) ;
it ! = showing_desktop_clients . constEnd ( ) ;
+ + it )
2007-04-29 17:35:43 +00:00
( * it ) - > unminimize ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
showing_desktop_clients . clear ( ) ;
- - block_showing_desktop ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +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 .
*/
2007-04-29 17:35:43 +00:00
void Workspace : : slotDisableGlobalShortcuts ( )
2011-01-30 14:34:42 +00:00
{
if ( global_shortcuts_disabled | | global_shortcuts_disabled_for_client )
disableGlobalShortcuts ( false ) ;
2007-04-29 17:35:43 +00:00
else
2011-01-30 14:34:42 +00:00
disableGlobalShortcuts ( true ) ;
}
2007-04-29 17:35:43 +00:00
static bool pending_dfc = false ;
2011-01-30 14:34:42 +00:00
void Workspace : : disableGlobalShortcutsForClient ( bool disable )
{
if ( global_shortcuts_disabled_for_client = = disable )
2007-04-29 17:35:43 +00:00
return ;
2011-01-30 14:34:42 +00:00
if ( ! global_shortcuts_disabled ) {
if ( disable )
2007-04-29 17:35:43 +00:00
pending_dfc = true ;
2011-01-30 14:34:42 +00:00
KGlobalSettings : : self ( ) - > emitChange ( KGlobalSettings : : BlockShortcuts , disable ) ;
2008-12-18 13:50:57 +00:00
// KWin will get the kipc message too
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : disableGlobalShortcuts ( bool disable )
{
KGlobalSettings : : self ( ) - > emitChange ( KGlobalSettings : : BlockShortcuts , disable ) ;
2008-12-18 13:50:57 +00:00
// KWin will get the kipc message too
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
void Workspace : : slotBlockShortcuts ( int data )
{
if ( pending_dfc & & data ) {
2007-04-29 17:35:43 +00:00
global_shortcuts_disabled_for_client = true ;
pending_dfc = false ;
2011-01-30 14:34:42 +00:00
} else {
2007-04-29 17:35:43 +00:00
global_shortcuts_disabled = data ;
global_shortcuts_disabled_for_client = false ;
2011-01-30 14:34:42 +00:00
}
2008-12-18 13:50:57 +00:00
// Update also Alt+LMB actions etc.
2011-01-30 14:34:42 +00:00
for ( ClientList : : ConstIterator it = clients . constBegin ( ) ;
it ! = clients . constEnd ( ) ;
+ + it )
2007-04-29 17:35:43 +00:00
( * it ) - > updateMouseGrab ( ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
// Optimized version of QCursor::pos() that tries to avoid X roundtrips
// by updating the value only when the X timestamp changes.
static QPoint last_cursor_pos ;
static int last_buttons = 0 ;
static Time last_cursor_timestamp = CurrentTime ;
2008-03-19 18:13:22 +00:00
static QTimer * last_cursor_timer ;
2007-04-29 17:35:43 +00:00
2007-08-24 09:54:21 +00:00
QPoint Workspace : : cursorPos ( ) const
2011-01-30 14:34:42 +00:00
{
if ( last_cursor_timestamp = = CurrentTime | |
last_cursor_timestamp ! = QX11Info : : appTime ( ) ) {
2007-04-29 17:35:43 +00:00
last_cursor_timestamp = QX11Info : : appTime ( ) ;
Window root ;
Window child ;
int root_x , root_y , win_x , win_y ;
uint state ;
2011-01-30 14:34:42 +00:00
XQueryPointer ( display ( ) , rootWindow ( ) , & root , & child ,
& root_x , & root_y , & win_x , & win_y , & state ) ;
last_cursor_pos = QPoint ( root_x , root_y ) ;
2007-04-29 17:35:43 +00:00
last_buttons = state ;
2011-01-30 14:34:42 +00:00
if ( last_cursor_timer = = NULL ) {
Workspace * ws = const_cast < Workspace * > ( this ) ;
last_cursor_timer = new QTimer ( ws ) ;
last_cursor_timer - > setSingleShot ( true ) ;
connect ( last_cursor_timer , SIGNAL ( timeout ( ) ) , ws , SLOT ( resetCursorPosTime ( ) ) ) ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
last_cursor_timer - > start ( 0 ) ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
return last_cursor_pos ;
}
2007-04-29 17:35:43 +00:00
2008-12-18 13:50:57 +00:00
/**
* Because of QTimer ' s and the impossibility to get events for all mouse
* movements ( at least I haven ' t figured out how ) the position needs
* to be also refetched after each return to the event loop .
*/
2007-04-29 17:35:43 +00:00
void Workspace : : resetCursorPosTime ( )
2011-01-30 14:34:42 +00:00
{
2007-04-29 17:35:43 +00:00
last_cursor_timestamp = CurrentTime ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
void Workspace : : checkCursorPos ( )
2011-01-30 14:34:42 +00:00
{
2007-04-29 17:35:43 +00:00
QPoint last = last_cursor_pos ;
int lastb = last_buttons ;
2008-12-18 13:50:57 +00:00
cursorPos ( ) ; // Update if needed
2011-03-12 13:37:30 +00:00
if ( last ! = last_cursor_pos | | lastb ! = last_buttons ) {
emit mouseChanged ( last_cursor_pos , last ,
x11ToQtMouseButtons ( last_buttons ) , x11ToQtMouseButtons ( lastb ) ,
x11ToQtKeyboardModifiers ( last_buttons ) , x11ToQtKeyboardModifiers ( lastb ) ) ;
}
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2009-11-16 10:09:03 +00:00
2011-04-28 09:16:27 +00:00
Outline * Workspace : : outline ( )
{
return m_outline ;
}
2011-07-07 16:29:11 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
2011-06-23 10:51:43 +00:00
ScreenEdge * Workspace : : screenEdge ( )
{
return & m_screenEdge ;
}
2011-07-07 16:29:11 +00:00
# endif
2011-06-23 10:51:43 +00:00
2011-06-30 11:02:30 +00:00
bool Workspace : : hasTabBox ( ) const
{
# ifdef KWIN_BUILD_TABBOX
return ( tab_box ! = NULL ) ;
# else
return false ;
# endif
}
# ifdef KWIN_BUILD_TABBOX
TabBox : : TabBox * Workspace : : tabBox ( ) const
{
return tab_box ;
}
# endif
2011-06-23 10:51:43 +00:00
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-13 16:48:56 +00:00
Tiling * Workspace : : tiling ( )
{
return m_tiling ;
}
2011-07-20 11:25:00 +00:00
# endif
2011-07-13 16:48:56 +00:00
/*
* Called from D - BUS
*/
void Workspace : : toggleTiling ( )
{
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-13 16:48:56 +00:00
if ( m_tiling ) {
m_tiling - > slotToggleTiling ( ) ;
}
2011-07-20 11:25:00 +00:00
# endif
2011-07-13 16:48:56 +00:00
}
/*
* Called from D - BUS
*/
void Workspace : : nextTileLayout ( )
{
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-13 16:48:56 +00:00
if ( m_tiling ) {
m_tiling - > slotNextTileLayout ( ) ;
}
2011-07-20 11:25:00 +00:00
# endif
2011-07-13 16:48:56 +00:00
}
/*
* Called from D - BUS
*/
void Workspace : : previousTileLayout ( )
{
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-13 16:48:56 +00:00
if ( m_tiling ) {
m_tiling - > slotPreviousTileLayout ( ) ;
}
2011-07-20 11:25:00 +00:00
# endif
2011-07-13 16:48:56 +00:00
}
void Workspace : : dumpTiles ( ) const {
2011-07-20 11:25:00 +00:00
# ifdef KWIN_BUILD_TILING
2011-07-13 16:48:56 +00:00
if ( m_tiling ) {
m_tiling - > dumpTiles ( ) ;
}
2011-07-20 11:25:00 +00:00
# endif
2011-07-13 16:48:56 +00:00
}
2012-03-04 14:13:22 +00:00
QString Workspace : : supportInformation ( ) const
{
QString support ;
support . append ( ki18nc ( " Introductory text shown in the support information. " ,
" KWin Support Information: \n "
" The following information should be used when requesting support on e.g. http://forum.kde.org. \n "
" It provides information about the currently running instance, which options are used, \n "
" what OpenGL driver and which effects are running. \n "
" Please post the information provided underneath this introductory text to a paste bin service \n "
" like http://paste.kde.org instead of pasting into support threads. \n " ) . toString ( ) ) ;
support . append ( " \n ========================== \n \n " ) ;
// all following strings are intended for support. They need to be pasted to e.g forums.kde.org
// it is expected that the support will happen in English language or that the people providing
// help understand English. Because of that all texts are not translated
support . append ( " Options \n " ) ;
support . append ( " ======= \n " ) ;
const QMetaObject * metaOptions = options - > metaObject ( ) ;
for ( int i = 0 ; i < metaOptions - > propertyCount ( ) ; + + i ) {
const QMetaProperty property = metaOptions - > property ( i ) ;
if ( QLatin1String ( property . name ( ) ) = = " objectName " ) {
continue ;
}
support . append ( QLatin1String ( property . name ( ) ) % " : " % options - > property ( property . name ( ) ) . toString ( ) % ' \n ' ) ;
}
support . append ( " \n Compositing \n " ) ;
support . append ( " =========== \n " ) ;
2012-03-08 06:46:21 +00:00
support . append ( " Qt Graphics System: " ) ;
if ( Extensions : : nonNativePixmaps ( ) ) {
support . append ( " raster \n " ) ;
} else {
support . append ( " native \n " ) ;
}
2012-03-04 14:13:22 +00:00
if ( effects ) {
support . append ( " Compositing is active \n " ) ;
switch ( effects - > compositingType ( ) ) {
case OpenGLCompositing : {
# ifdef KWIN_HAVE_OPENGLES
support . append ( " Compositing Type: OpenGL ES 2.0 \n " ) ;
# else
support . append ( " Compositing Type: OpenGL \n " ) ;
# endif
GLPlatform * platform = GLPlatform : : instance ( ) ;
support . append ( " OpenGL vendor string: " % platform - > glVendorString ( ) % ' \n ' ) ;
support . append ( " OpenGL renderer string: " % platform - > glRendererString ( ) % ' \n ' ) ;
support . append ( " OpenGL version string: " % platform - > glVersionString ( ) % ' \n ' ) ;
if ( platform - > supports ( LimitedGLSL ) )
support . append ( " OpenGL shading language version string: " % platform - > glShadingLanguageVersionString ( ) % ' \n ' ) ;
support . append ( " Driver: " % GLPlatform : : driverToString ( platform - > driver ( ) ) % ' \n ' ) ;
if ( ! platform - > isMesaDriver ( ) )
support . append ( " Driver version: " % GLPlatform : : versionToString ( platform - > driverVersion ( ) ) % ' \n ' ) ;
support . append ( " GPU class: " % GLPlatform : : chipClassToString ( platform - > chipClass ( ) ) % ' \n ' ) ;
support . append ( " OpenGL version: " % GLPlatform : : versionToString ( platform - > glVersion ( ) ) % ' \n ' ) ;
if ( platform - > supports ( LimitedGLSL ) )
support . append ( " GLSL version: " % GLPlatform : : versionToString ( platform - > glslVersion ( ) ) % ' \n ' ) ;
if ( platform - > isMesaDriver ( ) )
support . append ( " Mesa version: " % GLPlatform : : versionToString ( platform - > mesaVersion ( ) ) % ' \n ' ) ;
if ( platform - > serverVersion ( ) > 0 )
support . append ( " X server version: " % GLPlatform : : versionToString ( platform - > serverVersion ( ) ) % ' \n ' ) ;
if ( platform - > kernelVersion ( ) > 0 )
support . append ( " Linux kernel version: " % GLPlatform : : versionToString ( platform - > kernelVersion ( ) ) % ' \n ' ) ;
support . append ( " Direct rendering: " ) ;
if ( platform - > isDirectRendering ( ) ) {
support . append ( " yes \n " ) ;
} else {
support . append ( " no \n " ) ;
}
support . append ( " Requires strict binding: " ) ;
if ( ! platform - > isLooseBinding ( ) ) {
support . append ( " yes \n " ) ;
} else {
support . append ( " no \n " ) ;
}
support . append ( " GLSL shaders: " ) ;
if ( platform - > supports ( GLSL ) ) {
if ( platform - > supports ( LimitedGLSL ) ) {
support . append ( " limited \n " ) ;
} else {
support . append ( " yes \n " ) ;
}
} else {
support . append ( " no \n " ) ;
}
support . append ( " Texture NPOT support: " ) ;
if ( platform - > supports ( TextureNPOT ) ) {
if ( platform - > supports ( LimitedNPOT ) ) {
support . append ( " limited \n " ) ;
} else {
support . append ( " yes \n " ) ;
}
} else {
support . append ( " no \n " ) ;
}
if ( ShaderManager : : instance ( ) - > isValid ( ) ) {
support . append ( " OpenGL 2 Shaders are used \n " ) ;
} else {
support . append ( " OpenGL 2 Shaders are not used. Legacy OpenGL 1.x code path is used. \n " ) ;
}
break ;
}
case XRenderCompositing :
support . append ( " Compositing Type: XRender \n " ) ;
break ;
case NoCompositing :
default :
support . append ( " Something is really broken, neither OpenGL nor XRender is used " ) ;
}
support . append ( " \n Loaded Effects: \n " ) ;
support . append ( " --------------- \n " ) ;
foreach ( const QString & effect , loadedEffects ( ) ) {
support . append ( effect % ' \n ' ) ;
}
support . append ( " \n Currently Active Effects: \n " ) ;
support . append ( " ------------------------- \n " ) ;
foreach ( const QString & effect , activeEffects ( ) ) {
support . append ( effect % ' \n ' ) ;
}
} else {
support . append ( " Compositing is not active \n " ) ;
}
return support ;
}
2007-04-29 17:35:43 +00:00
} // namespace
# include "workspace.moc"