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>
2013-02-26 08:00:51 +00:00
# include <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>
2013-01-10 08:55:52 +00:00
# include <kdeversion.h>
2007-04-29 17:35:43 +00:00
# include <QtDBus/QtDBus>
2013-03-07 12:47:07 +00:00
# include <QtConcurrentRun>
2007-04-29 17:35:43 +00:00
# include "client.h"
2011-08-21 19:50:23 +00:00
# include "composite.h"
2012-11-20 16:26:50 +00:00
# include "focuschain.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"
2013-02-19 10:25:46 +00:00
# include "cursor.h"
2007-04-29 17:35:43 +00:00
# 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"
2012-08-30 06:20:26 +00:00
# include "dbusinterface.h"
2007-04-29 17:35:43 +00:00
# include "unmanaged.h"
# include "deleted.h"
# include "effects.h"
2011-07-06 09:58:23 +00:00
# include "overlaywindow.h"
2012-08-19 10:00:53 +00:00
# include "useractions.h"
2012-11-16 07:23:47 +00:00
# include "virtualdesktops.h"
2012-12-21 14:11:31 +00:00
# include "xcbutils.h"
2012-03-04 14:13:22 +00:00
# include <kwinglplatform.h>
# include <kwinglutils.h>
2013-01-21 08:04:06 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
# include "screenedge.h"
# endif
2012-04-12 13:19:38 +00:00
# ifdef KWIN_BUILD_SCRIPTING
# include "scripting/scripting.h"
# 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 <stdio.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 ;
2013-01-12 08:54:24 +00:00
extern bool is_multihead ;
2007-04-29 17:35:43 +00:00
2012-11-09 12:44:50 +00:00
# ifdef KWIN_BUILD_KAPPMENU
static const char * KDED_SERVICE = " org.kde.kded " ;
static const char * KDED_APPMENU_PATH = " /modules/appmenu " ;
static const char * KDED_INTERFACE = " org.kde.kded " ;
# endif
2008-12-18 13:50:57 +00:00
Workspace * Workspace : : _self = 0 ;
2007-04-29 17:35:43 +00:00
2011-01-30 14:34:42 +00:00
Workspace : : Workspace ( bool restore )
: QObject ( 0 )
2012-08-27 17:45:01 +00:00
, m_compositor ( NULL )
2009-02-14 15:40:52 +00:00
// Unsorted
2011-01-30 14:34:42 +00:00
, active_popup ( NULL )
, active_popup_client ( NULL )
2013-03-07 12:45:23 +00:00
, temporaryRulesMessages ( " _KDE_NET_WM_TEMPORARY_RULES " , NULL )
2011-01-30 14:34:42 +00:00
, 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
2012-08-19 10:00:53 +00:00
, m_userActionsMenu ( new UserActionsMenu ( this ) )
2011-01-30 14:34:42 +00:00
, 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 )
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 ) ;
2012-11-09 12:44:50 +00:00
# ifdef KWIN_BUILD_KAPPMENU
QDBusConnection dbus = QDBusConnection : : sessionBus ( ) ;
dbus . connect ( KDED_SERVICE , KDED_APPMENU_PATH , KDED_INTERFACE , " showRequest " ,
this , SLOT ( slotShowRequest ( qulonglong ) ) ) ;
dbus . connect ( KDED_SERVICE , KDED_APPMENU_PATH , KDED_INTERFACE , " menuAvailable " ,
this , SLOT ( slotMenuAvailable ( qulonglong ) ) ) ;
dbus . connect ( KDED_SERVICE , KDED_APPMENU_PATH , KDED_INTERFACE , " menuHidden " ,
this , SLOT ( slotMenuHidden ( qulonglong ) ) ) ;
dbus . connect ( KDED_SERVICE , KDED_APPMENU_PATH , KDED_INTERFACE , " clearMenus " ,
this , SLOT ( slotClearMenus ( ) ) ) ;
# endif
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-12-21 14:11:31 +00:00
Xcb : : Extensions : : self ( ) ;
2012-04-13 06:39:04 +00:00
2013-02-19 10:25:46 +00:00
// start the cursor support
Cursor : : create ( this ) ;
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 ;
2013-03-07 12:48:17 +00:00
default_colormap = DefaultColormap ( display ( ) , screen_number ) ;
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 ( ) ) ) ;
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-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
2013-01-25 09:15:00 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
ScreenEdges : : create ( this ) ;
# endif
2012-11-17 10:50:59 +00:00
// VirtualDesktopManager needs to be created prior to init shortcuts
// and prior to TabBox, due to TabBox connecting to signals
// actual initialization happens in init()
VirtualDesktopManager : : create ( this ) ;
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
2012-08-28 17:31:17 +00:00
m_compositor = Compositor : : createCompositor ( this ) ;
2012-08-23 11:42:59 +00:00
connect ( this , SIGNAL ( currentDesktopChanged ( int , KWin : : Client * ) ) , m_compositor , SLOT ( addRepaintFull ( ) ) ) ;
2011-08-21 19:50:23 +00:00
connect ( m_compositor , SIGNAL ( compositingToggled ( bool ) ) , SLOT ( slotCompositingToggled ( ) ) ) ;
2012-08-30 06:20:26 +00:00
new DBusInterface ( this ) ;
2007-04-29 17:35:43 +00:00
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
2013-01-25 09:15:00 +00:00
ScreenEdges * screenEdges = ScreenEdges : : self ( ) ;
screenEdges - > setConfig ( KGlobal : : config ( ) ) ;
screenEdges - > init ( ) ;
connect ( options , SIGNAL ( configChanged ( ) ) , screenEdges , SLOT ( reconfigure ( ) ) ) ;
connect ( VirtualDesktopManager : : self ( ) , SIGNAL ( layoutChanged ( int , int ) ) , screenEdges , SLOT ( updateLayout ( ) ) ) ;
2013-01-31 16:25:03 +00:00
connect ( this , SIGNAL ( clientActivated ( KWin : : Client * ) ) , screenEdges , SIGNAL ( checkBlocking ( ) ) ) ;
2011-07-07 16:29:11 +00:00
# endif
2007-04-29 17:35:43 +00:00
2012-11-20 16:26:50 +00:00
FocusChain * focusChain = FocusChain : : create ( this ) ;
connect ( this , SIGNAL ( clientRemoved ( KWin : : Client * ) ) , focusChain , SLOT ( remove ( KWin : : Client * ) ) ) ;
connect ( this , SIGNAL ( clientActivated ( KWin : : Client * ) ) , focusChain , SLOT ( setActiveClient ( KWin : : Client * ) ) ) ;
connect ( VirtualDesktopManager : : self ( ) , SIGNAL ( countChanged ( uint , uint ) ) , focusChain , SLOT ( resize ( uint , uint ) ) ) ;
connect ( VirtualDesktopManager : : self ( ) , SIGNAL ( currentChanged ( uint , uint ) ) , focusChain , SLOT ( setCurrentDesktop ( uint , uint ) ) ) ;
connect ( options , SIGNAL ( separateScreenFocusChanged ( bool ) ) , focusChain , SLOT ( setSeparateScreenFocus ( bool ) ) ) ;
focusChain - > setSeparateScreenFocus ( options - > isSeparateScreenFocus ( ) ) ;
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 ;
2013-03-07 12:48:17 +00:00
rootInfo = new RootInfo ( this , display ( ) , supportWindow - > winId ( ) , " KWin " , protocols , 5 , screen_number ) ;
2007-04-29 17:35:43 +00:00
2012-11-16 07:23:47 +00:00
// create VirtualDesktopManager and perform dependency injection
VirtualDesktopManager * vds = VirtualDesktopManager : : self ( ) ;
connect ( vds , SIGNAL ( desktopsRemoved ( uint ) ) , SLOT ( moveClientsFromRemovedDesktops ( ) ) ) ;
connect ( vds , SIGNAL ( countChanged ( uint , uint ) ) , SLOT ( slotDesktopCountChanged ( uint , uint ) ) ) ;
connect ( vds , SIGNAL ( currentChanged ( uint , uint ) ) , SLOT ( slotCurrentDesktopChanged ( uint , uint ) ) ) ;
vds - > setNavigationWrappingAround ( options - > isRollOverDesktops ( ) ) ;
connect ( options , SIGNAL ( rollOverDesktopsChanged ( bool ) ) , vds , SLOT ( setNavigationWrappingAround ( bool ) ) ) ;
vds - > setRootInfo ( rootInfo ) ;
vds - > setConfig ( KGlobal : : config ( ) ) ;
2012-05-01 16:34:38 +00:00
2012-05-26 19:06:40 +00:00
// Now we know how many desktops we'll have, thus we initialize the positioning object
2012-11-22 12:41:50 +00:00
Placement : : create ( this ) ;
2012-05-26 19:06:40 +00:00
2012-11-16 07:23:47 +00:00
// positioning object needs to be created before the virtual desktops are loaded.
vds - > load ( ) ;
vds - > updateLayout ( ) ;
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 ) ;
}
2012-11-16 07:23:47 +00:00
if ( ! VirtualDesktopManager : : self ( ) - > setCurrent ( initial_desktop ) )
VirtualDesktopManager : : self ( ) - > setCurrent ( 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 ( ) ) ) ;
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
2011-01-30 14:34:42 +00:00
bool fixoffset = KCmdLineArgs : : parsedArgs ( ) - > getOption ( " crashes " ) . toInt ( ) > 0 ;
2012-03-26 15:30:34 +00:00
2013-01-07 13:10:00 +00:00
Xcb : : Tree tree ( rootWindow ( ) ) ;
xcb_window_t * wins = xcb_query_tree_children ( tree . data ( ) ) ;
2012-03-26 15:30:34 +00:00
2013-01-07 13:10:00 +00:00
QVector < Xcb : : WindowAttributes > windowAttributes ( tree - > children_len ) ;
QVector < Xcb : : WindowGeometry > windowGeometries ( tree - > children_len ) ;
2012-03-26 15:30:34 +00:00
// Request the attributes and geometries of all toplevel windows
for ( int i = 0 ; i < tree - > children_len ; i + + ) {
2013-01-07 13:10:00 +00:00
windowAttributes [ i ] = Xcb : : WindowAttributes ( wins [ i ] ) ;
windowGeometries [ i ] = Xcb : : WindowGeometry ( wins [ i ] ) ;
2012-03-26 15:30:34 +00:00
}
// Get the replies
for ( int i = 0 ; i < tree - > children_len ; i + + ) {
2013-01-07 13:10:00 +00:00
Xcb : : WindowAttributes attr ( windowAttributes . at ( i ) ) ;
2012-03-26 15:30:34 +00:00
2013-01-07 13:10:00 +00:00
if ( attr . isNull ( ) ) {
2007-04-29 17:35:43 +00:00
continue ;
2013-01-07 13:10:00 +00:00
}
2012-03-26 15:30:34 +00:00
if ( attr - > override_redirect ) {
if ( attr - > map_state = = XCB_MAP_STATE_VIEWABLE & &
attr - > _class ! = XCB_WINDOW_CLASS_INPUT_ONLY )
// ### This will request the attributes again
createUnmanaged ( wins [ i ] ) ;
} else if ( attr - > map_state ! = XCB_MAP_STATE_UNMAPPED ) {
2013-01-07 13:10:00 +00:00
if ( fixoffset ) {
fixPositionAfterCrash ( wins [ i ] , windowGeometries [ i ] . data ( ) ) ;
}
2012-03-26 15:30:34 +00:00
// ### This will request the attributes again
2011-01-30 14:34:42 +00:00
createClient ( wins [ i ] , true ) ;
2007-04-29 17:35:43 +00:00
}
2011-01-30 14:34:42 +00:00
}
2012-03-26 15:30:34 +00:00
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
2012-11-16 07:23:47 +00:00
NETPoint * viewports = new NETPoint [ VirtualDesktopManager : : self ( ) - > count ( ) ] ;
rootInfo - > setDesktopViewport ( VirtualDesktopManager : : self ( ) - > count ( ) , * 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 )
2012-11-16 07:23:47 +00:00
new_active_client = topClientOnDesktop ( VirtualDesktopManager : : self ( ) - > current ( ) , - 1 ) ;
2011-01-30 14:34:42 +00:00
if ( new_active_client = = NULL & & ! desktops . isEmpty ( ) )
2012-11-16 07:23:47 +00:00
new_active_client = findDesktop ( true , VirtualDesktopManager : : self ( ) - > current ( ) ) ;
2011-01-30 14:34:42 +00:00
}
if ( new_active_client ! = NULL )
activateClient ( new_active_client ) ;
2009-09-08 20:01:08 +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
{
2011-08-21 19:50:23 +00:00
delete m_compositor ;
2012-08-27 17:45:01 +00:00
m_compositor = NULL ;
2011-01-30 14:34:42 +00:00
blockStackingUpdates ( true ) ;
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 ;
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 ;
2012-11-22 12:41:50 +00:00
delete Placement : : self ( ) ;
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();
2012-12-21 14:11:31 +00:00
Xcb : : Extensions : : destroy ( ) ;
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 ) ;
2012-08-23 11:42:59 +00:00
connect ( c , SIGNAL ( needsRepaint ( ) ) , m_compositor , SLOT ( scheduleRepaint ( ) ) ) ;
connect ( c , SIGNAL ( activeChanged ( ) ) , m_compositor , SLOT ( checkUnredirect ( ) ) ) ;
connect ( c , SIGNAL ( fullScreenChanged ( ) ) , m_compositor , SLOT ( checkUnredirect ( ) ) ) ;
connect ( c , SIGNAL ( geometryChanged ( ) ) , m_compositor , SLOT ( checkUnredirect ( ) ) ) ;
connect ( c , SIGNAL ( geometryShapeChanged ( KWin : : Toplevel * , QRect ) ) , m_compositor , SLOT ( checkUnredirect ( ) ) ) ;
connect ( c , SIGNAL ( blockingCompositingChanged ( KWin : : Client * ) ) , m_compositor , SLOT ( updateCompositeBlocking ( KWin : : Client * ) ) ) ;
2013-01-31 16:25:03 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
connect ( c , SIGNAL ( clientFullScreenSet ( KWin : : Client * , bool , bool ) ) , ScreenEdges : : self ( ) , SIGNAL ( checkBlocking ( ) ) ) ;
# endif
2012-10-15 16:57:21 +00:00
if ( ! c - > manage ( w , is_mapped ) ) {
Client : : deleteClient ( c , Allowed ) ;
return NULL ;
}
2011-01-30 14:34:42 +00:00
addClient ( c , Allowed ) ;
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 )
{
2012-08-16 19:19:54 +00:00
if ( m_compositor & & m_compositor - > checkForOverlayWindow ( w ) )
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 ;
}
2012-08-23 11:42:59 +00:00
connect ( c , SIGNAL ( needsRepaint ( ) ) , m_compositor , SLOT ( scheduleRepaint ( ) ) ) ;
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 {
2012-11-20 16:26:50 +00:00
FocusChain : : self ( ) - > update ( c , FocusChain : : Update ) ;
2011-01-30 14:34:42 +00:00
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 )
2012-11-16 07:23:47 +00:00
activateClient ( findDesktop ( true , VirtualDesktopManager : : self ( ) - > current ( ) ) ) ;
2011-01-30 14:34:42 +00:00
}
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
2012-11-09 12:44:50 +00:00
# ifdef KWIN_BUILD_KAPPMENU
if ( m_windowsMenu . removeOne ( c - > window ( ) ) )
c - > setAppMenuAvailable ( ) ;
# 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-08-19 10:00:53 +00:00
if ( m_userActionsMenu - > isMenuClient ( c ) ) {
m_userActionsMenu - > close ( ) ;
}
2007-04-29 17:35:43 +00:00
2012-12-29 14:36:55 +00:00
c - > untab ( QRect ( ) , true ) ;
2012-01-12 06:42:55 +00:00
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
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-08-21 19:50:23 +00:00
if ( m_compositor ) {
m_compositor - > updateCompositeBlocking ( ) ;
}
2011-03-20 14:42:05 +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 ( ) )
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 ;
2012-08-23 11:42:59 +00:00
connect ( c , SIGNAL ( needsRepaint ( ) ) , m_compositor , SLOT ( scheduleRepaint ( ) ) ) ;
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 ) ) ;
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 : : 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
}
2012-11-09 12:44:50 +00:00
# ifdef KWIN_BUILD_KAPPMENU
void Workspace : : slotShowRequest ( qulonglong wid )
{
if ( Client * c = findClient ( WindowMatchPredicate ( wid ) ) )
c - > emitShowRequest ( ) ;
}
2008-01-30 16:08:23 +00:00
2012-11-09 12:44:50 +00:00
void Workspace : : slotMenuAvailable ( qulonglong wid )
{
if ( Client * c = findClient ( WindowMatchPredicate ( wid ) ) )
c - > setAppMenuAvailable ( ) ;
else
m_windowsMenu . append ( wid ) ;
}
void Workspace : : slotMenuHidden ( qulonglong wid )
{
if ( Client * c = findClient ( WindowMatchPredicate ( wid ) ) )
c - > emitMenuHidden ( ) ;
}
void Workspace : : slotClearMenus ( )
{
foreach ( Client * c , clients ) {
c - > setAppMenuUnavailable ( ) ;
}
}
# endif
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-08-21 19:50:23 +00:00
if ( m_compositor ) {
2012-08-17 06:18:36 +00:00
return m_compositor - > isActive ( ) ;
2011-08-21 19:50:23 +00:00
}
return false ;
2011-01-30 14:34:42 +00:00
}
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 )
2012-08-19 10:00:53 +00:00
m_userActionsMenu - > discard ( ) ;
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 ( ) ;
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 ( ) ;
2012-08-19 10:00:53 +00:00
m_userActionsMenu - > discard ( ) ;
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
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-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
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 ( 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
2012-11-16 07:23:47 +00:00
void Workspace : : slotCurrentDesktopChanged ( uint oldDesktop , uint newDesktop )
2011-01-30 14:34:42 +00:00
{
2007-04-29 17:35:43 +00:00
closeActivePopup ( ) ;
+ + block_focus ;
2011-01-30 14:34:42 +00:00
StackingUpdatesBlocker blocker ( this ) ;
2012-11-16 07:23:47 +00:00
updateClientVisibilityOnDesktopChange ( oldDesktop , newDesktop ) ;
// Restore the focus on this desktop
- - block_focus ;
2007-04-29 17:35:43 +00:00
2012-11-16 07:23:47 +00:00
activateClientOnNewDesktop ( newDesktop ) ;
emit currentDesktopChanged ( oldDesktop , movingClient ) ;
}
2007-04-29 17:35:43 +00:00
2012-11-16 07:23:47 +00:00
void Workspace : : updateClientVisibilityOnDesktopChange ( uint oldDesktop , uint newDesktop )
{
+ + block_showing_desktop ;
ObscuringWindows obs_wins ;
for ( ToplevelList : : ConstIterator it = stacking_order . constBegin ( ) ;
it ! = stacking_order . constEnd ( ) ;
+ + it ) {
Client * c = qobject_cast < Client * > ( * it ) ;
if ( ! c ) {
continue ;
2011-01-30 14:34:42 +00:00
}
2012-11-16 07:23:47 +00:00
if ( ! c - > isOnDesktop ( newDesktop ) & & c ! = movingClient & & c - > isOnCurrentActivity ( ) ) {
if ( c - > isShown ( true ) & & c - > isOnDesktop ( oldDesktop ) & & ! compositing ( ) )
obs_wins . create ( c ) ;
( c ) - > updateVisibility ( ) ;
2012-04-08 08:07:35 +00:00
}
2011-01-30 14:34:42 +00:00
}
2012-11-16 07:23:47 +00:00
// Now propagate the change, after hiding, before showing
rootInfo - > setCurrentDesktop ( VirtualDesktopManager : : self ( ) - > current ( ) ) ;
2007-04-29 17:35:43 +00:00
2012-11-16 07:23:47 +00:00
if ( movingClient & & ! movingClient - > isOnDesktop ( newDesktop ) ) {
movingClient - > setDesktop ( newDesktop ) ;
}
2011-08-22 11:53:03 +00:00
2012-11-16 07:23:47 +00:00
for ( int i = stacking_order . size ( ) - 1 ; i > = 0 ; - - i ) {
Client * c = qobject_cast < Client * > ( stacking_order . at ( i ) ) ;
2011-01-30 14:34:42 +00:00
if ( ! c ) {
2012-11-16 07:23:47 +00:00
continue ;
2007-04-29 17:35:43 +00:00
}
2012-11-16 07:23:47 +00:00
if ( c - > isOnDesktop ( newDesktop ) & & c - > isOnCurrentActivity ( ) )
c - > updateVisibility ( ) ;
}
- - block_showing_desktop ;
if ( showingDesktop ( ) ) // Do this only after desktop change to avoid flicker
resetShowingDesktop ( false ) ;
}
void Workspace : : activateClientOnNewDesktop ( uint desktop )
{
Client * c = NULL ;
if ( options - > focusPolicyIsReasonable ( ) ) {
c = findClientToActivateOnDesktop ( desktop ) ;
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 ( ) )
2012-11-16 07:23:47 +00:00
c = findDesktop ( true , desktop ) ;
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 ( ) )
2012-11-16 07:23:47 +00:00
requestFocus ( findDesktop ( true , desktop ) ) ;
2007-04-29 17:35:43 +00:00
else
focusToNull ( ) ;
2012-11-16 07:23:47 +00:00
}
2007-04-29 17:35:43 +00:00
2012-11-16 07:23:47 +00:00
Client * Workspace : : findClientToActivateOnDesktop ( uint desktop )
{
if ( movingClient ! = NULL & & active_client = = movingClient & &
2012-11-20 16:26:50 +00:00
FocusChain : : self ( ) - > contains ( active_client , desktop ) & &
2012-11-16 07:23:47 +00:00
active_client - > isShown ( true ) & & active_client - > isOnCurrentDesktop ( ) ) {
// A requestFocus call will fail, as the client is already active
return active_client ;
}
// from actiavtion.cpp
if ( options - > isNextFocusPrefersMouse ( ) ) {
ToplevelList : : const_iterator it = stackingOrder ( ) . constEnd ( ) ;
while ( it ! = stackingOrder ( ) . constBegin ( ) ) {
Client * client = qobject_cast < Client * > ( * ( - - it ) ) ;
if ( ! client ) {
continue ;
}
2007-04-29 17:35:43 +00:00
2012-11-16 07:23:47 +00:00
if ( ! ( client - > isShown ( false ) & & client - > isOnDesktop ( desktop ) & &
client - > isOnCurrentActivity ( ) & & client - > isOnScreen ( activeScreen ( ) ) ) )
continue ;
2007-04-29 17:35:43 +00:00
2013-02-26 07:45:44 +00:00
if ( client - > geometry ( ) . contains ( Cursor : : pos ( ) ) ) {
2012-11-16 07:23:47 +00:00
if ( ! client - > isDesktop ( ) )
return client ;
break ; // unconditional break - we do not pass the focus to some client below an unusable one
}
}
}
2012-11-20 16:26:50 +00:00
return FocusChain : : self ( ) - > getForActivation ( desktop ) ;
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
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 ) ;
}
2012-08-19 10:00:53 +00:00
void Workspace : : updateActivityList ( bool running , bool updateCurrent , QObject * target , QString slot )
2012-04-12 19:52:44 +00:00
{
if ( updateCurrent ) {
QFutureWatcher < CurrentAndList > * watcher = new QFutureWatcher < CurrentAndList > ;
connect ( watcher , SIGNAL ( finished ( ) ) , SLOT ( handleActivityReply ( ) ) ) ;
2012-08-19 10:00:53 +00:00
if ( ! slot . isEmpty ( ) ) {
2012-04-12 19:52:44 +00:00
watcher - > setProperty ( " activityControllerCallback " , slot ) ; // "activity reply trigger"
2012-08-19 10:00:53 +00:00
watcher - > setProperty ( " activityControllerCallbackTarget " , qVariantFromValue ( ( void * ) target ) ) ;
}
2012-04-12 19:52:44 +00:00
watcher - > setFuture ( QtConcurrent : : run ( fetchActivityListAndCurrent , & activityController_ ) ) ;
} else {
QFutureWatcher < AssignedList > * watcher = new QFutureWatcher < AssignedList > ;
connect ( watcher , SIGNAL ( finished ( ) ) , SLOT ( handleActivityReply ( ) ) ) ;
2012-08-19 10:00:53 +00:00
if ( ! slot . isEmpty ( ) ) {
2012-04-12 19:52:44 +00:00
watcher - > setProperty ( " activityControllerCallback " , slot ) ; // "activity reply trigger"
2012-08-19 10:00:53 +00:00
watcher - > setProperty ( " activityControllerCallbackTarget " , qVariantFromValue ( ( void * ) target ) ) ;
}
2012-04-12 19:52:44 +00:00
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 ) ;
2012-11-17 10:50:59 +00:00
emit currentActivityChanged ( currentActivity ( ) ) ;
2012-04-12 19:52:44 +00:00
watcherObject = watcher ;
}
}
if ( watcherObject ) {
QString slot = watcherObject - > property ( " activityControllerCallback " ) . toString ( ) ;
2012-08-19 10:00:53 +00:00
QObject * target = static_cast < QObject * > ( watcherObject - > property ( " activityControllerCallbackTarget " ) . value < void * > ( ) ) ;
2012-04-12 19:52:44 +00:00
watcherObject - > deleteLater ( ) ; // has done it's job
if ( ! slot . isEmpty ( ) )
2012-08-19 10:00:53 +00:00
QMetaObject : : invokeMethod ( target , slot . toAscii ( ) . data ( ) , Qt : : DirectConnection ) ;
2012-04-12 19:52:44 +00:00
}
}
//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 ( ) ) {
2012-08-16 19:19:54 +00:00
if ( c - > isShown ( true ) & & c - > isOnActivity ( old_activity ) & & ! compositing ( ) )
2012-04-08 08:07:35 +00:00
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
{
movingClient - > setDesktop ( new_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
2012-11-20 16:26:50 +00:00
c = FocusChain : : self ( ) - > getForActivation ( VirtualDesktopManager : : self ( ) - > current ( ) ) ;
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 ( ) )
2012-11-16 07:23:47 +00:00
c = findDesktop ( true , VirtualDesktopManager : : self ( ) - > current ( ) ) ;
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 ( ) )
2012-11-16 07:23:47 +00:00
requestFocus ( findDesktop ( true , VirtualDesktopManager : : self ( ) - > current ( ) ) ) ;
2010-05-11 20:30:20 +00:00
else
focusToNull ( ) ;
// 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-08-21 19:50:23 +00:00
if ( compositing ( ) & & m_compositor )
m_compositor - > addRepaintFull ( ) ;
2010-05-11 20:30:20 +00:00
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
2012-11-16 07:23:47 +00:00
void Workspace : : moveClientsFromRemovedDesktops ( )
2011-01-30 14:34:42 +00:00
{
2012-11-16 07:23:47 +00:00
for ( ClientList : : ConstIterator it = clients . constBegin ( ) ; it ! = clients . constEnd ( ) ; + + it ) {
if ( ! ( * it ) - > isOnAllDesktops ( ) & & ( * it ) - > desktop ( ) > static_cast < int > ( VirtualDesktopManager : : self ( ) - > count ( ) ) )
sendClientToDesktop ( * it , VirtualDesktopManager : : self ( ) - > count ( ) , true ) ;
}
2011-01-30 14:34:42 +00:00
}
2007-04-29 17:35:43 +00:00
2012-11-16 07:23:47 +00:00
void Workspace : : slotDesktopCountChanged ( uint previousCount , uint newCount )
2011-01-30 14:34:42 +00:00
{
2012-11-17 10:50:59 +00:00
Q_UNUSED ( previousCount )
2012-11-22 12:41:50 +00:00
Placement : : self ( ) - > reinitCascading ( 0 ) ;
2007-04-29 17:35:43 +00:00
2012-11-16 07:23:47 +00:00
resetClientAreas ( newCount ) ;
}
2009-04-06 16:09:34 +00:00
2012-11-16 07:23:47 +00:00
void Workspace : : resetClientAreas ( uint desktopCount )
{
// Make it +1, so that it can be accessed as [1..numberofdesktops]
workarea . clear ( ) ;
workarea . resize ( desktopCount + 1 ) ;
restrictedmovearea . clear ( ) ;
restrictedmovearea . resize ( desktopCount + 1 ) ;
screenarea . clear ( ) ;
updateClientArea ( 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
/**
* 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 )
{
2012-11-16 07:23:47 +00:00
if ( ( desk < 1 & & desk ! = NET : : OnAllDesktops ) | | desk > static_cast < int > ( VirtualDesktopManager : : self ( ) - > count ( ) ) )
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
2012-11-16 07:23:47 +00:00
if ( c - > isOnDesktop ( VirtualDesktopManager : : self ( ) - > current ( ) ) ) {
2011-01-30 14:34:42 +00:00
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-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 );
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
2013-02-12 23:40:11 +00:00
/**
* checks whether the X Window with the input focus is on our X11 screen
* if the window cannot be determined or inspected , resturn depends on whether there ' s actually
* more than one screen
*
* this is NOT in any way related to XRandR multiscreen
*
*/
extern bool is_multihead ; // main.cpp
bool Workspace : : isOnCurrentHead ( )
{
if ( ! is_multihead ) {
return true ;
}
Xcb : : CurrentInput currentInput ;
if ( currentInput . window ( ) = = XCB_WINDOW_NONE ) {
return ! is_multihead ;
}
Xcb : : WindowGeometry geometry ( currentInput . window ( ) ) ;
if ( geometry . isNull ( ) ) { // should not happen
return ! is_multihead ;
}
return rootWindow ( ) = = geometry - > root ;
}
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 )
{
2012-08-24 16:48:50 +00:00
screen = c - > rules ( ) - > checkScreen ( screen ) ;
2013-03-18 16:26:34 +00:00
if ( c - > isActive ( ) ) {
active_screen = screen ;
// might impact the layer of a fullscreen window
foreach ( Client * cc , clientList ( ) ) {
if ( cc - > isFullScreen ( ) & & cc - > screen ( ) = = screen ) {
updateClientLayer ( cc ) ;
}
}
}
2011-01-30 14:34:42 +00:00
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 ) ;
}
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
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 : : 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 ;
2012-11-16 07:23:47 +00:00
if ( Client * desk = findDesktop ( true , VirtualDesktopManager : : self ( ) - > current ( ) ) )
2011-01-30 14:34:42 +00:00
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
2011-04-28 09:16:27 +00:00
Outline * Workspace : : outline ( )
{
return m_outline ;
}
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
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
2013-01-10 08:55:52 +00:00
support . append ( " Version \n " ) ;
support . append ( " ======= \n " ) ;
support . append ( " KWin version: " ) ;
support . append ( KWIN_VERSION_STRING ) ;
support . append ( ' \n ' ) ;
support . append ( " KDE SC version (runtime): " ) ;
support . append ( KDE : : versionString ( ) ) ;
support . append ( ' \n ' ) ;
support . append ( " KDE SC version (compile): " ) ;
support . append ( KDE_VERSION_STRING ) ;
support . append ( ' \n ' ) ;
support . append ( " Qt Version: " ) ;
support . append ( qVersion ( ) ) ;
support . append ( " \n \n " ) ;
2012-03-04 14:13:22 +00:00
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 ' ) ;
}
2013-01-21 08:04:06 +00:00
# ifdef KWIN_BUILD_SCREENEDGES
support . append ( " \n Screen Edges \n " ) ;
support . append ( " ============ \n " ) ;
2013-01-25 09:15:00 +00:00
const QMetaObject * metaScreenEdges = ScreenEdges : : self ( ) - > metaObject ( ) ;
2013-01-21 08:04:06 +00:00
for ( int i = 0 ; i < metaScreenEdges - > propertyCount ( ) ; + + i ) {
const QMetaProperty property = metaScreenEdges - > property ( i ) ;
if ( QLatin1String ( property . name ( ) ) = = " objectName " ) {
continue ;
}
2013-01-25 09:15:00 +00:00
support . append ( QLatin1String ( property . name ( ) ) % " : " % ScreenEdges : : self ( ) - > property ( property . name ( ) ) . toString ( ) % ' \n ' ) ;
2013-01-21 08:04:06 +00:00
}
# endif
2013-01-12 08:54:24 +00:00
support . append ( " \n Screens \n " ) ;
support . append ( " ======= \n " ) ;
support . append ( " Multi-Head: " ) ;
if ( is_multihead ) {
support . append ( " yes \n " ) ;
support . append ( QString ( " Head: %1 \n " ) . arg ( screen_number ) ) ;
} else {
support . append ( " no \n " ) ;
}
support . append ( QString ( " Number of Screens: %1 \n " ) . arg ( QApplication : : desktop ( ) - > screenCount ( ) ) ) ;
for ( int i = 0 ; i < QApplication : : desktop ( ) - > screenCount ( ) ; + + i ) {
const QRect geo = QApplication : : desktop ( ) - > screenGeometry ( i ) ;
support . append ( QString ( " Screen %1 Geometry: %2,%3,%4x%5 \n " )
. arg ( i )
. arg ( geo . x ( ) )
. arg ( geo . y ( ) )
. arg ( geo . width ( ) )
. arg ( geo . height ( ) ) ) ;
}
2012-03-04 14:13:22 +00:00
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 ( ) ) {
2012-09-20 09:33:32 +00:00
case OpenGL1Compositing :
case OpenGL2Compositing :
2012-03-04 14:13:22 +00:00
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 " ) ;
}
2012-10-13 08:33:38 +00:00
support . append ( " Virtual Machine: " ) ;
if ( platform - > isVirtualMachine ( ) ) {
support . append ( " yes \n " ) ;
} else {
support . append ( " no \n " ) ;
}
2012-03-04 14:13:22 +00:00
2012-09-21 07:09:52 +00:00
if ( effects - > compositingType ( ) = = OpenGL2Compositing ) {
2012-03-04 14:13:22 +00:00
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 " ) ;
2012-08-30 06:20:26 +00:00
foreach ( const QString & effect , static_cast < EffectsHandlerImpl * > ( effects ) - > loadedEffects ( ) ) {
2012-03-04 14:13:22 +00:00
support . append ( effect % ' \n ' ) ;
}
support . append ( " \n Currently Active Effects: \n " ) ;
support . append ( " ------------------------- \n " ) ;
2012-08-30 06:20:26 +00:00
foreach ( const QString & effect , static_cast < EffectsHandlerImpl * > ( effects ) - > activeEffects ( ) ) {
2012-03-04 14:13:22 +00:00
support . append ( effect % ' \n ' ) ;
}
2012-08-11 09:24:37 +00:00
support . append ( " \n Effect Settings: \n " ) ;
support . append ( " ---------------- \n " ) ;
2012-08-30 06:20:26 +00:00
foreach ( const QString & effect , static_cast < EffectsHandlerImpl * > ( effects ) - > loadedEffects ( ) ) {
support . append ( static_cast < EffectsHandlerImpl * > ( effects ) - > supportInformation ( effect ) ) ;
2012-08-11 09:24:37 +00:00
support . append ( ' \n ' ) ;
}
2012-03-04 14:13:22 +00:00
} else {
support . append ( " Compositing is not active \n " ) ;
}
return support ;
}
2011-08-21 19:50:23 +00:00
void Workspace : : slotCompositingToggled ( )
{
// notify decorations that composition state has changed
if ( hasDecorationPlugin ( ) ) {
KDecorationFactory * factory = mgr - > factory ( ) ;
factory - > reset ( SettingCompositing ) ;
}
}
void Workspace : : slotToggleCompositing ( )
{
if ( m_compositor ) {
m_compositor - > slotToggleCompositing ( ) ;
}
}
2007-04-29 17:35:43 +00:00
} // namespace
# include "workspace.moc"