not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kwin / tabbox.cpp
blob5d1a1739a5c2beae6d28877d18c4cdf386cfafa6
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
23 #include "tabbox.h"
24 #include <QTextStream>
25 #include "workspace.h"
26 #include "effects.h"
27 #include "client.h"
28 #include <QPainter>
29 #include <QLabel>
30 #include <qdrawutil.h>
31 #include <QStyle>
32 #include <kglobal.h>
33 #include <fixx11h.h>
34 #include <kconfig.h>
35 #include <klocale.h>
36 #include <QApplication>
37 #include <QDesktopWidget>
38 #include <QAction>
39 #include <stdarg.h>
40 #include <kdebug.h>
41 #include <kglobalsettings.h>
42 #include <kiconeffect.h>
43 #include <X11/keysym.h>
44 #include <X11/keysymdef.h>
45 #include <QX11Info>
46 #include <kactioncollection.h>
47 #include <kkeyserver.h>
48 #include <kconfiggroup.h>
50 // specify externals before namespace
52 namespace KWin
55 extern QPixmap* kwin_get_menu_pix_hack();
57 TabBox::TabBox( Workspace *ws )
58 : QFrame( 0, Qt::X11BypassWindowManagerHint )
59 , wspace(ws)
60 , client(0)
61 , display_refcount( 0 )
63 setFrameStyle(QFrame::StyledPanel);
64 setFrameShadow(QFrame::Raised);
65 setBackgroundRole(QPalette::Base);
66 setLineWidth(3);
67 setMidLineWidth(3);
68 setContentsMargins( 3, 3, 3, 3 );
70 showMiniIcon = false;
72 no_tasks = i18n("*** No Windows ***");
73 m = TabBoxDesktopMode; // init variables
74 reconfigure();
75 reset();
76 connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show()));
79 TabBox::~TabBox()
84 /*!
85 Sets the current mode to \a mode, either TabBoxDesktopListMode or TabBoxWindowsMode
87 \sa mode()
89 void TabBox::setMode( TabBoxMode mode )
91 m = mode;
95 /*!
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;
102 list.clear();
104 Client* start = c;
106 if ( chain )
107 c = workspace()->nextClientFocusChain(c);
108 else
109 c = workspace()->stackingOrder().first();
111 Client* stop = c;
113 while ( c )
115 Client* add = NULL;
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 )
121 add = c;
122 else if( !list.contains( modal ))
123 add = modal;
124 else
126 // nothing
129 if( options->separateScreenFocus && options->xineramaEnabled )
131 if( c->screen() != workspace()->activeScreen())
132 add = NULL;
134 if( add != NULL )
136 if ( start == add )
138 list.removeAll( add );
139 list.prepend( add );
141 else
142 list += add;
144 if ( chain )
145 c = workspace()->nextClientFocusChain( c );
146 else
148 if ( idx >= (workspace()->stackingOrder().size()-1) )
149 c = 0;
150 else
151 c = workspace()->stackingOrder()[++idx];
154 if ( c == stop )
155 break;
161 Create list of desktops, starting with desktop start
163 void TabBox::createDesktopList(QList< int > &list, int start, SortOrder order)
165 list.clear();
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 );
176 else
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();
203 else
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
220 QFont f = font();
221 f.setBold( true );
222 f.setPointSize( 14 );
224 h = QFontMetrics(f).height()*4;
226 else
228 showMiniIcon = false;
229 h = clients.count() * lineHeight;
231 if ( h > (r.height()-(2*frameWidth())) ) // if too high, use mini icons
233 showMiniIcon = true;
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;
251 else
253 int starting_desktop;
254 if( mode() == TabBoxDesktopListMode )
256 starting_desktop = 1;
257 createDesktopList(desktops, starting_desktop, StaticOrder );
259 else
260 { // TabBoxDesktopMode
261 starting_desktop = workspace()->currentDesktop();
262 createDesktopList(desktops, starting_desktop, MostRecentlyUsedOrder );
265 if( !partial_reset )
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(),
287 w, h );
289 if( effects )
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;
305 if ( next )
306 newClient = workspace()->nextClientFocusChain(newClient);
307 else
308 newClient = workspace()->previousClientFocusChain(newClient);
309 if (!firstClient)
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.
318 newClient = 0;
319 break;
321 } while ( newClient && !clients.contains( newClient ));
322 setCurrentClient( newClient );
324 else if( mode() == TabBoxDesktopMode )
326 setCurrentDesktop ( next ? workspace()->nextDesktopFocusChain( desk )
327 : workspace()->previousDesktopFocusChain( desk ) );
329 else
330 { // TabBoxDesktopListMode
331 setCurrentDesktop ( next ? workspace()->nextDesktopStatic( desk )
332 : workspace()->previousDesktopStatic( desk )) ;
335 if( effects )
336 static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
337 update();
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 )
349 return 0;
350 if (!workspace()->hasClient( client ))
351 return 0;
352 return client;
356 Returns the list of clients potentially displayed ( only works in
357 TabBoxWindowsMode ).
358 Returns an empty list if no clients are available.
360 ClientList TabBox::currentClientList()
362 if( mode() != TabBoxWindowsMode )
363 return ClientList();
364 return clients;
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 )
376 return desk;
377 return -1;
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 )
389 return desktops;
390 return QList< int >();
395 Change the currently selected client, and notify the effects.
397 \sa setCurrentDesktop()
399 void TabBox::setCurrentClient( Client* newClient )
401 client = newClient;
402 if( effects )
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 )
413 desk = newDesktop;
414 if( effects )
415 static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
419 Reimplemented to raise the tab box as well
421 void TabBox::showEvent( QShowEvent* )
423 raise();
428 hide the icon box if necessary
430 void TabBox::hideEvent( QHideEvent* )
435 Paints the tab box
437 void TabBox::paintEvent( QPaintEvent* e )
439 QFrame::paintEvent( e );
441 QPainter p( this );
442 QRect r( contentsRect());
444 QPixmap* menu_pix = kwin_get_menu_pix_hack();
446 int iconWidth = showMiniIcon ? 16 : 32;
447 int x = r.x();
448 int y = r.y();
450 if ( mode () == TabBoxWindowsMode )
452 if ( !currentClient() )
454 QFont f = font();
455 f.setBold( true );
456 f.setPointSize( 14 );
458 p.setFont(f);
459 p.drawText( r, Qt::AlignCenter, no_tasks);
461 else
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 ));
471 // draw icon
472 QPixmap icon;
473 if ( showMiniIcon )
475 if ( !(*it)->miniIcon().isNull() )
476 icon = (*it)->miniIcon();
478 else
479 if ( !(*it)->icon().isNull() )
480 icon = (*it)->icon();
481 else if ( menu_pix )
482 icon = *menu_pix;
484 if( !icon.isNull())
486 if( (*it)->isMinimized())
487 KIconEffect::semiTransparent( icon );
488 p.drawPixmap( x+5, y + (lineHeight - iconWidth)/2, icon );
491 // generate text to display
492 QString s;
494 if ( !(*it)->isOnDesktop(workspace()->currentDesktop()) )
495 s = workspace()->desktopName((*it)->desktop()) + ": ";
497 if ( (*it)->isMinimized() )
498 s += '(' + (*it)->caption() + ')';
499 else
500 s += (*it)->caption();
502 s = fontMetrics().elidedText( s, Qt::ElideMiddle, r.width() - 5 - iconWidth - 8 );
504 // draw text
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()
512 int r1, g1, b1;
513 int r2, g2, b2;
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 ));
524 else
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);
530 y += lineHeight;
532 if ( y >= r.height() ) break;
536 else
537 { // TabBoxDesktopMode || TabBoxDesktopListMode
538 int iconHeight = iconWidth;
540 // get widest desktop name/number
541 QFont f(font());
542 f.setBold(true);
543 f.setPixelSize(iconHeight - 4); // pixel, not point because I need to know the pixels
544 QFontMetrics fm(f);
546 int wmax = 0;
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 ));
562 p.save();
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
570 p.setFont(f);
571 QString num = QString::number(it);
572 p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num);
574 p.restore();
576 // draw desktop name text
577 if ( it == desk )
578 p.setPen(palette().color( QPalette::Active, QPalette::HighlightedText ));
579 else
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;
589 ClientList list;
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
597 break;
599 p.drawPixmap( x1, y + (lineHeight - 16)/2, list.at( i )->miniIcon() );
600 x1 += 18;
604 // next desktop
605 y += lineHeight;
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.
616 void TabBox::show()
618 if( effects )
619 static_cast<EffectsHandlerImpl*>(effects)->tabBoxAdded( mode());
620 if( isDisplayed())
621 return;
622 refDisplay();
623 QWidget::show();
628 Notify effects that the tab box is being hidden.
630 void TabBox::hide()
632 delayedShowTimer.stop();
633 if( isVisible())
634 unrefDisplay();
635 if( effects )
636 static_cast<EffectsHandlerImpl*>(effects)->tabBoxClosed();
637 if( isDisplayed())
638 kDebug( 1212 ) << "Tab box was not properly closed by an effect";
639 QWidget::hide();
640 QApplication::syncX();
641 XEvent otherEvent;
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()
653 --display_refcount;
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
678 nicely.
680 void TabBox::delayedShow()
682 KSharedConfigPtr c(KGlobal::config());
683 KConfigGroup cg(c, "TabBox");
684 bool delay = cg.readEntry("ShowDelay", true);
686 if (!delay)
688 show();
689 return;
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 ))
704 return;
706 if( e->type != ButtonPress )
707 return;
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
715 return;
718 int num = (widgetPos.y()-frameWidth()) / lineHeight;
720 if( mode() == TabBoxWindowsMode )
722 for( ClientList::ConstIterator it = clients.constBegin();
723 it != clients.constEnd();
724 ++it)
726 if( workspace()->hasClient( *it ) && (num == 0) ) // safety
728 setCurrentClient( *it );
729 break;
731 num--;
734 else
736 foreach( int it, desktops )
738 if( num == 0 )
740 setCurrentDesktop( it );
741 break;
743 num--;
746 update();
749 //*******************************
750 // Workspace
751 //*******************************
755 Handles alt-tab / control-tab
758 static
759 bool areKeySymXsDepressed( bool bAll, const uint keySyms[], int nKeySyms )
761 char keymap[32];
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 )
776 return false;
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,
783 if( bAll )
785 if( (keymap[i] & mask) == 0 )
786 return false;
788 else
790 // If we are looking for ANY key press, and this key is depressed,
791 if( keymap[i] & mask )
792 return true;
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.
798 return bAll;
801 static bool areModKeysDepressed( const QKeySequence& seq )
803 uint rgKeySyms[10];
804 int nKeySyms = 0;
805 if( seq.isEmpty())
806 return false;
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;
819 if( mod & Qt::ALT )
821 rgKeySyms[nKeySyms++] = XK_Alt_L;
822 rgKeySyms[nKeySyms++] = XK_Alt_R;
824 if( mod & Qt::META )
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()) )
841 return true;
843 return false;
846 void Workspace::slotWalkThroughWindows()
848 if ( tab_grab || control_grab )
849 return;
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 );
856 else
858 if ( areModKeysDepressed( cutWalkThroughWindows ) )
860 if ( startKDEWalkThroughWindows() )
861 KDEWalkThroughWindows( true );
863 else
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 )
873 return;
874 if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable())
876 // CDE style raise / lower
877 CDEWalkThroughWindows( false );
879 else
881 if ( areModKeysDepressed( cutWalkThroughWindowsReverse ) )
883 if ( startKDEWalkThroughWindows() )
884 KDEWalkThroughWindows( false );
886 else
888 KDEOneStepThroughWindows( false );
893 void Workspace::slotWalkThroughDesktops()
895 if( tab_grab || control_grab )
896 return;
897 if ( areModKeysDepressed( cutWalkThroughDesktops ) )
899 if ( startWalkThroughDesktops() )
900 walkThroughDesktops( true );
902 else
904 oneStepThroughDesktops( true );
908 void Workspace::slotWalkBackThroughDesktops()
910 if( tab_grab || control_grab )
911 return;
912 if ( areModKeysDepressed( cutWalkThroughDesktopsReverse ) )
914 if ( startWalkThroughDesktops() )
915 walkThroughDesktops( false );
917 else
919 oneStepThroughDesktops( false );
923 void Workspace::slotWalkThroughDesktopList()
925 if( tab_grab || control_grab )
926 return;
927 if ( areModKeysDepressed( cutWalkThroughDesktopList ) )
929 if ( startWalkThroughDesktopList() )
930 walkThroughDesktops( true );
932 else
934 oneStepThroughDesktopList( true );
938 void Workspace::slotWalkBackThroughDesktopList()
940 if( tab_grab || control_grab )
941 return;
942 if ( areModKeysDepressed( cutWalkThroughDesktopListReverse ) )
944 if ( startWalkThroughDesktopList() )
945 walkThroughDesktops( false );
947 else
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())
967 return false;
968 tab_grab = true;
969 modalActionsSwitch( false );
970 tab_box->setMode( TabBoxWindowsMode );
971 tab_box->reset();
972 return true;
975 bool Workspace::startWalkThroughDesktops( TabBoxMode mode )
977 if( !establishTabBoxGrab())
978 return false;
979 control_grab = true;
980 modalActionsSwitch( false );
981 tab_box->setMode( mode );
982 tab_box->reset();
983 return true;
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 )
1010 Client* c = NULL;
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;
1016 i >= 0 ;
1017 --i )
1019 Client* it = stacking_order.at( i );
1020 if ( it->isOnCurrentDesktop() && !it->isSpecialWindow()
1021 && it->isShown( false ) && it->wantsTabFocus()
1022 && !it->keepAbove() && !it->keepBelow())
1024 c = it;
1025 break;
1028 Client* nc = c;
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);
1039 if (!firstClient)
1041 // When we see our first client for the second time,
1042 // it's time to stop.
1043 firstClient = nc;
1045 else if (nc == firstClient)
1047 // No candidates found.
1048 nc = 0;
1049 break;
1051 } while (nc && nc != c &&
1052 (( !options_traverse_all && !nc->isOnDesktop(currentDesktop())) ||
1053 nc->isMinimized() || !nc->wantsTabFocus() || nc->keepAbove() || nc->keepBelow() ) );
1054 if (nc)
1056 if (c && c != nc)
1057 lowerClient( c );
1058 if ( options->focusPolicyIsReasonable() )
1060 activateClient( nc );
1061 if( nc->isShade() && options->shadeHover )
1062 nc->setShade( ShadeActivated );
1064 else
1066 if( !nc->isOnDesktop( currentDesktop()))
1067 setCurrentDesktop( nc->desktop());
1068 raiseClient( nc );
1073 void Workspace::KDEOneStepThroughWindows( bool forward )
1075 tab_box->setMode( TabBoxWindowsMode );
1076 tab_box->reset();
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 );
1089 tab_box->reset();
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;
1113 if (tab_grab)
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
1139 closeTabBox();
1144 void Workspace::refTabBox()
1146 if( tab_box )
1147 tab_box->refDisplay();
1150 void Workspace::unrefTabBox()
1152 if( tab_box )
1153 tab_box->unrefDisplay();
1156 void Workspace::closeTabBox()
1158 removeTabBoxGrab();
1159 tab_box->hide();
1160 modalActionsSwitch( true );
1161 tab_grab = false;
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
1179 int mod_index = -1;
1180 for( int i = ShiftMapIndex;
1181 i <= Mod5MapIndex;
1182 ++i )
1183 if(( mk & ( 1 << i )) != 0 )
1185 if( mod_index >= 0 )
1186 return;
1187 mod_index = i;
1189 bool release = false;
1190 if( mod_index == -1 )
1191 release = true;
1192 else
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]
1197 == ev.keycode)
1198 release = true;
1199 XFreeModifiermap(xmk);
1201 if( !release )
1202 return;
1203 if (tab_grab)
1205 bool old_control_grab = control_grab;
1206 closeTabBox();
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 );
1215 if (control_grab)
1217 bool old_tab_grab = tab_grab;
1218 closeTabBox();
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 ];
1235 else
1236 return 1;
1239 int Workspace::previousDesktopFocusChain( int iDesktop ) const
1241 int i = desktop_focus_chain.indexOf( iDesktop );
1242 if( i-1 >= 0 )
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];
1246 else
1247 return numberOfDesktops();
1250 int Workspace::nextDesktopStatic( int iDesktop ) const
1252 int i = ++iDesktop;
1253 if( i > numberOfDesktops())
1254 i = 1;
1255 return i;
1258 int Workspace::previousDesktopStatic( int iDesktop ) const
1260 int i = --iDesktop;
1261 if( i < 1 )
1262 i = numberOfDesktops();
1263 return i;
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() )
1273 return 0;
1274 int pos = global_focus_chain.indexOf( c );
1275 if ( pos == -1 )
1276 return global_focus_chain.last();
1277 if ( pos == 0 )
1278 return global_focus_chain.last();
1279 pos--;
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() )
1290 return 0;
1291 int pos = global_focus_chain.indexOf( c );
1292 if ( pos == -1 )
1293 return global_focus_chain.first();
1294 pos++;
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() )
1307 return 0;
1308 int pos = clients.indexOf( c );
1309 if ( pos == -1 )
1310 return clients.first();
1311 ++pos;
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() )
1323 return 0;
1324 int pos = clients.indexOf( c );
1325 if ( pos == -1 )
1326 return clients.last();
1327 if ( pos == 0 )
1328 return clients.last();
1329 --pos;
1330 return clients[ pos ];
1333 Client* Workspace::currentTabBoxClient() const
1335 if( !tab_box )
1336 return 0;
1337 return tab_box->currentClient();
1340 ClientList Workspace::currentTabBoxClientList() const
1342 if( !tab_box )
1343 return ClientList();
1344 return tab_box->currentClientList();
1347 int Workspace::currentTabBoxDesktop() const
1349 if( !tab_box )
1350 return -1;
1351 return tab_box->currentDesktop();
1354 QList< int > Workspace::currentTabBoxDesktopList() const
1356 if( !tab_box )
1357 return QList< int >();
1358 return tab_box->currentDesktopList();
1361 void Workspace::setTabBoxClient( Client* c )
1363 if( tab_box )
1364 tab_box->setCurrentClient( c );
1367 void Workspace::setTabBoxDesktop( int iDesktop )
1369 if( tab_box )
1370 tab_box->setCurrentDesktop( iDesktop );
1373 bool Workspace::establishTabBoxGrab()
1375 if( !grabXKeyboard())
1376 return false;
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();
1386 return true;
1389 void Workspace::removeTabBoxGrab()
1391 ungrabXKeyboard();
1392 assert( forced_global_mouse_grab );
1393 forced_global_mouse_grab = false;
1394 if( active_client != NULL )
1395 active_client->updateMouseGrab();
1398 } // namespace
1400 #include "tabbox.moc"