1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
22 //#define QT_CLEAN_NAMESPACE
24 #include "workspace.h"
26 #include <kapplication.h>
27 #include <kstartupinfo.h>
38 #include <kglobalaccel.h>
39 #include <QDesktopWidget>
40 #include <QToolButton>
41 #include <kactioncollection.h>
43 #include <kconfiggroup.h>
44 #include <QtDBus/QtDBus>
48 #include "popupinfo.h"
51 #include "placement.h"
52 #include "notifications.h"
55 #include "kwinadaptor.h"
56 #include "unmanaged.h"
61 #include <X11/extensions/shape.h>
62 #include <X11/keysym.h>
63 #include <X11/keysymdef.h>
64 #include <X11/cursorfont.h>
67 #include <kauthorized.h>
68 #include <ktoolinvocation.h>
69 #include <kglobalsettings.h>
74 extern int screen_number
;
76 Workspace
*Workspace::_self
= 0;
78 // Rikkus: This class is too complex. It needs splitting further.
79 // It's a nightmare to understand, especially with so few comments :(
81 // Matthias: Feel free to ask me questions about it. Feel free to add
82 // comments. I dissagree that further splittings makes it easier. 2500
83 // lines are not too much. It's the task that is complex, not the
85 Workspace::Workspace( bool restore
)
88 number_of_desktops(0),
90 active_popup_client( NULL
),
91 temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL
, false ),
92 rules_updates_disabled( false ),
94 last_active_client (0),
95 most_recently_raised (0),
97 pending_take_activity ( NULL
),
99 delayfocus_client (0),
100 force_restacking( false ),
101 showing_desktop( false ),
102 block_showing_desktop( 0 ),
103 was_user_interaction (false),
104 session_saving (false),
105 control_grab (false),
107 mouse_emulation (false),
116 client_keys ( NULL
),
117 client_keys_dialog ( NULL
),
118 client_keys_client ( NULL
),
119 disable_shortcuts_keys ( NULL
),
120 global_shortcuts_disabled( false ),
121 global_shortcuts_disabled_for_client( false ),
122 workspaceInit (true),
124 layoutOrientation(Qt::Vertical
),
129 managing_topmenus( false ),
130 topmenu_selection( NULL
),
131 topmenu_watcher( NULL
),
133 topmenu_space( NULL
),
134 set_active_client_recursion( 0 ),
135 block_stacking_updates( 0 ),
136 forced_global_mouse_grab( false ),
137 cm_selection( NULL
),
140 overlay_visible( true ),
144 (void) new KWinAdaptor( this );
145 QDBusConnection dbus
= QDBusConnection::sessionBus();
146 dbus
.registerObject("/KWin", this);
147 dbus
.connect(QString(), "/KWin", "org.kde.KWin", "reloadConfig", this, SLOT(slotReloadConfig()));
148 dbus
.connect(QString(), "/KWin", "org.kde.KWin", "reinitCompositing", this, SLOT(slotReinitCompositing()));
152 default_colormap
= DefaultColormap(display(), info
.screen() );
153 installed_colormap
= default_colormap
;
159 electric_reserved
[ i
] = 0;
160 electric_windows
[ i
] = None
;
163 connect( &temporaryRulesMessages
, SIGNAL( gotMessage( const QString
& )),
164 this, SLOT( gotTemporaryRulesMessage( const QString
& )));
165 connect( &rulesUpdatedTimer
, SIGNAL( timeout()), this, SLOT( writeWindowRules()));
167 updateXTime(); // needed for proper initialization of user_time in Client ctor
176 (void) QApplication::desktop(); // trigger creation of desktop widget
178 // call this before XSelectInput() on the root window
179 startup
= new KStartupInfo(
180 KStartupInfo::DisableKWinModule
| KStartupInfo::AnnounceSilenceChanges
, this );
182 // select windowmanager privileges
183 XSelectInput(display(), rootWindow(),
187 SubstructureRedirectMask
|
188 SubstructureNotifyMask
|
189 FocusChangeMask
| // for NotifyDetailNone
206 (unsigned char*) &data
,
210 client_keys
= new KActionCollection( this );
212 tab_box
= new TabBox( this );
213 popupinfo
= new PopupInfo( this );
217 connect( kapp
->desktop(), SIGNAL( resized( int )), SLOT( desktopResized()));
220 void Workspace::init()
222 if( options
->electricBorders() == Options::ElectricAlways
)
223 reserveElectricBorderSwitching( true );
224 updateElectricBorders();
228 // maximizedWindowCounter = 0;
230 supportWindow
= new QWidget
;
231 XLowerWindow( display(), supportWindow
->winId()); // see usage in layers.cpp
233 XSetWindowAttributes attr
;
234 attr
.override_redirect
= 1;
235 null_focus_window
= XCreateWindow( display(), rootWindow(), -1,-1, 1, 1, 0, CopyFromParent
,
236 InputOnly
, CopyFromParent
, CWOverrideRedirect
, &attr
);
237 XMapWindow(display(), null_focus_window
);
239 unsigned long protocols
[ 5 ] =
242 NET::SupportingWMCheck
|
244 NET::ClientListStacking
|
245 NET::DesktopGeometry
|
246 NET::NumberOfDesktops
|
247 NET::CurrentDesktop
|
258 NET::WMIconGeometry
|
262 NET::WMFrameExtents
|
275 // No compositing window types here unless we support them also as managed window types
279 // NET::Sticky | // large desktops not supported (and probably never will be)
285 // NET::StaysOnTop | the same like KeepAbove
290 NET::DemandsAttention
|
295 NET::WM2AllowedActions
|
296 NET::WM2RestackWindow
|
297 NET::WM2MoveResizeWindow
|
298 NET::WM2ExtendedStrut
|
299 NET::WM2KDETemporaryRules
|
300 NET::WM2ShowingDesktop
|
301 NET::WM2DesktopLayout
|
302 NET::WM2FullPlacement
|
307 NET::ActionMinimize
|
309 // NET::ActionStick | // Sticky state is not supported
311 NET::ActionMaxHoriz
|
312 NET::ActionFullScreen
|
313 NET::ActionChangeDesktop
|
320 rootInfo
= new RootInfo( this, display(), supportWindow
->winId(), "KWin",
321 protocols
, 5, info
.screen() );
323 loadDesktopSettings();
324 updateDesktopLayout();
325 // extra NETRootInfo instance in Client mode is needed to get the values of the properties
326 NETRootInfo
client_info( display(), NET::ActiveWindow
| NET::CurrentDesktop
);
328 if( !kapp
->isSessionRestored())
329 initial_desktop
= client_info
.currentDesktop();
332 KConfigGroup
group( kapp
->sessionConfig(), "Session" );
333 initial_desktop
= group
.readEntry( "desktop", 1 );
335 if( !setCurrentDesktop( initial_desktop
))
336 setCurrentDesktop( 1 );
338 // now we know how many desktops we'll, thus, we initialize the positioning object
339 initPositioning
= new Placement(this);
341 reconfigureTimer
.setSingleShot( true );
342 updateToolWindowsTimer
.setSingleShot( true );
344 connect(&reconfigureTimer
, SIGNAL(timeout()), this,
345 SLOT(slotReconfigure()));
346 connect( &updateToolWindowsTimer
, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows()));
347 connect( &compositeTimer
, SIGNAL( timeout()), SLOT( performCompositing()));
349 connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this,
350 SLOT(slotReconfigure()));
351 connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this,
352 SLOT(slotSettingsChanged(int)));
353 connect(KGlobalSettings::self(), SIGNAL(blockShortcuts(int)), this,
354 SLOT(slotBlockShortcuts(int)));
356 active_client
= NULL
;
357 rootInfo
->setActiveWindow( None
);
359 if( !kapp
->isSessionRestored())
360 ++block_focus
; // because it will be set below
363 sprintf( nm
, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( display()));
364 Atom topmenu_atom
= XInternAtom( display(), nm
, False
);
365 topmenu_selection
= new KSelectionOwner( topmenu_atom
);
366 topmenu_watcher
= new KSelectionWatcher( topmenu_atom
);
367 // TODO grabXServer(); - where exactly put this? topmenu selection claiming down belong must be before
369 { // begin updates blocker block
370 StackingUpdatesBlocker
blocker( this );
372 if( options
->topMenuEnabled() && topmenu_selection
->claim( false ))
373 setupTopMenuHandling(); // this can call updateStackingOrder()
375 lostTopMenuSelection();
377 unsigned int i
, nwins
;
378 Window root_return
, parent_return
, *wins
;
379 XQueryTree(display(), rootWindow(), &root_return
, &parent_return
, &wins
, &nwins
);
380 for (i
= 0; i
< nwins
; i
++)
382 XWindowAttributes attr
;
383 XGetWindowAttributes(display(), wins
[i
], &attr
);
384 if (attr
.override_redirect
)
386 createUnmanaged( wins
[ i
] );
389 if( topmenu_space
&& topmenu_space
->winId() == wins
[ i
] )
391 if (attr
.map_state
!= IsUnmapped
)
392 createClient( wins
[i
], true );
395 XFree((void *) wins
);
396 // propagate clients, will really happen at the end of the updates blocker block
397 updateStackingOrder( true );
401 // NETWM spec says we have to set it to (0,0) if we don't support it
402 NETPoint
* viewports
= new NETPoint
[ number_of_desktops
];
403 rootInfo
->setDesktopViewport( number_of_desktops
, *viewports
);
405 QRect geom
= QApplication::desktop()->geometry();
406 NETSize desktop_geometry
;
407 desktop_geometry
.width
= geom
.width();
408 desktop_geometry
.height
= geom
.height();
409 rootInfo
->setDesktopGeometry( -1, desktop_geometry
);
410 setShowingDesktop( false );
412 } // end updates blocker block
414 Client
* new_active_client
= NULL
;
415 if( !kapp
->isSessionRestored())
418 new_active_client
= findClient( WindowMatchPredicate( client_info
.activeWindow()));
420 if( new_active_client
== NULL
421 && activeClient() == NULL
&& should_get_focus
.count() == 0 ) // no client activated in manage()
423 if( new_active_client
== NULL
)
424 new_active_client
= topClientOnDesktop( currentDesktop());
425 if( new_active_client
== NULL
&& !desktops
.isEmpty() )
426 new_active_client
= findDesktop( true, currentDesktop());
428 if( new_active_client
!= NULL
)
429 activateClient( new_active_client
);
430 // SELI TODO this won't work with unreasonable focus policies,
431 // and maybe in rare cases also if the selected client doesn't
433 workspaceInit
= false;
434 // TODO ungrabXServer()
437 Workspace::~Workspace()
440 blockStackingUpdates( true );
441 // TODO grabXServer();
442 // use stacking_order, so that kwin --replace keeps stacking order
443 for( ClientList::ConstIterator it
= stacking_order
.begin();
444 it
!= stacking_order
.end();
447 // only release the window
448 (*it
)->releaseWindow( true );
449 // No removeClient() is called, it does more than just removing.
450 // However, remove from some lists to e.g. prevent performTransiencyCheck()
452 clients
.removeAll( *it
);
453 desktops
.removeAll( *it
);
455 for( UnmanagedList::ConstIterator it
= unmanaged
.begin();
456 it
!= unmanaged
.end();
462 XDeleteProperty(display(), rootWindow(), atoms
->kwin_running
);
465 KGlobal::config()->sync();
468 delete supportWindow
;
473 delete initPositioning
;
474 delete topmenu_watcher
;
475 delete topmenu_selection
;
476 delete topmenu_space
;
477 delete client_keys_dialog
;
478 while( !rules
.isEmpty())
480 delete rules
.front();
483 foreach ( SessionInfo
* s
, session
)
485 XDestroyWindow( display(), null_focus_window
);
486 // TODO ungrabXServer();
490 Client
* Workspace::createClient( Window w
, bool is_mapped
)
492 StackingUpdatesBlocker
blocker( this );
493 Client
* c
= new Client( this );
494 if( !c
->manage( w
, is_mapped
))
496 Client::deleteClient( c
, Allowed
);
499 addClient( c
, Allowed
);
501 scene
->windowAdded( c
);
503 static_cast<EffectsHandlerImpl
*>(effects
)->windowAdded( c
->effectWindow());
507 Unmanaged
* Workspace::createUnmanaged( Window w
)
511 Unmanaged
* c
= new Unmanaged( this );
514 Unmanaged::deleteUnmanaged( c
, Allowed
);
517 addUnmanaged( c
, Allowed
);
519 scene
->windowAdded( c
);
521 static_cast<EffectsHandlerImpl
*>(effects
)->windowAdded( c
->effectWindow());
525 void Workspace::addClient( Client
* c
, allowed_t
)
527 Group
* grp
= findGroup( c
->window());
531 if ( c
->isDesktop() )
533 desktops
.append( c
);
534 if( active_client
== NULL
&& should_get_focus
.isEmpty() && c
->isOnCurrentDesktop())
535 requestFocus( c
); // CHECKME? make sure desktop is active after startup if there's no other window active
539 updateFocusChains( c
, FocusChainUpdate
); // add to focus chain if not already there
542 if( !unconstrained_stacking_order
.contains( c
))
543 unconstrained_stacking_order
.append( c
); // raise if it hasn't got any stacking position yet
544 if( !stacking_order
.contains( c
)) // it'll be updated later, and updateToolWindows() requires
545 stacking_order
.append( c
); // c to be in stacking_order
548 updateClientArea(); // this cannot be in manage(), because the client got added only now
549 updateClientLayer( c
);
553 // if there's no active client, make this desktop the active one
554 if( activeClient() == NULL
&& should_get_focus
.count() == 0 )
555 activateClient( findDesktop( true, currentDesktop()));
557 c
->checkActiveModal();
558 checkTransients( c
->window()); // SELI does this really belong here?
559 updateStackingOrder( true ); // propagate new client
560 if( c
->isUtility() || c
->isMenu() || c
->isToolbar())
561 updateToolWindows( true );
562 checkNonExistentClients();
564 tab_box
->reset( true );
567 void Workspace::addUnmanaged( Unmanaged
* c
, allowed_t
)
569 unmanaged
.append( c
);
570 unmanaged_stacking_order
.append( c
);
574 Destroys the client \a c
576 void Workspace::removeClient( Client
* c
, allowed_t
)
578 if (c
== active_popup_client
)
581 if( client_keys_client
== c
)
582 setupWindowShortcutDone( false );
583 if( !c
->shortcut().isEmpty())
584 c
->setShortcut( QString() ); // remove from client_keys
587 Notify::raise( Notify::TransDelete
);
588 if( c
->isNormalWindow())
589 Notify::raise( Notify::Delete
);
593 if( tab_box
->currentClient() == c
)
594 tab_box
->nextPrev( true );
597 Q_ASSERT( clients
.contains( c
) || desktops
.contains( c
));
598 clients
.removeAll( c
);
599 desktops
.removeAll( c
);
600 unconstrained_stacking_order
.removeAll( c
);
601 stacking_order
.removeAll( c
);
603 i
<= numberOfDesktops();
605 focus_chain
[ i
].removeAll( c
);
606 global_focus_chain
.removeAll( c
);
607 attention_chain
.removeAll( c
);
608 showing_desktop_clients
.removeAll( c
);
611 Group
* group
= findGroup( c
->window());
615 if ( c
== most_recently_raised
)
616 most_recently_raised
= 0;
617 should_get_focus
.removeAll( c
);
618 Q_ASSERT( c
!= active_client
);
619 if ( c
== last_active_client
)
620 last_active_client
= 0;
621 if( c
== pending_take_activity
)
622 pending_take_activity
= NULL
;
623 if( c
== delayfocus_client
)
626 updateStackingOrder( true );
629 tab_box
->reset( true );
634 void Workspace::removeUnmanaged( Unmanaged
* c
, allowed_t
)
636 assert( unmanaged
.contains( c
));
637 unmanaged
.removeAll( c
);
638 unmanaged_stacking_order
.removeAll( c
);
641 void Workspace::addDeleted( Deleted
* c
, allowed_t
)
643 assert( !deleted
.contains( c
));
647 void Workspace::removeDeleted( Deleted
* c
, allowed_t
)
649 assert( deleted
.contains( c
));
651 scene
->windowDeleted( c
);
653 static_cast<EffectsHandlerImpl
*>(effects
)->windowDeleted( c
->effectWindow());
654 deleted
.removeAll( c
);
657 void Workspace::updateFocusChains( Client
* c
, FocusChainChange change
)
659 if( !c
->wantsTabFocus()) // doesn't want tab focus, remove
662 i
<= numberOfDesktops();
664 focus_chain
[i
].removeAll(c
);
665 global_focus_chain
.removeAll( c
);
668 if(c
->desktop() == NET::OnAllDesktops
)
669 { //now on all desktops, add it to focus_chains it is not already in
670 for( int i
=1; i
<= numberOfDesktops(); i
++)
671 { // making first/last works only on current desktop, don't affect all desktops
672 if( i
== currentDesktop()
673 && ( change
== FocusChainMakeFirst
|| change
== FocusChainMakeLast
))
675 focus_chain
[ i
].removeAll( c
);
676 if( change
== FocusChainMakeFirst
)
677 focus_chain
[ i
].append( c
);
679 focus_chain
[ i
].prepend( c
);
681 else if( !focus_chain
[ i
].contains( c
))
682 { // add it after the active one
683 if( active_client
!= NULL
&& active_client
!= c
684 && !focus_chain
[ i
].isEmpty() && focus_chain
[ i
].last() == active_client
)
685 focus_chain
[ i
].insert( focus_chain
[ i
].size() - 1, c
);
687 focus_chain
[ i
].append( c
); // otherwise add as the first one
691 else //now only on desktop, remove it anywhere else
693 for( int i
=1; i
<= numberOfDesktops(); i
++)
695 if( i
== c
->desktop())
697 if( change
== FocusChainMakeFirst
)
699 focus_chain
[ i
].removeAll( c
);
700 focus_chain
[ i
].append( c
);
702 else if( change
== FocusChainMakeLast
)
704 focus_chain
[ i
].removeAll( c
);
705 focus_chain
[ i
].prepend( c
);
707 else if( !focus_chain
[ i
].contains( c
))
708 { // add it after the active one
709 if( active_client
!= NULL
&& active_client
!= c
710 && !focus_chain
[ i
].isEmpty() && focus_chain
[ i
].last() == active_client
)
711 focus_chain
[ i
].insert( focus_chain
[ i
].size() - 1, c
);
713 focus_chain
[ i
].append( c
); // otherwise add as the first one
717 focus_chain
[ i
].removeAll( c
);
720 if( change
== FocusChainMakeFirst
)
722 global_focus_chain
.removeAll( c
);
723 global_focus_chain
.append( c
);
725 else if( change
== FocusChainMakeLast
)
727 global_focus_chain
.removeAll( c
);
728 global_focus_chain
.prepend( c
);
730 else if( !global_focus_chain
.contains( c
))
731 { // add it after the active one
732 if( active_client
!= NULL
&& active_client
!= c
733 && !global_focus_chain
.isEmpty() && global_focus_chain
.last() == active_client
)
734 global_focus_chain
.insert( global_focus_chain
.size() - 1, c
);
736 global_focus_chain
.append( c
); // otherwise add as the first one
740 void Workspace::updateCurrentTopMenu()
742 if( !managingTopMenus())
744 // toplevel menubar handling
746 bool block_desktop_menubar
= false;
749 // show the new menu bar first...
750 Client
* menu_client
= active_client
;
753 if( menu_client
->isFullScreen())
754 block_desktop_menubar
= true;
755 for( ClientList::ConstIterator it
= menu_client
->transients().begin();
756 it
!= menu_client
->transients().end();
758 if( (*it
)->isTopMenu())
763 if( menubar
!= NULL
|| !menu_client
->isTransient())
765 if( menu_client
->isModal() || menu_client
->transientFor() == NULL
)
766 break; // don't use mainwindow's menu if this is modal or group transient
767 menu_client
= menu_client
->transientFor();
770 { // try to find any topmenu from the application (#72113)
771 for( ClientList::ConstIterator it
= active_client
->group()->members().begin();
772 it
!= active_client
->group()->members().end();
774 if( (*it
)->isTopMenu())
781 if( !menubar
&& !block_desktop_menubar
&& options
->desktopTopMenu())
783 // Find the menubar of the desktop
784 Client
* desktop
= findDesktop( true, currentDesktop());
785 if( desktop
!= NULL
)
787 for( ClientList::ConstIterator it
= desktop
->transients().begin();
788 it
!= desktop
->transients().end();
790 if( (*it
)->isTopMenu())
796 // TODO to be cleaned app with window grouping
797 // Without qt-copy patch #0009, the topmenu and desktop are not in the same group,
798 // thus the topmenu is not transient for it :-/.
799 if( menubar
== NULL
)
801 for( ClientList::ConstIterator it
= topmenus
.begin();
802 it
!= topmenus
.end();
804 if( (*it
)->wasOriginallyGroupTransient()) // kdesktop's topmenu has WM_TRANSIENT_FOR
805 { // set pointing to the root window
806 menubar
= *it
; // to recognize it here
807 break; // Also, with the xroot hack in kdesktop,
808 } // there's no NET::Desktop window to be transient for
812 // kDebug() << "CURRENT TOPMENU:" << menubar << ":" << active_client;
815 if( active_client
&& !menubar
->isOnDesktop( active_client
->desktop()))
816 menubar
->setDesktop( active_client
->desktop());
817 menubar
->hideClient( false );
818 topmenu_space
->hide();
819 // make it appear like it's been raised manually - it's in the Dock layer anyway,
820 // and not raising it could mess up stacking order of topmenus within one application,
821 // and thus break raising of mainclients in raiseClient()
822 unconstrained_stacking_order
.removeAll( menubar
);
823 unconstrained_stacking_order
.append( menubar
);
825 else if( !block_desktop_menubar
)
826 { // no topmenu active - show the space window, so that there's not empty space
827 topmenu_space
->show();
830 // ... then hide the other ones. Avoids flickers.
831 for ( ClientList::ConstIterator it
= clients
.begin(); it
!= clients
.end(); ++it
)
833 if( (*it
)->isTopMenu() && (*it
) != menubar
)
834 (*it
)->hideClient( true );
839 void Workspace::updateToolWindows( bool also_hide
)
841 // TODO what if Client's transiency/group changes? should this be called too? (I'm paranoid, am I not?)
842 if( !options
->hideUtilityWindowsForInactive
)
844 for( ClientList::ConstIterator it
= clients
.begin();
847 (*it
)->hideClient( false );
850 const Group
* group
= NULL
;
851 const Client
* client
= active_client
;
852 // Go up in transiency hiearchy, if the top is found, only tool transients for the top mainwindow
853 // will be shown; if a group transient is group, all tools in the group will be shown
854 while( client
!= NULL
)
856 if( !client
->isTransient())
858 if( client
->groupTransient())
860 group
= client
->group();
863 client
= client
->transientFor();
865 // use stacking order only to reduce flicker, it doesn't matter if block_stacking_updates == 0,
866 // i.e. if it's not up to date
868 // SELI but maybe it should - what if a new client has been added that's not in stacking order yet?
869 ClientList to_show
, to_hide
;
870 for( ClientList::ConstIterator it
= stacking_order
.begin();
871 it
!= stacking_order
.end();
874 if( (*it
)->isUtility() || (*it
)->isMenu() || (*it
)->isToolbar())
877 if( !(*it
)->isTransient())
879 if( (*it
)->group()->members().count() == 1 ) // has its own group, keep always visible
881 else if( client
!= NULL
&& (*it
)->group() == client
->group())
888 if( group
!= NULL
&& (*it
)->group() == group
)
890 else if( client
!= NULL
&& client
->hasTransient( (*it
), true ))
895 if( !show
&& also_hide
)
897 const ClientList mainclients
= (*it
)->mainClients();
898 // don't hide utility windows which are standalone(?) or
899 // have e.g. kicker as mainwindow
900 if( mainclients
.isEmpty())
902 for( ClientList::ConstIterator it2
= mainclients
.begin();
903 it2
!= mainclients
.end();
906 if( (*it2
)->isSpecialWindow())
910 to_hide
.append( *it
);
913 to_show
.append( *it
);
915 } // first show new ones, then hide
916 for( int i
= to_show
.size() - 1;
919 // TODO since this is in stacking order, the order of taskbar entries changes :(
920 to_show
.at( i
)->hideClient( false );
923 for( ClientList::ConstIterator it
= to_hide
.begin();
925 ++it
) // from bottommost
926 (*it
)->hideClient( true );
927 updateToolWindowsTimer
.stop();
929 else // setActiveClient() is after called with NULL client, quickly followed
930 { // by setting a new client, which would result in flickering
931 updateToolWindowsTimer
.start( 50 );
935 void Workspace::slotUpdateToolWindows()
937 updateToolWindows( true );
941 Updates the current colormap according to the currently active client
943 void Workspace::updateColormap()
945 Colormap cmap
= default_colormap
;
946 if ( activeClient() && activeClient()->colormap() != None
)
947 cmap
= activeClient()->colormap();
948 if ( cmap
!= installed_colormap
)
950 XInstallColormap(display(), cmap
);
951 installed_colormap
= cmap
;
955 void Workspace::slotReloadConfig()
960 void Workspace::reconfigure()
962 reconfigureTimer
.start( 200 );
966 void Workspace::slotSettingsChanged(int category
)
968 kDebug(1212) << "Workspace::slotSettingsChanged()";
969 if( category
== KGlobalSettings::SETTINGS_SHORTCUTS
)
976 KWIN_PROCEDURE( CheckBorderSizesProcedure
, Client
, cl
->checkBorderSizes() );
978 void Workspace::slotReconfigure()
980 kDebug(1212) << "Workspace::slotReconfigure()";
981 reconfigureTimer
.stop();
983 if( options
->electricBorders() == Options::ElectricAlways
)
984 reserveElectricBorderSwitching( false );
986 KGlobal::config()->reparseConfiguration();
987 unsigned long changed
= options
->updateSettings();
988 tab_box
->reconfigure();
989 popupinfo
->reconfigure();
990 initPositioning
->reinitCascading( 0 );
992 forEachClient( CheckIgnoreFocusStealingProcedure());
993 updateToolWindows( true );
995 if( mgr
->reset( changed
))
996 { // decorations need to be recreated
997 #if 0 // This actually seems to make things worse now
999 curtain
.setBackgroundMode( NoBackground
);
1000 curtain
.setGeometry( QApplication::desktop()->geometry() );
1003 for( ClientList::ConstIterator it
= clients
.begin();
1004 it
!= clients
.end();
1007 (*it
)->updateDecoration( true, true );
1009 mgr
->destroyPreviousPlugin();
1013 forEachClient( CheckBorderSizesProcedure());
1016 if( options
->electricBorders() == Options::ElectricAlways
)
1017 reserveElectricBorderSwitching( true );
1018 updateElectricBorders();
1020 if( options
->topMenuEnabled() && !managingTopMenus())
1022 if( topmenu_selection
->claim( false ))
1023 setupTopMenuHandling();
1025 lostTopMenuSelection();
1027 else if( !options
->topMenuEnabled() && managingTopMenus())
1029 topmenu_selection
->release();
1030 lostTopMenuSelection();
1032 topmenu_height
= 0; // invalidate used menu height
1033 if( managingTopMenus())
1035 updateTopMenuGeometry();
1036 updateCurrentTopMenu();
1039 if( options
->useCompositing
)
1042 if( effects
) // setupCompositing() may fail
1043 effects
->reconfigure();
1047 finishCompositing();
1050 for( ClientList::Iterator it
= clients
.begin();
1051 it
!= clients
.end();
1054 (*it
)->setupWindowRules( true );
1055 (*it
)->applyWindowRules();
1056 discardUsedWindowRules( *it
, false );
1060 void Workspace::slotReinitCompositing()
1062 // Reparse config. Config options will be reloaded by setupCompositing()
1063 KGlobal::config()->reparseConfiguration();
1064 options
->updateSettings();
1066 // Stop any current compositing
1067 finishCompositing();
1068 // And start new one
1070 if( effects
) // setupCompositing() may fail
1071 effects
->reconfigure();
1074 void Workspace::loadDesktopSettings()
1076 KSharedConfig::Ptr c
= KGlobal::config();
1078 if (screen_number
== 0)
1079 groupname
= "Desktops";
1081 groupname
.sprintf("Desktops-screen-%d", screen_number
);
1082 KConfigGroup
group(c
,groupname
);
1084 int n
= group
.readEntry("Number", 4);
1085 number_of_desktops
= n
;
1087 workarea
= new QRect
[ n
+ 1 ];
1090 rootInfo
->setNumberOfDesktops( number_of_desktops
);
1091 desktop_focus_chain
.resize( n
);
1092 // make it +1, so that it can be accessed as [1..numberofdesktops]
1093 focus_chain
.resize( n
+ 1 );
1094 for(int i
= 1; i
<= n
; i
++)
1096 QString s
= group
.readEntry(QString("Name_%1").arg(i
),
1097 i18n("Desktop %1", i
));
1098 rootInfo
->setDesktopName( i
, s
.toUtf8().data() );
1099 desktop_focus_chain
[i
-1] = i
;
1103 void Workspace::saveDesktopSettings()
1105 KSharedConfig::Ptr c
= KGlobal::config();
1107 if (screen_number
== 0)
1108 groupname
= "Desktops";
1110 groupname
.sprintf("Desktops-screen-%d", screen_number
);
1111 KConfigGroup
group(c
,groupname
);
1113 group
.writeEntry("Number", number_of_desktops
);
1114 for(int i
= 1; i
<= number_of_desktops
; i
++)
1116 QString s
= desktopName( i
);
1117 QString defaultvalue
= i18n("Desktop %1", i
);
1121 rootInfo
->setDesktopName( i
, s
.toUtf8().data() );
1124 if (s
!= defaultvalue
)
1126 group
.writeEntry( QString("Name_%1").arg(i
), s
);
1130 QString currentvalue
= group
.readEntry(QString("Name_%1").arg(i
), QString());
1131 if (currentvalue
!= defaultvalue
)
1132 group
.writeEntry( QString("Name_%1").arg(i
), "" );
1137 QStringList
Workspace::configModules(bool controlCenter
)
1140 args
<< "kwindecoration";
1142 args
<< "kwinoptions";
1143 else if (KAuthorized::authorizeControlModule("kde-kwinoptions.desktop"))
1144 args
<< "kwinactions" << "kwinfocus" << "kwinmoving" << "kwinadvanced" << "kwinrules" << "kwincompositing";
1148 void Workspace::configureWM()
1150 KToolInvocation::kdeinitExec( "kcmshell4", configModules(false) );
1154 avoids managing a window with title \a title
1156 void Workspace::doNotManage( const QString
&title
)
1158 doNotManageList
.append( title
);
1162 Hack for java applets
1164 bool Workspace::isNotManaged( const QString
& title
)
1166 for ( QStringList::Iterator it
= doNotManageList
.begin(); it
!= doNotManageList
.end(); ++it
)
1169 if (r
.indexIn(title
) != -1)
1171 doNotManageList
.erase( it
);
1179 Refreshes all the client windows
1181 void Workspace::refresh()
1184 w
.setGeometry( QApplication::desktop()->geometry() );
1187 QApplication::flush();
1191 During virt. desktop switching, desktop areas covered by windows that are
1192 going to be hidden are first obscured by new windows with no background
1193 ( i.e. transparent ) placed right below the windows. These invisible windows
1194 are removed after the switch is complete.
1195 Reduces desktop ( wallpaper ) repaints during desktop switching
1197 class ObscuringWindows
1200 ~ObscuringWindows();
1201 void create( Client
* c
);
1203 QList
<Window
> obscuring_windows
;
1204 static QList
<Window
>* cached
;
1205 static unsigned int max_cache_size
;
1208 QList
<Window
>* ObscuringWindows::cached
= 0;
1209 unsigned int ObscuringWindows::max_cache_size
= 0;
1211 void ObscuringWindows::create( Client
* c
)
1213 if( compositing()) // not needed with compositing
1216 cached
= new QList
<Window
>;
1218 XWindowChanges chngs
;
1219 int mask
= CWSibling
| CWStackMode
;
1220 if( cached
->count() > 0 )
1222 cached
->removeAll( obs_win
= cached
->first());
1225 chngs
.width
= c
->width();
1226 chngs
.height
= c
->height();
1227 mask
|= CWX
| CWY
| CWWidth
| CWHeight
;
1231 XSetWindowAttributes a
;
1232 a
.background_pixmap
= None
;
1233 a
.override_redirect
= True
;
1234 obs_win
= XCreateWindow( display(), rootWindow(), c
->x(), c
->y(),
1235 c
->width(), c
->height(), 0, CopyFromParent
, InputOutput
,
1236 CopyFromParent
, CWBackPixmap
| CWOverrideRedirect
, &a
);
1238 chngs
.sibling
= c
->frameId();
1239 chngs
.stack_mode
= Below
;
1240 XConfigureWindow( display(), obs_win
, mask
, &chngs
);
1241 XMapWindow( display(), obs_win
);
1242 obscuring_windows
.append( obs_win
);
1245 ObscuringWindows::~ObscuringWindows()
1247 max_cache_size
= qMax( ( int )max_cache_size
, obscuring_windows
.count() + 4 ) - 1;
1248 for( QList
<Window
>::ConstIterator it
= obscuring_windows
.begin();
1249 it
!= obscuring_windows
.end();
1252 XUnmapWindow( display(), *it
);
1253 if( cached
->count() < ( int )max_cache_size
)
1254 cached
->prepend( *it
);
1256 XDestroyWindow( display(), *it
);
1262 Sets the current desktop to \a new_desktop
1264 Shows/Hides windows according to the stacking order and finally
1265 propages the new desktop to the world
1267 bool Workspace::setCurrentDesktop( int new_desktop
)
1269 if (new_desktop
< 1 || new_desktop
> number_of_desktops
)
1274 // TODO Q_ASSERT( block_stacking_updates == 0 ); // make sure stacking_order is up to date
1275 StackingUpdatesBlocker
blocker( this );
1277 int old_desktop
= current_desktop
;
1278 if (new_desktop
!= current_desktop
)
1280 ++block_showing_desktop
;
1282 optimized Desktop switching: unmapping done from back to front
1283 mapping done from front to back => less exposure events
1285 Notify::raise((Notify::Event
) (Notify::DesktopChange
+new_desktop
));
1287 ObscuringWindows obs_wins
;
1289 current_desktop
= new_desktop
; // change the desktop (so that Client::updateVisibility() works)
1291 for ( ClientList::ConstIterator it
= stacking_order
.begin(); it
!= stacking_order
.end(); ++it
)
1292 if ( !(*it
)->isOnDesktop( new_desktop
) && (*it
) != movingClient
)
1294 if( (*it
)->isShown( true ) && (*it
)->isOnDesktop( old_desktop
))
1295 obs_wins
.create( *it
);
1296 (*it
)->updateVisibility();
1299 rootInfo
->setCurrentDesktop( current_desktop
); // now propagate the change, after hiding, before showing
1301 if( movingClient
&& !movingClient
->isOnDesktop( new_desktop
))
1302 movingClient
->setDesktop( new_desktop
);
1304 for( int i
= stacking_order
.size() - 1; i
>= 0 ; --i
)
1305 if ( stacking_order
.at( i
)->isOnDesktop( new_desktop
) )
1306 stacking_order
.at( i
)->updateVisibility();
1308 --block_showing_desktop
;
1309 if( showingDesktop()) // do this only after desktop change to avoid flicker
1310 resetShowingDesktop( false );
1313 // restore the focus on this desktop
1317 if ( options
->focusPolicyIsReasonable())
1319 // Search in focus chain
1320 if ( movingClient
!= NULL
&& active_client
== movingClient
1321 && focus_chain
[currentDesktop()].contains( active_client
)
1322 && active_client
->isShown( true ) && active_client
->isOnCurrentDesktop())
1324 c
= active_client
; // the requestFocus below will fail, as the client is already active
1328 for( int i
= focus_chain
[ currentDesktop() ].size() - 1;
1332 if( focus_chain
[ currentDesktop() ].at( i
)->isShown( false )
1333 && focus_chain
[ currentDesktop() ].at( i
)->isOnCurrentDesktop())
1335 c
= focus_chain
[ currentDesktop() ].at( i
);
1342 //if "unreasonable focus policy"
1343 // and active_client is on_all_desktops and under mouse (hence == old_active_client),
1344 // conserve focus (thanks to Volker Schatz <V.Schatz at thphys.uni-heidelberg.de>)
1345 else if( active_client
&& active_client
->isShown( true ) && active_client
->isOnCurrentDesktop())
1348 if( c
== NULL
&& !desktops
.isEmpty())
1349 c
= findDesktop( true, currentDesktop());
1351 if( c
!= active_client
)
1352 setActiveClient( NULL
, Allowed
);
1356 else if( !desktops
.isEmpty() )
1357 requestFocus( findDesktop( true, currentDesktop()));
1361 updateCurrentTopMenu();
1363 // Update focus chain:
1364 // If input: chain = { 1, 2, 3, 4 } and currentDesktop() = 3,
1365 // Output: chain = { 3, 1, 2, 4 }.
1366 // kDebug(1212) << QString("Switching to desktop #%1, at focus_chain index %2\n")
1367 // .arg(currentDesktop()).arg(desktop_focus_chain.find( currentDesktop() ));
1368 for( int i
= desktop_focus_chain
.indexOf( currentDesktop() ); i
> 0; i
-- )
1369 desktop_focus_chain
[i
] = desktop_focus_chain
[i
-1];
1370 desktop_focus_chain
[0] = currentDesktop();
1372 // QString s = "desktop_focus_chain[] = { ";
1373 // for( uint i = 0; i < desktop_focus_chain.size(); i++ )
1374 // s += QString::number(desktop_focus_chain[i]) + ", ";
1375 // kDebug(1212) << s << "}\n";
1377 if( old_desktop
!= 0 ) // not for the very first time
1378 popupinfo
->showInfo( desktopName(currentDesktop()) );
1380 if( effects
!= NULL
&& old_desktop
!= 0 && old_desktop
!= new_desktop
)
1381 static_cast<EffectsHandlerImpl
*>(effects
)->desktopChanged( old_desktop
);
1388 // called only from DCOP
1389 void Workspace::nextDesktop()
1391 int desktop
= currentDesktop() + 1;
1392 setCurrentDesktop(desktop
> numberOfDesktops() ? 1 : desktop
);
1395 // called only from DCOP
1396 void Workspace::previousDesktop()
1398 int desktop
= currentDesktop() - 1;
1399 setCurrentDesktop(desktop
> 0 ? desktop
: numberOfDesktops());
1402 int Workspace::desktopToRight( int desktop
, bool wrap
) const
1405 Qt::Orientation orientation
;
1406 calcDesktopLayout( &x
, &y
, &orientation
);
1408 if (orientation
== Qt::Vertical
)
1411 if ( dt
>= numberOfDesktops() )
1414 dt
-= numberOfDesktops();
1421 int d
= (dt
% x
) + 1;
1429 dt
= dt
- (dt
% x
) + d
;
1434 int Workspace::desktopToLeft( int desktop
, bool wrap
) const
1437 Qt::Orientation orientation
;
1438 calcDesktopLayout( &x
, &y
, &orientation
);
1440 if (orientation
== Qt::Vertical
)
1446 dt
+= numberOfDesktops();
1453 int d
= (dt
% x
) - 1;
1461 dt
= dt
- (dt
% x
) + d
;
1466 int Workspace::desktopUp( int desktop
, bool wrap
) const
1469 Qt::Orientation orientation
;
1470 calcDesktopLayout( &x
, &y
, &orientation
);
1472 if (orientation
== Qt::Horizontal
)
1478 dt
+= numberOfDesktops();
1485 int d
= (dt
% y
) - 1;
1493 dt
= dt
- (dt
% y
) + d
;
1498 int Workspace::desktopDown( int desktop
, bool wrap
) const
1501 Qt::Orientation orientation
;
1502 calcDesktopLayout( &x
, &y
, &orientation
);
1504 if (orientation
== Qt::Horizontal
)
1507 if ( dt
>= numberOfDesktops() )
1510 dt
-= numberOfDesktops();
1517 int d
= (dt
% y
) + 1;
1525 dt
= dt
- (dt
% y
) + d
;
1532 Sets the number of virtual desktops to \a n
1534 void Workspace::setNumberOfDesktops( int n
)
1536 if ( n
== number_of_desktops
)
1538 int old_number_of_desktops
= number_of_desktops
;
1539 number_of_desktops
= n
;
1541 if( currentDesktop() > numberOfDesktops())
1542 setCurrentDesktop( numberOfDesktops());
1544 // if increasing the number, do the resizing now,
1545 // otherwise after the moving of windows to still existing desktops
1546 if( old_number_of_desktops
< number_of_desktops
)
1548 rootInfo
->setNumberOfDesktops( number_of_desktops
);
1549 NETPoint
* viewports
= new NETPoint
[ number_of_desktops
];
1550 rootInfo
->setDesktopViewport( number_of_desktops
, *viewports
);
1552 updateClientArea( true );
1553 focus_chain
.resize( number_of_desktops
+ 1 );
1556 // if the number of desktops decreased, move all
1557 // windows that would be hidden to the last visible desktop
1558 if( old_number_of_desktops
> number_of_desktops
)
1560 for( ClientList::ConstIterator it
= clients
.begin();
1561 it
!= clients
.end();
1564 if( !(*it
)->isOnAllDesktops() && (*it
)->desktop() > numberOfDesktops())
1565 sendClientToDesktop( *it
, numberOfDesktops(), true );
1568 if( old_number_of_desktops
> number_of_desktops
)
1570 rootInfo
->setNumberOfDesktops( number_of_desktops
);
1571 NETPoint
* viewports
= new NETPoint
[ number_of_desktops
];
1572 rootInfo
->setDesktopViewport( number_of_desktops
, *viewports
);
1574 updateClientArea( true );
1575 focus_chain
.resize( number_of_desktops
+ 1 );
1578 saveDesktopSettings();
1580 // Resize and reset the desktop focus chain.
1581 desktop_focus_chain
.resize( n
);
1582 for( int i
= 0; i
< (int)desktop_focus_chain
.size(); i
++ )
1583 desktop_focus_chain
[i
] = i
+1;
1587 Sends client \a c to desktop \a desk.
1589 Takes care of transients as well.
1591 void Workspace::sendClientToDesktop( Client
* c
, int desk
, bool dont_activate
)
1593 bool was_on_desktop
= c
->isOnDesktop( desk
) || c
->isOnAllDesktops();
1594 c
->setDesktop( desk
);
1595 if ( c
->desktop() != desk
) // no change or desktop forced
1597 desk
= c
->desktop(); // Client did range checking
1599 if ( c
->isOnDesktop( currentDesktop() ) )
1601 if ( c
->wantsTabFocus() && options
->focusPolicyIsReasonable()
1602 && !was_on_desktop
// for stickyness changes
1606 restackClientUnderActive( c
);
1613 ClientList transients_stacking_order
= ensureStackingOrder( c
->transients());
1614 for( ClientList::ConstIterator it
= transients_stacking_order
.begin();
1615 it
!= transients_stacking_order
.end();
1617 sendClientToDesktop( *it
, desk
, dont_activate
);
1621 int Workspace::numScreens() const
1623 if( !options
->xineramaEnabled
)
1625 return qApp
->desktop()->numScreens();
1628 int Workspace::activeScreen() const
1630 if( !options
->xineramaEnabled
)
1632 if( !options
->activeMouseScreen
)
1634 if( activeClient() != NULL
&& !activeClient()->isOnScreen( active_screen
))
1635 return qApp
->desktop()->screenNumber( activeClient()->geometry().center());
1636 return active_screen
;
1638 return qApp
->desktop()->screenNumber( cursorPos());
1641 // check whether a client moved completely out of what's considered the active screen,
1642 // if yes, set a new active screen
1643 void Workspace::checkActiveScreen( const Client
* c
)
1645 if( !options
->xineramaEnabled
)
1649 if( !c
->isOnScreen( active_screen
))
1650 active_screen
= c
->screen();
1653 // called e.g. when a user clicks on a window, set active screen to be the screen
1654 // where the click occurred
1655 void Workspace::setActiveScreenMouse( const QPoint
&mousepos
)
1657 if( !options
->xineramaEnabled
)
1659 active_screen
= qApp
->desktop()->screenNumber( mousepos
);
1662 QRect
Workspace::screenGeometry( int screen
) const
1664 if( !options
->xineramaEnabled
)
1665 return qApp
->desktop()->geometry();
1666 return qApp
->desktop()->screenGeometry( screen
);
1669 int Workspace::screenNumber( const QPoint
&pos
) const
1671 if( !options
->xineramaEnabled
)
1673 return qApp
->desktop()->screenNumber( pos
);
1676 void Workspace::sendClientToScreen( Client
* c
, int screen
)
1678 if( c
->screen() == screen
) // don't use isOnScreen(), that's true even when only partially
1680 GeometryUpdatesBlocker
blocker( c
);
1681 QRect old_sarea
= clientArea( MaximizeArea
, c
);
1682 QRect sarea
= clientArea( MaximizeArea
, screen
, c
->desktop());
1683 c
->setGeometry( sarea
.x() - old_sarea
.x() + c
->x(), sarea
.y() - old_sarea
.y() + c
->y(),
1684 c
->size().width(), c
->size().height());
1685 c
->checkWorkspacePosition();
1686 ClientList transients_stacking_order
= ensureStackingOrder( c
->transients());
1687 for( ClientList::ConstIterator it
= transients_stacking_order
.begin();
1688 it
!= transients_stacking_order
.end();
1690 sendClientToScreen( *it
, screen
);
1692 active_screen
= screen
;
1695 void Workspace::updateDesktopLayout()
1697 // rootInfo->desktopLayoutCorner(); // I don't find this worth bothering, feel free to
1698 layoutOrientation
= ( rootInfo
->desktopLayoutOrientation() == NET::OrientationHorizontal
1699 ? Qt::Horizontal
: Qt::Vertical
);
1700 layoutX
= rootInfo
->desktopLayoutColumnsRows().width();
1701 layoutY
= rootInfo
->desktopLayoutColumnsRows().height();
1702 if( layoutX
== 0 && layoutY
== 0 ) // not given, set default layout
1706 void Workspace::calcDesktopLayout(int* xp
, int* yp
, Qt::Orientation
* orientation
) const
1708 int x
= layoutX
; // <= 0 means compute it from the other and total number of desktops
1710 if((x
<= 0) && (y
> 0))
1711 x
= (numberOfDesktops()+y
-1) / y
;
1712 else if((y
<=0) && (x
> 0))
1713 y
= (numberOfDesktops()+x
-1) / x
;
1721 *orientation
= layoutOrientation
;
1724 void Workspace::killWindowId( Window window_to_kill
)
1726 if( window_to_kill
== None
)
1728 Window window
= window_to_kill
;
1729 Client
* client
= NULL
;
1732 client
= findClient( FrameIdMatchPredicate( window
));
1733 if( client
!= NULL
) // found the client
1735 Window parent
, root
;
1737 unsigned int children_count
;
1738 XQueryTree( display(), window
, &root
, &parent
, &children
, &children_count
);
1739 if( children
!= NULL
)
1741 if( window
== root
) // we didn't find the client, probably an override-redirect window
1743 window
= parent
; // go up
1745 if( client
!= NULL
)
1746 client
->killWindow();
1748 XKillClient( display(), window_to_kill
);
1752 void Workspace::sendPingToWindow( Window window
, Time timestamp
)
1754 rootInfo
->sendPing( window
, timestamp
);
1757 void Workspace::sendTakeActivity( Client
* c
, Time timestamp
, long flags
)
1759 rootInfo
->takeActivity( c
->window(), timestamp
, flags
);
1760 pending_take_activity
= c
;
1765 Takes a screenshot of the current window and puts it in the clipboard.
1767 void Workspace::slotGrabWindow()
1769 if ( active_client
)
1771 QPixmap snapshot
= QPixmap::grabWindow( active_client
->frameId() );
1773 //No XShape - no work.
1774 if( Extensions::shapeAvailable())
1776 //As the first step, get the mask from XShape.
1778 XRectangle
* rects
= XShapeGetRectangles( display(), active_client
->frameId(),
1779 ShapeBounding
, &count
, &order
);
1780 //The ShapeBounding region is the outermost shape of the window;
1781 //ShapeBounding - ShapeClipping is defined to be the border.
1782 //Since the border area is part of the window, we use bounding
1783 // to limit our work region
1786 //Create a QRegion from the rectangles describing the bounding mask.
1788 for (int pos
= 0; pos
< count
; pos
++)
1789 contents
+= QRegion(rects
[pos
].x
, rects
[pos
].y
,
1790 rects
[pos
].width
, rects
[pos
].height
);
1793 //Create the bounding box.
1794 QRegion
bbox(0, 0, snapshot
.width(), snapshot
.height());
1796 //Get the masked away area.
1797 QRegion maskedAway
= bbox
- contents
;
1798 QVector
<QRect
> maskedAwayRects
= maskedAway
.rects();
1800 //Construct a bitmap mask from the rectangles
1801 QBitmap
mask( snapshot
.width(), snapshot
.height());
1803 p
.fillRect(0, 0, mask
.width(), mask
.height(), Qt::color1
);
1804 for (int pos
= 0; pos
< maskedAwayRects
.count(); pos
++)
1805 p
.fillRect(maskedAwayRects
[pos
], Qt::color0
);
1807 snapshot
.setMask(mask
);
1811 QClipboard
*cb
= QApplication::clipboard();
1812 cb
->setPixmap( snapshot
);
1819 Takes a screenshot of the whole desktop and puts it in the clipboard.
1821 void Workspace::slotGrabDesktop()
1823 QPixmap p
= QPixmap::grabWindow( rootWindow() );
1824 QClipboard
*cb
= QApplication::clipboard();
1830 Invokes keyboard mouse emulation
1832 void Workspace::slotMouseEmulation()
1834 if ( mouse_emulation
)
1837 mouse_emulation
= false;
1841 if( grabXKeyboard())
1843 mouse_emulation
= true;
1844 mouse_emulation_state
= 0;
1845 mouse_emulation_window
= 0;
1850 Returns the child window under the mouse and activates the
1851 respective client if necessary.
1853 Auxiliary function for the mouse emulation system.
1855 WId
Workspace::getMouseEmulationWindow()
1858 Window child
= rootWindow();
1859 int root_x
, root_y
, lx
, ly
;
1867 c
= findClient( FrameIdMatchPredicate( w
));
1868 XQueryPointer( display(), w
, &root
, &child
,
1869 &root_x
, &root_y
, &lx
, &ly
, &state
);
1870 } while ( child
!= None
&& child
!= w
);
1872 if ( c
&& !c
->isActive() )
1873 activateClient( c
);
1878 Sends a faked mouse event to the specified window. Returns the new button state.
1880 unsigned int Workspace::sendFakedMouseEvent( const QPoint
&pos
, WId w
, MouseEmulation type
, int button
, unsigned int state
)
1884 QWidget
* widget
= QWidget::find( w
);
1885 if ( (!widget
|| qobject_cast
<QToolButton
*>(widget
)) && !findClient( WindowMatchPredicate( w
)) )
1889 XTranslateCoordinates( display(), rootWindow(), w
, pos
.x(), pos
.y(), &x
, &y
, &xw
);
1890 if ( type
== EmuMove
)
1891 { // motion notify events
1893 e
.type
= MotionNotify
;
1894 e
.xmotion
.window
= w
;
1895 e
.xmotion
.root
= rootWindow();
1896 e
.xmotion
.subwindow
= w
;
1897 e
.xmotion
.time
= xTime();
1900 e
.xmotion
.x_root
= pos
.x();
1901 e
.xmotion
.y_root
= pos
.y();
1902 e
.xmotion
.state
= state
;
1903 e
.xmotion
.is_hint
= NotifyNormal
;
1904 XSendEvent( display(), w
, true, ButtonMotionMask
, &e
);
1909 e
.type
= type
== EmuRelease
? ButtonRelease
: ButtonPress
;
1910 e
.xbutton
.window
= w
;
1911 e
.xbutton
.root
= rootWindow();
1912 e
.xbutton
.subwindow
= w
;
1913 e
.xbutton
.time
= xTime();
1916 e
.xbutton
.x_root
= pos
.x();
1917 e
.xbutton
.y_root
= pos
.y();
1918 e
.xbutton
.state
= state
;
1919 e
.xbutton
.button
= button
;
1920 XSendEvent( display(), w
, true, ButtonPressMask
, &e
);
1922 if ( type
== EmuPress
)
1927 state
|= Button2Mask
;
1930 state
|= Button3Mask
;
1933 state
|= Button1Mask
;
1942 state
&= ~Button2Mask
;
1945 state
&= ~Button3Mask
;
1948 state
&= ~Button1Mask
;
1958 Handles keypress event during mouse emulation
1960 bool Workspace::keyPressMouseEmulation( XKeyEvent
& ev
)
1962 int kc
= XKeycodeToKeysym(display(), ev
.keycode
, 0);
1963 int km
= ev
.state
& (ControlMask
| Mod1Mask
| ShiftMask
);
1965 bool is_control
= km
& ControlMask
;
1966 bool is_alt
= km
& Mod1Mask
;
1967 bool is_shift
= km
& ShiftMask
;
1968 int delta
= is_control
?1:is_alt
?32:8;
1969 QPoint pos
= cursorPos();
1990 if ( !mouse_emulation_state
)
1991 mouse_emulation_window
= getMouseEmulationWindow();
1992 if ( (mouse_emulation_state
& Button1Mask
) == 0 )
1993 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuPress
, Button1
, mouse_emulation_state
);
1995 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuRelease
, Button1
, mouse_emulation_state
);
1998 if ( !mouse_emulation_state
)
1999 mouse_emulation_window
= getMouseEmulationWindow();
2000 if ( (mouse_emulation_state
& Button2Mask
) == 0 )
2001 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuPress
, Button2
, mouse_emulation_state
);
2003 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuRelease
, Button2
, mouse_emulation_state
);
2006 if ( !mouse_emulation_state
)
2007 mouse_emulation_window
= getMouseEmulationWindow();
2008 if ( (mouse_emulation_state
& Button3Mask
) == 0 )
2009 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuPress
, Button3
, mouse_emulation_state
);
2011 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuRelease
, Button3
, mouse_emulation_state
);
2018 if ( !mouse_emulation_state
)
2020 // nothing was pressed, fake a LMB click
2021 mouse_emulation_window
= getMouseEmulationWindow();
2022 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuPress
, Button1
, mouse_emulation_state
);
2023 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuRelease
, Button1
, mouse_emulation_state
);
2027 if ( mouse_emulation_state
& Button1Mask
)
2028 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuRelease
, Button1
, mouse_emulation_state
);
2029 if ( mouse_emulation_state
& Button2Mask
)
2030 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuRelease
, Button2
, mouse_emulation_state
);
2031 if ( mouse_emulation_state
& Button3Mask
)
2032 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuRelease
, Button3
, mouse_emulation_state
);
2038 mouse_emulation
= false;
2044 QCursor::setPos( pos
);
2045 if ( mouse_emulation_state
)
2046 mouse_emulation_state
= sendFakedMouseEvent( pos
, mouse_emulation_window
, EmuMove
, 0, mouse_emulation_state
);
2051 //Delayed focus functions
2052 void Workspace::delayFocus()
2054 requestFocus( delayfocus_client
);
2058 void Workspace::requestDelayFocus( Client
* c
)
2060 delayfocus_client
= c
;
2061 delete delayFocusTimer
;
2062 delayFocusTimer
= new QTimer( this );
2063 connect( delayFocusTimer
, SIGNAL( timeout() ), this, SLOT( delayFocus() ) );
2064 delayFocusTimer
->setSingleShot( true );
2065 delayFocusTimer
->start( options
->delayFocusInterval
);
2068 void Workspace::cancelDelayFocus()
2070 delete delayFocusTimer
;
2071 delayFocusTimer
= 0;
2075 //========================================================================//
2076 // Electric Border Window management. Electric borders allow a user
2077 // to change the virtual desktop or activate another features
2078 // by moving the mouse pointer to the borders or corners.
2079 // Technically this is done with input only windows.
2080 void Workspace::updateElectricBorders()
2082 electric_time_first
= xTime();
2083 electric_time_last
= xTime();
2084 electric_current_border
= ElectricNone
;
2085 QRect r
= QApplication::desktop()->geometry();
2086 electricTop
= r
.top();
2087 electricBottom
= r
.bottom();
2088 electricLeft
= r
.left();
2089 electricRight
= r
.right();
2092 pos
< ELECTRIC_COUNT
;
2095 if( electric_reserved
[ pos
] == 0 )
2097 if( electric_windows
[ pos
] != None
)
2098 XDestroyWindow( display(), electric_windows
[ pos
] );
2099 electric_windows
[ pos
] = None
;
2102 if( electric_windows
[ pos
] != None
)
2104 XSetWindowAttributes attributes
;
2105 attributes
.override_redirect
= True
;
2106 attributes
.event_mask
= EnterWindowMask
| LeaveWindowMask
;
2107 unsigned long valuemask
= CWOverrideRedirect
| CWEventMask
;
2108 int xywh
[ ELECTRIC_COUNT
][ 4 ] =
2110 { r
.left() + 1, r
.top(), r
.width() - 2, 1 }, // top
2111 { r
.right(), r
.top(), 1, 1 }, // topright
2112 { r
.right(), r
.top() + 1, 1, r
.height() - 2 }, // etc.
2113 { r
.right(), r
.bottom(), 1, 1 },
2114 { r
.left() + 1, r
.bottom(), r
.width() - 2, 1 },
2115 { r
.left(), r
.bottom(), 1, 1 },
2116 { r
.left(), r
.top() + 1, 1, r
.height() - 2 },
2117 { r
.left(), r
.top(), 1, 1 }
2119 electric_windows
[ pos
] = XCreateWindow( display(), rootWindow(),
2120 xywh
[ pos
][ 0 ], xywh
[ pos
][ 1 ], xywh
[ pos
][ 2 ], xywh
[ pos
][ 3 ],
2121 0, CopyFromParent
, InputOnly
, CopyFromParent
, valuemask
, &attributes
);
2122 XMapWindow( display(), electric_windows
[ pos
]);
2123 // Set XdndAware on the windows, so that DND enter events are received (#86998)
2124 Atom version
= 4; // XDND version
2125 XChangeProperty( display(), electric_windows
[ pos
], atoms
->xdnd_aware
, XA_ATOM
,
2126 32, PropModeReplace
, ( unsigned char* )&version
, 1 );
2130 void Workspace::destroyElectricBorders()
2133 pos
< ELECTRIC_COUNT
;
2136 if( electric_windows
[ pos
] != None
)
2137 XDestroyWindow( display(), electric_windows
[ pos
] );
2138 electric_windows
[ pos
] = None
;
2142 void Workspace::reserveElectricBorderSwitching( bool reserve
)
2145 pos
< ELECTRIC_COUNT
;
2148 reserveElectricBorder( static_cast< ElectricBorder
>( pos
));
2150 unreserveElectricBorder( static_cast< ElectricBorder
>( pos
));
2153 void Workspace::reserveElectricBorder( ElectricBorder border
)
2155 if( border
== ElectricNone
)
2157 if( electric_reserved
[ border
]++ == 0 )
2158 QTimer::singleShot( 0, this, SLOT( updateElectricBorders()));
2161 void Workspace::unreserveElectricBorder( ElectricBorder border
)
2163 if( border
== ElectricNone
)
2165 assert( electric_reserved
[ border
] > 0 );
2166 if( --electric_reserved
[ border
] == 0 )
2167 QTimer::singleShot( 0, this, SLOT( updateElectricBorders()));
2170 void Workspace::checkElectricBorder(const QPoint
&pos
, Time now
)
2172 if ((pos
.x() != electricLeft
) &&
2173 (pos
.x() != electricRight
) &&
2174 (pos
.y() != electricTop
) &&
2175 (pos
.y() != electricBottom
))
2178 bool have_borders
= false;
2182 if( electric_windows
[ i
] != None
)
2183 have_borders
= true;
2187 Time treshold_set
= options
->electricBorderDelay(); // set timeout
2188 Time treshold_reset
= 250; // reset timeout
2189 int distance_reset
= 30; // Mouse should not move more than this many pixels
2191 ElectricBorder border
;
2192 if( pos
.x() == electricLeft
&& pos
.y() == electricTop
)
2193 border
= ElectricTopLeft
;
2194 else if( pos
.x() == electricRight
&& pos
.y() == electricTop
)
2195 border
= ElectricTopRight
;
2196 else if( pos
.x() == electricLeft
&& pos
.y() == electricBottom
)
2197 border
= ElectricBottomLeft
;
2198 else if( pos
.x() == electricRight
&& pos
.y() == electricBottom
)
2199 border
= ElectricBottomRight
;
2200 else if( pos
.x() == electricLeft
)
2201 border
= ElectricLeft
;
2202 else if( pos
.x() == electricRight
)
2203 border
= ElectricRight
;
2204 else if( pos
.y() == electricTop
)
2205 border
= ElectricTop
;
2206 else if( pos
.y() == electricBottom
)
2207 border
= ElectricBottom
;
2211 if( electric_windows
[ border
] == None
)
2214 if ((electric_current_border
== border
) &&
2215 (timestampDiff(electric_time_last
, now
) < treshold_reset
) &&
2216 ((pos
-electric_push_point
).manhattanLength() < distance_reset
))
2218 electric_time_last
= now
;
2220 if (timestampDiff(electric_time_first
, now
) > treshold_set
)
2222 electric_current_border
= ElectricNone
;
2223 if( effects
&& static_cast<EffectsHandlerImpl
*>(effects
)->borderActivated( border
))
2224 {} // handled by effects
2226 electricBorderSwitchDesktop( border
, pos
);
2232 electric_current_border
= border
;
2233 electric_time_first
= now
;
2234 electric_time_last
= now
;
2235 electric_push_point
= pos
;
2238 // reset the pointer to find out wether the user is really pushing
2239 // (the direction back from which it came, starting from top clockwise)
2240 const int xdiff
[ ELECTRIC_COUNT
] = { 0, -1, -1, -1, 0, 1, 1, 1 };
2241 const int ydiff
[ ELECTRIC_COUNT
] = { 1, 1, 0, -1, -1, -1, 0, 1 };
2242 QCursor::setPos( pos
.x() + xdiff
[ border
], pos
.y() + ydiff
[ border
] );
2245 void Workspace::electricBorderSwitchDesktop( ElectricBorder border
, const QPoint
& _pos
)
2248 int desk
= currentDesktop();
2249 const int OFFSET
= 2;
2250 if( border
== ElectricLeft
|| border
== ElectricTopLeft
|| border
== ElectricBottomLeft
)
2252 desk
= desktopToLeft( desk
, options
->rollOverDesktops
);
2253 pos
.setX( displayWidth() - 1 - OFFSET
);
2255 if( border
== ElectricRight
|| border
== ElectricTopRight
|| border
== ElectricBottomRight
)
2257 desk
= desktopToRight( desk
, options
->rollOverDesktops
);
2260 if( border
== ElectricTop
|| border
== ElectricTopLeft
|| border
== ElectricTopRight
)
2262 desk
= desktopUp( desk
, options
->rollOverDesktops
);
2263 pos
.setY( displayHeight() - 1 - OFFSET
);
2265 if( border
== ElectricBottom
|| border
== ElectricBottomLeft
|| border
== ElectricBottomRight
)
2267 desk
= desktopDown( desk
, options
->rollOverDesktops
);
2270 int desk_before
= currentDesktop();
2271 setCurrentDesktop( desk
);
2272 if( currentDesktop() != desk_before
)
2273 QCursor::setPos( pos
);
2276 // this function is called when the user entered an electric border
2277 // with the mouse. It may switch to another virtual desktop
2278 bool Workspace::electricBorderEvent(XEvent
*e
)
2280 if( e
->type
== EnterNotify
)
2285 if( electric_windows
[ i
] != None
&& e
->xcrossing
.window
== electric_windows
[ i
] )
2286 { // the user entered an electric border
2287 checkElectricBorder( QPoint( e
->xcrossing
.x_root
, e
->xcrossing
.y_root
), e
->xcrossing
.time
);
2291 if( e
->type
== ClientMessage
)
2293 if( e
->xclient
.message_type
== atoms
->xdnd_position
)
2298 if( electric_windows
[ i
] != None
&& e
->xclient
.window
== electric_windows
[ i
] )
2301 checkElectricBorder( QPoint( e
->xclient
.data
.l
[2]>>16, e
->xclient
.data
.l
[2]&0xffff), xTime() );
2309 void Workspace::addTopMenu( Client
* c
)
2311 assert( c
->isTopMenu());
2312 assert( !topmenus
.contains( c
));
2313 topmenus
.append( c
);
2314 if( managingTopMenus())
2316 int minsize
= c
->minSize().height();
2317 if( minsize
> topMenuHeight())
2319 topmenu_height
= minsize
;
2320 updateTopMenuGeometry();
2322 updateTopMenuGeometry( c
);
2323 updateCurrentTopMenu();
2325 // kDebug() << "NEW TOPMENU:" << c;
2328 void Workspace::removeTopMenu( Client
* c
)
2330 // if( c->isTopMenu())
2331 // kDebug() << "REMOVE TOPMENU:" << c;
2332 assert( c
->isTopMenu());
2333 assert( topmenus
.contains( c
));
2334 topmenus
.removeAll( c
);
2335 updateCurrentTopMenu();
2336 // TODO reduce topMenuHeight() if possible?
2339 void Workspace::lostTopMenuSelection()
2341 // kDebug() << "lost TopMenu selection";
2342 // make sure this signal is always set when not owning the selection
2343 disconnect( topmenu_watcher
, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
2344 connect( topmenu_watcher
, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
2345 if( !managing_topmenus
)
2347 connect( topmenu_watcher
, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
2348 disconnect( topmenu_selection
, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
2349 managing_topmenus
= false;
2350 delete topmenu_space
;
2351 topmenu_space
= NULL
;
2353 for( ClientList::ConstIterator it
= topmenus
.begin();
2354 it
!= topmenus
.end();
2356 (*it
)->checkWorkspacePosition();
2359 void Workspace::lostTopMenuOwner()
2361 if( !options
->topMenuEnabled())
2363 // kDebug() << "TopMenu selection lost owner";
2364 if( !topmenu_selection
->claim( false ))
2366 // kDebug() << "Failed to claim TopMenu selection";
2369 // kDebug() << "claimed TopMenu selection";
2370 setupTopMenuHandling();
2373 void Workspace::setupTopMenuHandling()
2375 if( managing_topmenus
)
2377 connect( topmenu_selection
, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
2378 disconnect( topmenu_watcher
, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
2379 managing_topmenus
= true;
2380 topmenu_space
= new QWidget
;
2382 stack
[ 0 ] = supportWindow
->winId();
2383 stack
[ 1 ] = topmenu_space
->winId();
2384 XRestackWindows(display(), stack
, 2);
2385 updateTopMenuGeometry();
2386 topmenu_space
->show();
2388 updateCurrentTopMenu();
2391 int Workspace::topMenuHeight() const
2393 if( topmenu_height
== 0 )
2394 { // simply create a dummy menubar and use its preffered height as the menu height
2396 tmpmenu
.addAction( "dummy" );
2397 topmenu_height
= tmpmenu
.sizeHint().height();
2399 return topmenu_height
;
2402 KDecoration
* Workspace::createDecoration( KDecorationBridge
* bridge
)
2404 return mgr
->createDecoration( bridge
);
2407 QString
Workspace::desktopName( int desk
) const
2409 return QString::fromUtf8( rootInfo
->desktopName( desk
) );
2412 bool Workspace::checkStartupNotification( Window w
, KStartupInfoId
& id
, KStartupInfoData
& data
)
2414 return startup
->checkStartup( w
, id
, data
) == KStartupInfo::Match
;
2418 Puts the focus on a dummy window
2419 Just using XSetInputFocus() with None would block keyboard input
2421 void Workspace::focusToNull()
2423 XSetInputFocus(display(), null_focus_window
, RevertToPointerRoot
, xTime() );
2426 void Workspace::helperDialog( const QString
& message
, const Client
* c
)
2430 if( message
== "noborderaltf3" )
2432 KAction
* action
= qobject_cast
<KAction
*>(keys
->action( "Window Operations Menu" ));
2433 if (action
==0) assert( false );
2434 QString shortcut
= QString( "%1 (%2)" ).arg( action
->text() )
2435 .arg( action
->globalShortcut().primary().toString());
2436 args
<< "--msgbox" <<
2437 i18n( "You have selected to show a window without its border.\n"
2438 "Without the border, you will not be able to enable the border "
2439 "again using the mouse: use the window operations menu instead, "
2440 "activated using the %1 keyboard shortcut." ,
2442 type
= "altf3warning";
2444 else if( message
== "fullscreenaltf3" )
2446 KAction
* action
= qobject_cast
<KAction
*>(keys
->action( "Window Operations Menu" ));
2447 if (action
==0) assert( false );
2448 QString shortcut
= QString( "%1 (%2)" ).arg( action
->text() )
2449 .arg( action
->globalShortcut().primary().toString());
2450 args
<< "--msgbox" <<
2451 i18n( "You have selected to show a window in fullscreen mode.\n"
2452 "If the application itself does not have an option to turn the fullscreen "
2453 "mode off you will not be able to disable it "
2454 "again using the mouse: use the window operations menu instead, "
2455 "activated using the %1 keyboard shortcut." ,
2457 type
= "altf3warning";
2461 if( !type
.isEmpty())
2463 KConfig
cfg( "kwin_dialogsrc" );
2464 KConfigGroup
cg(&cfg
, "Notification Messages" ); // this depends on KMessageBox
2465 if( !cg
.readEntry( type
, true )) // has don't show again checked
2466 return; // save launching kdialog
2467 args
<<"--dontagain" << "kwin_dialogsrc:" + type
;
2470 args
<<"--embed" << QString::number( c
->window());
2471 KProcess::startDetached("kdialog",args
);
2474 void Workspace::setShowingDesktop( bool showing
)
2476 rootInfo
->setShowingDesktop( showing
);
2477 showing_desktop
= showing
;
2478 ++block_showing_desktop
;
2479 if( showing_desktop
)
2481 showing_desktop_clients
.clear();
2483 ClientList cls
= stackingOrder();
2484 // find them first, then minimize, otherwise transients may get minimized with the window
2485 // they're transient for
2486 for( ClientList::ConstIterator it
= cls
.begin();
2490 if( (*it
)->isOnCurrentDesktop() && (*it
)->isShown( true ) && !(*it
)->isSpecialWindow())
2491 showing_desktop_clients
.prepend( *it
); // topmost first to reduce flicker
2493 for( ClientList::ConstIterator it
= showing_desktop_clients
.begin();
2494 it
!= showing_desktop_clients
.end();
2498 if( Client
* desk
= findDesktop( true, currentDesktop()))
2499 requestFocus( desk
);
2503 for( ClientList::ConstIterator it
= showing_desktop_clients
.begin();
2504 it
!= showing_desktop_clients
.end();
2506 (*it
)->unminimize();
2507 if( showing_desktop_clients
.count() > 0 )
2508 requestFocus( showing_desktop_clients
.first());
2509 showing_desktop_clients
.clear();
2511 --block_showing_desktop
;
2514 // Following Kicker's behavior:
2515 // Changing a virtual desktop resets the state and shows the windows again.
2516 // Unminimizing a window resets the state but keeps the windows hidden (except
2517 // the one that was unminimized).
2518 // A new window resets the state and shows the windows again, with the new window
2519 // being active. Due to popular demand (#67406) by people who apparently
2520 // don't see a difference between "show desktop" and "minimize all", this is not
2521 // true if "showDesktopIsMinimizeAll" is set in kwinrc. In such case showing
2522 // a new window resets the state but doesn't show windows.
2523 void Workspace::resetShowingDesktop( bool keep_hidden
)
2525 if( block_showing_desktop
> 0 )
2527 rootInfo
->setShowingDesktop( false );
2528 showing_desktop
= false;
2529 ++block_showing_desktop
;
2532 for( ClientList::ConstIterator it
= showing_desktop_clients
.begin();
2533 it
!= showing_desktop_clients
.end();
2535 (*it
)->unminimize();
2537 showing_desktop_clients
.clear();
2538 --block_showing_desktop
;
2541 // Activating/deactivating this feature works like this:
2542 // When nothing is active, and the shortcut is pressed, global shortcuts are disabled
2543 // (using global_shortcuts_disabled)
2544 // When a window that has disabling forced is activated, global shortcuts are disabled.
2545 // (using global_shortcuts_disabled_for_client)
2546 // When a shortcut is pressed and global shortcuts are disabled (either by a shortcut
2547 // or for a client), they are enabled again.
2548 void Workspace::slotDisableGlobalShortcuts()
2550 if( global_shortcuts_disabled
|| global_shortcuts_disabled_for_client
)
2551 disableGlobalShortcuts( false );
2553 disableGlobalShortcuts( true );
2556 static bool pending_dfc
= false;
2558 void Workspace::disableGlobalShortcutsForClient( bool disable
)
2560 if( global_shortcuts_disabled_for_client
== disable
)
2562 if( !global_shortcuts_disabled
)
2566 KGlobalSettings::self()->emitChange( KGlobalSettings::BlockShortcuts
, disable
);
2567 // kwin will get the kipc message too
2571 void Workspace::disableGlobalShortcuts( bool disable
)
2573 KGlobalSettings::self()->emitChange( KGlobalSettings::BlockShortcuts
, disable
);
2574 // kwin will get the kipc message too
2577 void Workspace::slotBlockShortcuts( int data
)
2579 if( pending_dfc
&& data
)
2581 global_shortcuts_disabled_for_client
= true;
2582 pending_dfc
= false;
2586 global_shortcuts_disabled
= data
;
2587 global_shortcuts_disabled_for_client
= false;
2589 // update also Alt+LMB actions etc.
2590 for( ClientList::ConstIterator it
= clients
.begin();
2591 it
!= clients
.end();
2593 (*it
)->updateMouseGrab();
2596 // Optimized version of QCursor::pos() that tries to avoid X roundtrips
2597 // by updating the value only when the X timestamp changes.
2598 static QPoint last_cursor_pos
;
2599 static int last_buttons
= 0;
2600 static Time last_cursor_timestamp
= CurrentTime
;
2602 QPoint
Workspace::cursorPos() const
2604 if( last_cursor_timestamp
== CurrentTime
2605 || last_cursor_timestamp
!= QX11Info::appTime())
2607 last_cursor_timestamp
= QX11Info::appTime();
2610 int root_x
, root_y
, win_x
, win_y
;
2612 XQueryPointer( display(), rootWindow(), &root
, &child
,
2613 &root_x
, &root_y
, &win_x
, &win_y
, &state
);
2614 last_cursor_pos
= QPoint( root_x
, root_y
);
2615 last_buttons
= state
;
2616 QTimer::singleShot( 0, const_cast< Workspace
* >( this ), SLOT( resetCursorPosTime()));
2618 return last_cursor_pos
;
2621 // Because of QTimer's and the impossibility to get events for all mouse
2622 // movements (at least I haven't figured out how) the position needs
2623 // to be also refetched after each return to the event loop.
2624 void Workspace::resetCursorPosTime()
2626 last_cursor_timestamp
= CurrentTime
;
2629 void Workspace::checkCursorPos()
2631 QPoint last
= last_cursor_pos
;
2632 int lastb
= last_buttons
;
2633 cursorPos(); // update if needed
2634 if( last
!= last_cursor_pos
|| lastb
!= last_buttons
)
2635 static_cast< EffectsHandlerImpl
* >( effects
)->mouseChanged( cursorPos(), last
,
2636 x11ToQtMouseButtons( last_buttons
), x11ToQtMouseButtons( lastb
),
2637 x11ToQtKeyboardModifiers( last_buttons
), x11ToQtKeyboardModifiers( lastb
));
2642 #include "workspace.moc"