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 <QTextStream>
25 #include "workspace.h"
30 #include <qdrawutil.h>
36 #include <QApplication>
37 #include <QDesktopWidget>
41 #include <kglobalsettings.h>
42 #include <kiconeffect.h>
43 #include <X11/keysym.h>
44 #include <X11/keysymdef.h>
46 #include <kactioncollection.h>
47 #include <kkeyserver.h>
48 #include <kconfiggroup.h>
50 // specify externals before namespace
55 extern QPixmap
* kwin_get_menu_pix_hack();
57 TabBox::TabBox( Workspace
*ws
)
58 : QFrame( 0, Qt::X11BypassWindowManagerHint
)
61 , display_refcount( 0 )
63 setFrameStyle(QFrame::StyledPanel
);
64 setFrameShadow(QFrame::Raised
);
65 setBackgroundRole(QPalette::Base
);
68 setContentsMargins( 3, 3, 3, 3 );
72 no_tasks
= i18n("*** No Windows ***");
73 m
= TabBoxDesktopMode
; // init variables
76 connect(&delayedShowTimer
, SIGNAL(timeout()), this, SLOT(show()));
85 Sets the current mode to \a mode, either TabBoxDesktopListMode or TabBoxWindowsMode
89 void TabBox::setMode( TabBoxMode mode
)
96 Create list of clients on specified desktop, starting with client c
98 void TabBox::createClientList(ClientList
&list
, int desktop
/*-1 = all*/, Client
*c
, bool chain
)
100 ClientList::size_type idx
= 0;
107 c
= workspace()->nextClientFocusChain(c
);
109 c
= workspace()->stackingOrder().first();
116 if ( ((desktop
== -1) || c
->isOnDesktop(desktop
))
117 && c
->wantsTabFocus() )
118 { // don't add windows that have modal dialogs
119 Client
* modal
= c
->findModal();
120 if( modal
== NULL
|| modal
== c
)
122 else if( !list
.contains( modal
))
129 if( options
->separateScreenFocus
&& options
->xineramaEnabled
)
131 if( c
->screen() != workspace()->activeScreen())
138 list
.removeAll( add
);
145 c
= workspace()->nextClientFocusChain( c
);
148 if ( idx
>= (workspace()->stackingOrder().size()-1) )
151 c
= workspace()->stackingOrder()[++idx
];
161 Create list of desktops, starting with desktop start
163 void TabBox::createDesktopList(QList
< int > &list
, int start
, SortOrder order
)
167 int iDesktop
= start
;
169 for( int i
= 1; i
<= workspace()->numberOfDesktops(); i
++ )
171 list
.append( iDesktop
);
172 if ( order
== StaticOrder
)
174 iDesktop
= workspace()->nextDesktopStatic( iDesktop
);
177 { // MostRecentlyUsedOrder
178 iDesktop
= workspace()->nextDesktopFocusChain( iDesktop
);
185 Resets the tab box to display the active client in TabBoxWindowsMode, or the
186 current desktop in TabBoxDesktopListMode
188 void TabBox::reset( bool partial_reset
)
190 int w
, h
, cw
= 0, wmax
= 0;
192 QRect r
= workspace()->screenGeometry( workspace()->activeScreen());
194 // calculate height of 1 line
195 // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below
196 lineHeight
= qMax(fontMetrics().height() + 2, 32 + 4);
198 if ( mode() == TabBoxWindowsMode
)
200 Client
* starting_client
= 0;
201 if( partial_reset
&& clients
.count() != 0 )
202 starting_client
= clients
.first();
204 client
= starting_client
= workspace()->activeClient();
206 // get all clients to show
207 createClientList(clients
, options_traverse_all
? -1 : workspace()->currentDesktop(), starting_client
, true);
209 // calculate maximum caption width
210 cw
= fontMetrics().width(no_tasks
)+20;
211 for (ClientList::ConstIterator it
= clients
.constBegin(); it
!= clients
.constEnd(); ++it
)
213 cw
= fontMetrics().width( (*it
)->caption() );
214 if ( cw
> wmax
) wmax
= cw
;
217 // calculate height for the popup
218 if ( clients
.count() == 0 ) // height for the "not tasks" text
222 f
.setPointSize( 14 );
224 h
= QFontMetrics(f
).height()*4;
228 showMiniIcon
= false;
229 h
= clients
.count() * lineHeight
;
231 if ( h
> (r
.height()-(2*frameWidth())) ) // if too high, use mini icons
234 // fontheight + 1 pixel above + 1 pixel below, or 16x16 icon + 1 pixel above + below
235 lineHeight
= qMax(fontMetrics().height() + 2, 16 + 2);
237 h
= clients
.count() * lineHeight
;
239 if ( h
> (r
.height()-(2*frameWidth())) ) // if still too high, remove some clients
241 // how many clients to remove
242 int howMany
= (h
- (r
.height()-(2*frameWidth())))/lineHeight
;
243 for (; howMany
; howMany
--)
244 clients
.removeAll(clients
.last());
246 h
= clients
.count() * lineHeight
;
253 int starting_desktop
;
254 if( mode() == TabBoxDesktopListMode
)
256 starting_desktop
= 1;
257 createDesktopList(desktops
, starting_desktop
, StaticOrder
);
260 { // TabBoxDesktopMode
261 starting_desktop
= workspace()->currentDesktop();
262 createDesktopList(desktops
, starting_desktop
, MostRecentlyUsedOrder
);
266 desk
= workspace()->currentDesktop();
268 showMiniIcon
= false;
270 foreach (int it
, desktops
)
272 cw
= fontMetrics().width( workspace()->desktopName(it
) );
273 if ( cw
> wmax
) wmax
= cw
;
276 // calculate height for the popup (max. 16 desktops always fit in a 800x600 screen)
277 h
= desktops
.count() * lineHeight
;
280 // height, width for the popup
281 h
+= 2 * frameWidth();
282 w
= 2*frameWidth() + 5*2 + ( showMiniIcon
? 16 : 32 ) + 8 + wmax
; // 5*2=margins, ()=icon, 8=space between icon+text
283 w
= qBound( r
.width()/3 , w
, r
.width() * 4 / 5 );
285 setGeometry( (r
.width()-w
)/2 + r
.x(),
286 (r
.height()-h
)/2+ r
.y(),
290 static_cast<EffectsHandlerImpl
*>(effects
)->tabBoxUpdated();
295 Shows the next or previous item, depending on \a next
297 void TabBox::nextPrev( bool next
)
299 if ( mode() == TabBoxWindowsMode
)
301 Client
* firstClient
= 0;
302 Client
* newClient
= client
;
306 newClient
= workspace()->nextClientFocusChain(newClient
);
308 newClient
= workspace()->previousClientFocusChain(newClient
);
311 // When we see our first client for the second time,
312 // it's time to stop.
313 firstClient
= newClient
;
315 else if (newClient
== firstClient
)
317 // No candidates found.
321 } while ( newClient
&& !clients
.contains( newClient
));
322 setCurrentClient( newClient
);
324 else if( mode() == TabBoxDesktopMode
)
326 setCurrentDesktop ( next
? workspace()->nextDesktopFocusChain( desk
)
327 : workspace()->previousDesktopFocusChain( desk
) );
330 { // TabBoxDesktopListMode
331 setCurrentDesktop ( next
? workspace()->nextDesktopStatic( desk
)
332 : workspace()->previousDesktopStatic( desk
)) ;
336 static_cast<EffectsHandlerImpl
*>(effects
)->tabBoxUpdated();
343 Returns the currently displayed client ( only works in TabBoxWindowsMode ).
344 Returns 0 if no client is displayed.
346 Client
* TabBox::currentClient()
348 if ( mode() != TabBoxWindowsMode
)
350 if (!workspace()->hasClient( client
))
356 Returns the list of clients potentially displayed ( only works in
358 Returns an empty list if no clients are available.
360 ClientList
TabBox::currentClientList()
362 if( mode() != TabBoxWindowsMode
)
369 Returns the currently displayed virtual desktop ( only works in
370 TabBoxDesktopListMode )
371 Returns -1 if no desktop is displayed.
373 int TabBox::currentDesktop()
375 if ( mode() == TabBoxDesktopListMode
|| mode() == TabBoxDesktopMode
)
382 Returns the list of desktops potentially displayed ( only works in
383 TabBoxDesktopListMode )
384 Returns an empty list if no desktops are available.
386 QList
< int > TabBox::currentDesktopList()
388 if ( mode() == TabBoxDesktopListMode
|| mode() == TabBoxDesktopMode
)
390 return QList
< int >();
395 Change the currently selected client, and notify the effects.
397 \sa setCurrentDesktop()
399 void TabBox::setCurrentClient( Client
* newClient
)
403 static_cast<EffectsHandlerImpl
*>(effects
)->tabBoxUpdated();
407 Change the currently selected desktop, and notify the effects.
409 \sa setCurrentClient()
411 void TabBox::setCurrentDesktop( int newDesktop
)
415 static_cast<EffectsHandlerImpl
*>(effects
)->tabBoxUpdated();
419 Reimplemented to raise the tab box as well
421 void TabBox::showEvent( QShowEvent
* )
428 hide the icon box if necessary
430 void TabBox::hideEvent( QHideEvent
* )
437 void TabBox::paintEvent( QPaintEvent
* e
)
439 QFrame::paintEvent( e
);
442 QRect
r( contentsRect());
444 QPixmap
* menu_pix
= kwin_get_menu_pix_hack();
446 int iconWidth
= showMiniIcon
? 16 : 32;
450 if ( mode () == TabBoxWindowsMode
)
452 if ( !currentClient() )
456 f
.setPointSize( 14 );
459 p
.drawText( r
, Qt::AlignCenter
, no_tasks
);
463 for (ClientList::ConstIterator it
= clients
.constBegin(); it
!= clients
.constEnd(); ++it
)
465 if ( workspace()->hasClient( *it
) ) // safety
467 // draw highlight background
468 if ( (*it
) == currentClient() )
469 p
.fillRect(x
, y
, r
.width(), lineHeight
, palette().brush( QPalette::Active
, QPalette::Highlight
));
475 if ( !(*it
)->miniIcon().isNull() )
476 icon
= (*it
)->miniIcon();
479 if ( !(*it
)->icon().isNull() )
480 icon
= (*it
)->icon();
486 if( (*it
)->isMinimized())
487 KIconEffect::semiTransparent( icon
);
488 p
.drawPixmap( x
+5, y
+ (lineHeight
- iconWidth
)/2, icon
);
491 // generate text to display
494 if ( !(*it
)->isOnDesktop(workspace()->currentDesktop()) )
495 s
= workspace()->desktopName((*it
)->desktop()) + ": ";
497 if ( (*it
)->isMinimized() )
498 s
+= '(' + (*it
)->caption() + ')';
500 s
+= (*it
)->caption();
502 s
= fontMetrics().elidedText( s
, Qt::ElideMiddle
, r
.width() - 5 - iconWidth
- 8 );
505 if ( (*it
) == currentClient() )
506 p
.setPen(palette().color( QPalette::Active
, QPalette::HighlightedText
));
507 else if( (*it
)->isMinimized())
509 QColor c1
= palette().color( QPalette::Active
, QPalette::Text
);
510 QColor c2
= palette().color( QPalette::Active
, QPalette::Background
);
511 // from kicker's TaskContainer::blendColors()
515 c1
.getRgb( &r1
, &g1
, &b1
);
516 c2
.getRgb( &r2
, &g2
, &b2
);
518 r1
+= (int) ( .5 * ( r2
- r1
) );
519 g1
+= (int) ( .5 * ( g2
- g1
) );
520 b1
+= (int) ( .5 * ( b2
- b1
) );
522 p
.setPen(QColor( r1
, g1
, b1
));
525 p
.setPen(palette().color( QPalette::Active
, QPalette::Text
));
527 p
.drawText(x
+5 + iconWidth
+ 8, y
, r
.width() - 5 - iconWidth
- 8, lineHeight
,
528 Qt::AlignLeft
| Qt::AlignVCenter
| Qt::TextSingleLine
, s
);
532 if ( y
>= r
.height() ) break;
537 { // TabBoxDesktopMode || TabBoxDesktopListMode
538 int iconHeight
= iconWidth
;
540 // get widest desktop name/number
543 f
.setPixelSize(iconHeight
- 4); // pixel, not point because I need to know the pixels
547 foreach (int it
, desktops
)
549 wmax
= qMax(wmax
, fontMetrics().width(workspace()->desktopName(it
)));
551 // calculate max width of desktop-number text
552 QString num
= QString::number(it
);
553 iconWidth
= qMax(iconWidth
- 4, fm
.boundingRect(num
).width()) + 4;
556 foreach (int it
, desktops
)
558 // draw highlight background
559 if ( it
== desk
) // current desktop
560 p
.fillRect(x
, y
, r
.width(), lineHeight
, palette().brush( QPalette::Active
, QPalette::Highlight
));
564 // draw "icon" (here: number of desktop)
565 p
.fillRect(x
+5, y
+2, iconWidth
, iconHeight
, palette().brush( QPalette::Active
, QPalette::Base
));
566 p
.setPen(palette().color( QPalette::Active
, QPalette::Text
));
567 p
.drawRect(x
+5, y
+2, iconWidth
, iconHeight
);
569 // draw desktop-number
571 QString num
= QString::number(it
);
572 p
.drawText(x
+5, y
+2, iconWidth
, iconHeight
, Qt::AlignCenter
, num
);
576 // draw desktop name text
578 p
.setPen(palette().color( QPalette::Active
, QPalette::HighlightedText
));
580 p
.setPen(palette().color( QPalette::Active
, QPalette::Text
));
582 p
.drawText(x
+5 + iconWidth
+ 8, y
, r
.width() - 5 - iconWidth
- 8, lineHeight
,
583 Qt::AlignLeft
| Qt::AlignVCenter
| Qt::TextSingleLine
,
584 workspace()->desktopName(it
));
586 // show mini icons from that desktop aligned to each other
587 int x1
= x
+ 5 + iconWidth
+ 8 + wmax
+ 5;
590 createClientList(list
, it
, 0, false);
591 // clients are in reversed stacking order
592 for ( int i
= list
.size() - 1; i
>=0; i
-- )
594 if ( !list
.at( i
)->miniIcon().isNull() )
596 if ( x1
+18 >= x
+r
.width() ) // only show full icons
599 p
.drawPixmap( x1
, y
+ (lineHeight
- 16)/2, list
.at( i
)->miniIcon() );
606 if ( y
>= r
.height() ) break;
613 Notify effects that the tab box is being shown, and only display the
614 default tab box QFrame if no effect has referenced the tab box.
619 static_cast<EffectsHandlerImpl
*>(effects
)->tabBoxAdded( mode());
628 Notify effects that the tab box is being hidden.
632 delayedShowTimer
.stop();
636 static_cast<EffectsHandlerImpl
*>(effects
)->tabBoxClosed();
638 kDebug( 1212 ) << "Tab box was not properly closed by an effect";
640 QApplication::syncX();
642 while (XCheckTypedEvent (display(), EnterNotify
, &otherEvent
) )
648 Decrease the reference count. Only when the reference count is 0 will
649 the default tab box be shown.
651 void TabBox::unrefDisplay()
656 void TabBox::reconfigure()
658 KSharedConfigPtr
c(KGlobal::config());
659 options_traverse_all
= c
->group("TabBox").readEntry("TraverseAll", false );
663 Rikkus: please document! (Matthias)
665 Ok, here's the docs :)
667 You call delayedShow() instead of show() directly.
669 If the 'ShowDelay' setting is false, show() is simply called.
671 Otherwise, we start a timer for the delay given in the settings and only
672 do a show() when it times out.
674 This means that you can alt-tab between windows and you don't see the
675 tab box immediately. Not only does this make alt-tabbing faster, it gives
676 less 'flicker' to the eyes. You don't need to see the tab box if you're
677 just quickly switching between 2 or 3 windows. It seems to work quite
680 void TabBox::delayedShow()
682 KSharedConfigPtr
c(KGlobal::config());
683 KConfigGroup
cg(c
, "TabBox");
684 bool delay
= cg
.readEntry("ShowDelay", true);
692 int delayTime
= cg
.readEntry("DelayTime", 90);
693 delayedShowTimer
.setSingleShot(true);
694 delayedShowTimer
.start(delayTime
);
698 void TabBox::handleMouseEvent( XEvent
* e
)
700 XAllowEvents( display(), AsyncPointer
, xTime());
701 if( !isVisible() && isDisplayed())
702 { // tabbox has been replaced, check effects
703 if( effects
&& static_cast<EffectsHandlerImpl
*>(effects
)->checkInputWindowEvent( e
))
706 if( e
->type
!= ButtonPress
)
708 QPoint
pos( e
->xbutton
.x_root
, e
->xbutton
.y_root
);
709 QPoint widgetPos
= mapFromGlobal( pos
); // inside tabbox
711 if(( !isVisible() && isDisplayed())
712 || !geometry().contains( pos
))
714 workspace()->closeTabBox(); // click outside closes tab
718 int num
= (widgetPos
.y()-frameWidth()) / lineHeight
;
720 if( mode() == TabBoxWindowsMode
)
722 for( ClientList::ConstIterator it
= clients
.constBegin();
723 it
!= clients
.constEnd();
726 if( workspace()->hasClient( *it
) && (num
== 0) ) // safety
728 setCurrentClient( *it
);
736 foreach( int it
, desktops
)
740 setCurrentDesktop( it
);
749 //*******************************
751 //*******************************
755 Handles alt-tab / control-tab
759 bool areKeySymXsDepressed( bool bAll
, const uint keySyms
[], int nKeySyms
)
763 kDebug(125) << "areKeySymXsDepressed: " << (bAll
? "all of " : "any of ") << nKeySyms
;
765 XQueryKeymap( display(), keymap
);
767 for( int iKeySym
= 0; iKeySym
< nKeySyms
; iKeySym
++ )
769 uint keySymX
= keySyms
[ iKeySym
];
770 uchar keyCodeX
= XKeysymToKeycode( display(), keySymX
);
771 int i
= keyCodeX
/ 8;
772 char mask
= 1 << (keyCodeX
- (i
* 8));
774 // Abort if bad index value,
775 if( i
< 0 || i
>= 32 )
778 kDebug(125) << iKeySym
<< ": keySymX=0x" << QString::number( keySymX
, 16 )
779 << " i=" << i
<< " mask=0x" << QString::number( mask
, 16 )
780 << " keymap[i]=0x" << QString::number( keymap
[i
], 16 ) << endl
;
782 // If ALL keys passed need to be depressed,
785 if( (keymap
[i
] & mask
) == 0 )
790 // If we are looking for ANY key press, and this key is depressed,
791 if( keymap
[i
] & mask
)
796 // If we were looking for ANY key press, then none was found, return false,
797 // If we were looking for ALL key presses, then all were found, return true.
801 static bool areModKeysDepressed( const QKeySequence
& seq
)
807 int mod
= seq
[seq
.count()-1] & Qt::KeyboardModifierMask
;
809 if ( mod
& Qt::SHIFT
)
811 rgKeySyms
[nKeySyms
++] = XK_Shift_L
;
812 rgKeySyms
[nKeySyms
++] = XK_Shift_R
;
814 if ( mod
& Qt::CTRL
)
816 rgKeySyms
[nKeySyms
++] = XK_Control_L
;
817 rgKeySyms
[nKeySyms
++] = XK_Control_R
;
821 rgKeySyms
[nKeySyms
++] = XK_Alt_L
;
822 rgKeySyms
[nKeySyms
++] = XK_Alt_R
;
826 // It would take some code to determine whether the Win key
827 // is associated with Super or Meta, so check for both.
828 // See bug #140023 for details.
829 rgKeySyms
[nKeySyms
++] = XK_Super_L
;
830 rgKeySyms
[nKeySyms
++] = XK_Super_R
;
831 rgKeySyms
[nKeySyms
++] = XK_Meta_L
;
832 rgKeySyms
[nKeySyms
++] = XK_Meta_R
;
835 return areKeySymXsDepressed( false, rgKeySyms
, nKeySyms
);
838 static bool areModKeysDepressed( const KShortcut
& cut
)
840 if( areModKeysDepressed( cut
.primary()) || areModKeysDepressed( cut
.alternate()) )
846 void Workspace::slotWalkThroughWindows()
848 if ( tab_grab
|| control_grab
)
850 if ( options
->altTabStyle
== Options::CDE
|| !options
->focusPolicyIsReasonable())
852 //ungrabXKeyboard(); // need that because of accelerator raw mode
853 // CDE style raise / lower
854 CDEWalkThroughWindows( true );
858 if ( areModKeysDepressed( cutWalkThroughWindows
) )
860 if ( startKDEWalkThroughWindows() )
861 KDEWalkThroughWindows( true );
864 // if the shortcut has no modifiers, don't show the tabbox,
865 // don't grab, but simply go to the next window
866 KDEOneStepThroughWindows( true );
870 void Workspace::slotWalkBackThroughWindows()
872 if( tab_grab
|| control_grab
)
874 if ( options
->altTabStyle
== Options::CDE
|| !options
->focusPolicyIsReasonable())
876 // CDE style raise / lower
877 CDEWalkThroughWindows( false );
881 if ( areModKeysDepressed( cutWalkThroughWindowsReverse
) )
883 if ( startKDEWalkThroughWindows() )
884 KDEWalkThroughWindows( false );
888 KDEOneStepThroughWindows( false );
893 void Workspace::slotWalkThroughDesktops()
895 if( tab_grab
|| control_grab
)
897 if ( areModKeysDepressed( cutWalkThroughDesktops
) )
899 if ( startWalkThroughDesktops() )
900 walkThroughDesktops( true );
904 oneStepThroughDesktops( true );
908 void Workspace::slotWalkBackThroughDesktops()
910 if( tab_grab
|| control_grab
)
912 if ( areModKeysDepressed( cutWalkThroughDesktopsReverse
) )
914 if ( startWalkThroughDesktops() )
915 walkThroughDesktops( false );
919 oneStepThroughDesktops( false );
923 void Workspace::slotWalkThroughDesktopList()
925 if( tab_grab
|| control_grab
)
927 if ( areModKeysDepressed( cutWalkThroughDesktopList
) )
929 if ( startWalkThroughDesktopList() )
930 walkThroughDesktops( true );
934 oneStepThroughDesktopList( true );
938 void Workspace::slotWalkBackThroughDesktopList()
940 if( tab_grab
|| control_grab
)
942 if ( areModKeysDepressed( cutWalkThroughDesktopListReverse
) )
944 if ( startWalkThroughDesktopList() )
945 walkThroughDesktops( false );
949 oneStepThroughDesktopList( false );
953 void Workspace::modalActionsSwitch( bool enabled
)
955 QList
<KActionCollection
*> collections
;
956 collections
.append( keys
);
957 collections
.append( disable_shortcuts_keys
);
958 collections
.append( client_keys
);
959 foreach (KActionCollection
* collection
, collections
)
960 foreach (QAction
*action
, collection
->actions())
961 action
->setEnabled(enabled
);
964 bool Workspace::startKDEWalkThroughWindows()
966 if( !establishTabBoxGrab())
969 modalActionsSwitch( false );
970 tab_box
->setMode( TabBoxWindowsMode
);
975 bool Workspace::startWalkThroughDesktops( TabBoxMode mode
)
977 if( !establishTabBoxGrab())
980 modalActionsSwitch( false );
981 tab_box
->setMode( mode
);
986 bool Workspace::startWalkThroughDesktops()
988 return startWalkThroughDesktops( TabBoxDesktopMode
);
991 bool Workspace::startWalkThroughDesktopList()
993 return startWalkThroughDesktops( TabBoxDesktopListMode
);
996 void Workspace::KDEWalkThroughWindows( bool forward
)
998 tab_box
->nextPrev( forward
);
999 tab_box
->delayedShow();
1002 void Workspace::walkThroughDesktops( bool forward
)
1004 tab_box
->nextPrev( forward
);
1005 tab_box
->delayedShow();
1008 void Workspace::CDEWalkThroughWindows( bool forward
)
1011 // this function find the first suitable client for unreasonable focus
1012 // policies - the topmost one, with some exceptions (can't be keepabove/below,
1013 // otherwise it gets stuck on them)
1014 Q_ASSERT( block_stacking_updates
== 0 );
1015 for( int i
= stacking_order
.size() - 1;
1019 Client
* it
= stacking_order
.at( i
);
1020 if ( it
->isOnCurrentDesktop() && !it
->isSpecialWindow()
1021 && it
->isShown( false ) && it
->wantsTabFocus()
1022 && !it
->keepAbove() && !it
->keepBelow())
1029 bool options_traverse_all
;
1031 KConfigGroup
group( KGlobal::config(), "TabBox" );
1032 options_traverse_all
= group
.readEntry("TraverseAll", false );
1035 Client
* firstClient
= 0;
1038 nc
= forward
? nextClientStatic(nc
) : previousClientStatic(nc
);
1041 // When we see our first client for the second time,
1042 // it's time to stop.
1045 else if (nc
== firstClient
)
1047 // No candidates found.
1051 } while (nc
&& nc
!= c
&&
1052 (( !options_traverse_all
&& !nc
->isOnDesktop(currentDesktop())) ||
1053 nc
->isMinimized() || !nc
->wantsTabFocus() || nc
->keepAbove() || nc
->keepBelow() ) );
1058 if ( options
->focusPolicyIsReasonable() )
1060 activateClient( nc
);
1061 if( nc
->isShade() && options
->shadeHover
)
1062 nc
->setShade( ShadeActivated
);
1066 if( !nc
->isOnDesktop( currentDesktop()))
1067 setCurrentDesktop( nc
->desktop());
1073 void Workspace::KDEOneStepThroughWindows( bool forward
)
1075 tab_box
->setMode( TabBoxWindowsMode
);
1077 tab_box
->nextPrev( forward
);
1078 if( Client
* c
= tab_box
->currentClient() )
1080 activateClient( c
);
1081 if( c
->isShade() && options
->shadeHover
)
1082 c
->setShade( ShadeActivated
);
1086 void Workspace::oneStepThroughDesktops( bool forward
, TabBoxMode mode
)
1088 tab_box
->setMode( mode
);
1090 tab_box
->nextPrev( forward
);
1091 if ( tab_box
->currentDesktop() != -1 )
1092 setCurrentDesktop( tab_box
->currentDesktop() );
1095 void Workspace::oneStepThroughDesktops( bool forward
)
1097 oneStepThroughDesktops( forward
, TabBoxDesktopMode
);
1100 void Workspace::oneStepThroughDesktopList( bool forward
)
1102 oneStepThroughDesktops( forward
, TabBoxDesktopListMode
);
1106 Handles holding alt-tab / control-tab
1108 void Workspace::tabBoxKeyPress( int keyQt
)
1110 bool forward
= false;
1111 bool backward
= false;
1115 forward
= cutWalkThroughWindows
.contains( keyQt
);
1116 backward
= cutWalkThroughWindowsReverse
.contains( keyQt
);
1117 if (forward
|| backward
)
1119 kDebug(125) << "== " << cutWalkThroughWindows
.toString()
1120 << " or " << cutWalkThroughWindowsReverse
.toString() << endl
;
1121 KDEWalkThroughWindows( forward
);
1124 else if (control_grab
)
1126 forward
= cutWalkThroughDesktops
.contains( keyQt
) ||
1127 cutWalkThroughDesktopList
.contains( keyQt
);
1128 backward
= cutWalkThroughDesktopsReverse
.contains( keyQt
) ||
1129 cutWalkThroughDesktopListReverse
.contains( keyQt
);
1130 if (forward
|| backward
)
1131 walkThroughDesktops(forward
);
1134 if (control_grab
|| tab_grab
)
1136 if ( ((keyQt
& ~Qt::KeyboardModifierMask
) == Qt::Key_Escape
)
1137 && !(forward
|| backward
) )
1138 { // if Escape is part of the shortcut, don't cancel
1144 void Workspace::refTabBox()
1147 tab_box
->refDisplay();
1150 void Workspace::unrefTabBox()
1153 tab_box
->unrefDisplay();
1156 void Workspace::closeTabBox()
1160 modalActionsSwitch( true );
1162 control_grab
= false;
1166 Handles alt-tab / control-tab releasing
1168 void Workspace::tabBoxKeyRelease( const XKeyEvent
& ev
)
1170 unsigned int mk
= ev
.state
&
1171 (KKeyServer::modXShift() |
1172 KKeyServer::modXCtrl() |
1173 KKeyServer::modXAlt() |
1174 KKeyServer::modXMeta() );
1175 // ev.state is state before the key release, so just checking mk being 0 isn't enough
1176 // using XQueryPointer() also doesn't seem to work well, so the check that all
1177 // modifiers are released: only one modifier is active and the currently released
1178 // key is this modifier - if yes, release the grab
1180 for( int i
= ShiftMapIndex
;
1183 if(( mk
& ( 1 << i
)) != 0 )
1185 if( mod_index
>= 0 )
1189 bool release
= false;
1190 if( mod_index
== -1 )
1194 XModifierKeymap
* xmk
= XGetModifierMapping(display());
1195 for (int i
=0; i
<xmk
->max_keypermod
; i
++)
1196 if (xmk
->modifiermap
[xmk
->max_keypermod
* mod_index
+ i
]
1199 XFreeModifiermap(xmk
);
1205 bool old_control_grab
= control_grab
;
1207 control_grab
= old_control_grab
;
1208 if( Client
* c
= tab_box
->currentClient())
1210 activateClient( c
);
1211 if( c
->isShade() && options
->shadeHover
)
1212 c
->setShade( ShadeActivated
);
1217 bool old_tab_grab
= tab_grab
;
1219 tab_grab
= old_tab_grab
;
1220 if ( tab_box
->currentDesktop() != -1 )
1222 setCurrentDesktop( tab_box
->currentDesktop() );
1228 int Workspace::nextDesktopFocusChain( int iDesktop
) const
1230 int i
= desktop_focus_chain
.indexOf( iDesktop
);
1231 if( i
>= 0 && i
+1 < (int)desktop_focus_chain
.size() )
1232 return desktop_focus_chain
[i
+1];
1233 else if( desktop_focus_chain
.size() > 0 )
1234 return desktop_focus_chain
[ 0 ];
1239 int Workspace::previousDesktopFocusChain( int iDesktop
) const
1241 int i
= desktop_focus_chain
.indexOf( iDesktop
);
1243 return desktop_focus_chain
[i
-1];
1244 else if( desktop_focus_chain
.size() > 0 )
1245 return desktop_focus_chain
[desktop_focus_chain
.size()-1];
1247 return numberOfDesktops();
1250 int Workspace::nextDesktopStatic( int iDesktop
) const
1253 if( i
> numberOfDesktops())
1258 int Workspace::previousDesktopStatic( int iDesktop
) const
1262 i
= numberOfDesktops();
1267 auxiliary functions to travers all clients according to the focus
1268 order. Useful for kwms Alt-tab feature.
1270 Client
* Workspace::nextClientFocusChain( Client
* c
) const
1272 if ( global_focus_chain
.isEmpty() )
1274 int pos
= global_focus_chain
.indexOf( c
);
1276 return global_focus_chain
.last();
1278 return global_focus_chain
.last();
1280 return global_focus_chain
[ pos
];
1284 auxiliary functions to travers all clients according to the focus
1285 order. Useful for kwms Alt-tab feature.
1287 Client
* Workspace::previousClientFocusChain( Client
* c
) const
1289 if ( global_focus_chain
.isEmpty() )
1291 int pos
= global_focus_chain
.indexOf( c
);
1293 return global_focus_chain
.first();
1295 if ( pos
== global_focus_chain
.count() )
1296 return global_focus_chain
.first();
1297 return global_focus_chain
[ pos
];
1301 auxiliary functions to travers all clients according to the static
1302 order. Useful for the CDE-style Alt-tab feature.
1304 Client
* Workspace::nextClientStatic( Client
* c
) const
1306 if ( !c
|| clients
.isEmpty() )
1308 int pos
= clients
.indexOf( c
);
1310 return clients
.first();
1312 if ( pos
== clients
.count() )
1313 return clients
.first();
1314 return clients
[ pos
];
1317 auxiliary functions to travers all clients according to the static
1318 order. Useful for the CDE-style Alt-tab feature.
1320 Client
* Workspace::previousClientStatic( Client
* c
) const
1322 if ( !c
|| clients
.isEmpty() )
1324 int pos
= clients
.indexOf( c
);
1326 return clients
.last();
1328 return clients
.last();
1330 return clients
[ pos
];
1333 Client
* Workspace::currentTabBoxClient() const
1337 return tab_box
->currentClient();
1340 ClientList
Workspace::currentTabBoxClientList() const
1343 return ClientList();
1344 return tab_box
->currentClientList();
1347 int Workspace::currentTabBoxDesktop() const
1351 return tab_box
->currentDesktop();
1354 QList
< int > Workspace::currentTabBoxDesktopList() const
1357 return QList
< int >();
1358 return tab_box
->currentDesktopList();
1361 void Workspace::setTabBoxClient( Client
* c
)
1364 tab_box
->setCurrentClient( c
);
1367 void Workspace::setTabBoxDesktop( int iDesktop
)
1370 tab_box
->setCurrentDesktop( iDesktop
);
1373 bool Workspace::establishTabBoxGrab()
1375 if( !grabXKeyboard())
1377 // Don't try to establish a global mouse grab using XGrabPointer, as that would prevent
1378 // using Alt+Tab while DND (#44972). However force passive grabs on all windows
1379 // in order to catch MouseRelease events and close the tabbox (#67416).
1380 // All clients already have passive grabs in their wrapper windows, so check only
1381 // the active client, which may not have it.
1382 assert( !forced_global_mouse_grab
);
1383 forced_global_mouse_grab
= true;
1384 if( active_client
!= NULL
)
1385 active_client
->updateMouseGrab();
1389 void Workspace::removeTabBoxGrab()
1392 assert( forced_global_mouse_grab
);
1393 forced_global_mouse_grab
= false;
1394 if( active_client
!= NULL
)
1395 active_client
->updateMouseGrab();
1400 #include "tabbox.moc"