• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KWin

tabbox.cpp

Go to the documentation of this file.
00001 /********************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
00007 
00008 This program is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020 *********************************************************************/
00021 
00022 //#define QT_CLEAN_NAMESPACE
00023 #include "tabbox.h"
00024 #include <QTextStream>
00025 #include "workspace.h"
00026 #include "effects.h"
00027 #include "client.h"
00028 #include <QPainter>
00029 #include <QLabel>
00030 #include <qdrawutil.h>
00031 #include <QStyle>
00032 #include <kglobal.h>
00033 #include <fixx11h.h>
00034 #include <kconfig.h>
00035 #include <klocale.h>
00036 #include <QApplication>
00037 #include <QDesktopWidget>
00038 #include <QAction>
00039 #include <stdarg.h>
00040 #include <kdebug.h>
00041 #include <kglobalsettings.h>
00042 #include <kiconeffect.h>
00043 #include <X11/keysym.h>
00044 #include <X11/keysymdef.h>
00045 #include <QX11Info>
00046 #include <kactioncollection.h>
00047 #include <kkeyserver.h>
00048 #include <kconfiggroup.h>
00049 
00050 // specify externals before namespace
00051 
00052 namespace KWin
00053 {
00054 
00055 extern QPixmap* kwin_get_menu_pix_hack();
00056 
00057 TabBox::TabBox( Workspace *ws )
00058     : QFrame( 0, Qt::X11BypassWindowManagerHint )
00059     , wspace(ws)
00060     , client(0)
00061     , display_refcount( 0 )
00062     {
00063     setFrameStyle(QFrame::StyledPanel);
00064     setFrameShadow(QFrame::Plain);
00065     setBackgroundRole(QPalette::Base);
00066     setLineWidth(2);
00067     setMidLineWidth(2);
00068     setContentsMargins( 2, 2, 2, 2 );
00069 
00070     showMiniIcon = false;
00071 
00072     no_tasks = i18n("*** No Windows ***");
00073     m = TabBoxDesktopMode; // init variables
00074     reconfigure();
00075     reset();
00076     connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show()));
00077     }
00078 
00079 TabBox::~TabBox()
00080     {
00081     }
00082 
00083 
00089 void TabBox::setMode( TabBoxMode mode )
00090     {
00091     m = mode;
00092     }
00093 
00094 
00098 void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client *c, bool chain)
00099     {
00100     ClientList::size_type idx = 0;
00101 
00102     list.clear();
00103 
00104     Client* start = c;
00105 
00106     if ( chain )
00107         c = workspace()->nextClientFocusChain(c);
00108     else
00109         c = workspace()->stackingOrder().first();
00110 
00111     Client* stop = c;
00112 
00113     while ( c )
00114         {
00115         Client* add = NULL;
00116         if ( ((desktop == -1) || c->isOnDesktop(desktop))
00117              && c->wantsTabFocus() )
00118             { // don't add windows that have modal dialogs
00119             Client* modal = c->findModal();
00120             if( modal == NULL || modal == c )
00121                 add = c;
00122             else if( !list.contains( modal ))
00123                 add = modal;
00124             else
00125                 {
00126                 // nothing
00127                 }
00128             }
00129         if( options->separateScreenFocus && options->xineramaEnabled )
00130             {
00131             if( c->screen() != workspace()->activeScreen())
00132                 add = NULL;
00133             }
00134         if( add != NULL )
00135             {
00136             if ( start == add )
00137                 {
00138                 list.removeAll( add );
00139                 list.prepend( add );
00140                 }
00141             else
00142                 list += add;
00143             }
00144         if ( chain )
00145           c = workspace()->nextClientFocusChain( c );
00146         else
00147           {
00148           if ( idx >= (workspace()->stackingOrder().size()-1) )
00149             c = 0;
00150           else
00151             c = workspace()->stackingOrder()[++idx];
00152           }
00153 
00154         if ( c == stop )
00155             break;
00156         }
00157     }
00158 
00159 
00163 void TabBox::createDesktopList(QList< int > &list, int start, SortOrder order)
00164     {
00165     list.clear();
00166 
00167     int iDesktop = start;
00168 
00169     for( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
00170         {
00171         list.append( iDesktop );
00172         if ( order == StaticOrder )
00173             {
00174             iDesktop = workspace()->nextDesktopStatic( iDesktop );
00175             }
00176         else
00177             { // MostRecentlyUsedOrder
00178             iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
00179             }
00180         }
00181     }
00182 
00183 
00188 void TabBox::reset( bool partial_reset )
00189     {
00190     int w, h, cw = 0, wmax = 0;
00191 
00192     QRect r = workspace()->screenGeometry( workspace()->activeScreen());
00193 
00194     // calculate height of 1 line
00195     // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below
00196     lineHeight = qMax(fontMetrics().height() + 2, 32 + 4);
00197 
00198     if ( mode() == TabBoxWindowsMode )
00199         {
00200         Client* starting_client = 0;
00201         if( partial_reset && clients.count() != 0 )
00202             starting_client = clients.first();
00203         else
00204             client = starting_client = workspace()->activeClient();
00205 
00206         // get all clients to show
00207         createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), starting_client, true);
00208 
00209         // calculate maximum caption width
00210         cw = fontMetrics().width(no_tasks)+20;
00211         for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00212           {
00213           cw = fontMetrics().width( (*it)->caption() );
00214           if ( cw > wmax ) wmax = cw;
00215           }
00216 
00217         // calculate height for the popup
00218         if ( clients.count() == 0 )  // height for the "not tasks" text
00219           {
00220           QFont f = font();
00221           f.setBold( true );
00222           f.setPointSize( 14 );
00223 
00224           h = QFontMetrics(f).height()*4;
00225           }
00226         else
00227           {
00228           showMiniIcon = false;
00229           h = clients.count() * lineHeight;
00230 
00231           if ( h > (r.height()-(2*frameWidth())) )  // if too high, use mini icons
00232             {
00233             showMiniIcon = true;
00234             // fontheight + 1 pixel above + 1 pixel below, or 16x16 icon + 1 pixel above + below
00235             lineHeight = qMax(fontMetrics().height() + 2, 16 + 2);
00236 
00237             h = clients.count() * lineHeight;
00238 
00239             if ( h > (r.height()-(2*frameWidth())) ) // if still too high, remove some clients
00240               {
00241                 // how many clients to remove
00242                 int howMany = (h - (r.height()-(2*frameWidth())))/lineHeight;
00243                 for (; howMany; howMany--)
00244                   clients.removeAll(clients.last());
00245 
00246                 h = clients.count() * lineHeight;
00247               }
00248             }
00249           }
00250         }
00251     else
00252         {
00253         int starting_desktop;
00254         if( mode() == TabBoxDesktopListMode )
00255             {
00256             starting_desktop = 1;
00257             createDesktopList(desktops, starting_desktop, StaticOrder );
00258             }
00259         else
00260             { // TabBoxDesktopMode
00261             starting_desktop = workspace()->currentDesktop();
00262             createDesktopList(desktops, starting_desktop, MostRecentlyUsedOrder );
00263             }
00264 
00265         if( !partial_reset )
00266             desk = workspace()->currentDesktop();
00267 
00268         showMiniIcon = false;
00269 
00270         foreach (int it, desktops)
00271           {
00272           cw = fontMetrics().width( workspace()->desktopName(it) );
00273           if ( cw > wmax ) wmax = cw;
00274           }
00275 
00276         // calculate height for the popup (max. 16 desktops always fit in a 800x600 screen)
00277         h = desktops.count() * lineHeight;
00278         }
00279 
00280     // height, width for the popup
00281     h += 2 * frameWidth();
00282     w = 2*frameWidth() + 5*2 + ( showMiniIcon ? 16 : 32 ) + 8 + wmax; // 5*2=margins, ()=icon, 8=space between icon+text
00283     w = qBound( r.width()/3 , w, r.width() * 4 / 5 );
00284 
00285     setGeometry( (r.width()-w)/2 + r.x(),
00286                  (r.height()-h)/2+ r.y(),
00287                  w, h );
00288 
00289     if( effects )
00290         static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
00291     }
00292 
00293 
00297 void TabBox::nextPrev( bool next)
00298     {
00299     if ( mode() == TabBoxWindowsMode )
00300         {
00301         Client* firstClient = 0;
00302         Client* newClient = client;
00303         do
00304             {
00305             if ( next )
00306                 newClient = workspace()->nextClientFocusChain(newClient);
00307             else
00308                 newClient = workspace()->previousClientFocusChain(newClient);
00309             if (!firstClient)
00310                 {
00311                 // When we see our first client for the second time,
00312                 // it's time to stop.
00313                 firstClient = newClient;
00314                 }
00315             else if (newClient == firstClient)
00316                 {
00317                 // No candidates found.
00318                 newClient = 0;
00319                 break;
00320                 }
00321             } while ( newClient && !clients.contains( newClient ));
00322         setCurrentClient( newClient );
00323         }
00324     else if( mode() == TabBoxDesktopMode )
00325         {
00326         setCurrentDesktop ( next ? workspace()->nextDesktopFocusChain( desk )
00327                                  : workspace()->previousDesktopFocusChain( desk ) );
00328         }
00329     else
00330         { // TabBoxDesktopListMode
00331         setCurrentDesktop ( next ? workspace()->nextDesktopStatic( desk )
00332                                  : workspace()->previousDesktopStatic( desk )) ;
00333         }
00334 
00335     if( effects )
00336         static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
00337     update();
00338     }
00339 
00340 
00341 
00346 Client* TabBox::currentClient()
00347     {
00348     if ( mode() != TabBoxWindowsMode )
00349         return 0;
00350     if (!workspace()->hasClient( client ))
00351         return 0;
00352     return client;
00353     }
00354 
00360 ClientList TabBox::currentClientList()
00361     {
00362     if( mode() != TabBoxWindowsMode )
00363         return ClientList();
00364     return clients;
00365     }
00366 
00367 
00373 int TabBox::currentDesktop()
00374     {
00375     if ( mode() == TabBoxDesktopListMode || mode() == TabBoxDesktopMode )
00376         return desk;
00377     return -1;
00378     }
00379 
00380 
00386 QList< int > TabBox::currentDesktopList()
00387     {
00388     if ( mode() == TabBoxDesktopListMode || mode() == TabBoxDesktopMode )
00389         return desktops;
00390     return QList< int >();
00391     }
00392 
00393 
00399 void TabBox::setCurrentClient( Client* newClient )
00400     {
00401     client = newClient;
00402     if( effects )
00403         static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
00404     }
00405 
00411 void TabBox::setCurrentDesktop( int newDesktop )
00412     {
00413     desk = newDesktop;
00414     if( effects )
00415         static_cast<EffectsHandlerImpl*>(effects)->tabBoxUpdated();
00416     }
00417 
00421 void TabBox::showEvent( QShowEvent* )
00422     {
00423     raise();
00424     }
00425 
00426 
00430 void TabBox::hideEvent( QHideEvent* )
00431     {
00432     }
00433 
00437 void TabBox::paintEvent( QPaintEvent* e )
00438     {
00439     QFrame::paintEvent( e );
00440 
00441     QPainter p( this );
00442     QRect r( contentsRect());
00443 
00444     QPixmap* menu_pix = kwin_get_menu_pix_hack();
00445 
00446     int iconWidth = showMiniIcon ? 16 : 32;
00447     int x = r.x();
00448     int y = r.y();
00449 
00450     if ( mode () == TabBoxWindowsMode )
00451         {
00452         if ( !currentClient() )
00453             {
00454             QFont f = font();
00455             f.setBold( true );
00456             f.setPointSize( 14 );
00457 
00458             p.setFont(f);
00459             p.drawText( r, Qt::AlignCenter, no_tasks);
00460             }
00461         else
00462             {
00463             for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00464               {
00465               if ( workspace()->hasClient( *it ) )  // safety
00466                   {
00467                   // draw highlight background
00468                   if ( (*it) == currentClient() )
00469                     p.fillRect(x, y, r.width(), lineHeight, palette().brush( QPalette::Active, QPalette::Highlight ));
00470 
00471                   // draw icon
00472                   QPixmap icon;
00473                   if ( showMiniIcon )
00474                     {
00475                     if ( !(*it)->miniIcon().isNull() )
00476                       icon = (*it)->miniIcon();
00477                     }
00478                   else
00479                     if ( !(*it)->icon().isNull() )
00480                       icon = (*it)->icon();
00481                     else if ( menu_pix )
00482                       icon = *menu_pix;
00483                 
00484                   if( !icon.isNull())
00485                     {
00486                     if( (*it)->isMinimized())
00487                         KIconEffect::semiTransparent( icon );
00488                     p.drawPixmap( x+5, y + (lineHeight - iconWidth)/2, icon );
00489                     }
00490 
00491                   // generate text to display
00492                   QString s;
00493 
00494                   if ( !(*it)->isOnDesktop(workspace()->currentDesktop()) )
00495                     s = workspace()->desktopName((*it)->desktop()) + ": ";
00496 
00497                   if ( (*it)->isMinimized() )
00498                     s += '(' + (*it)->caption() + ')';
00499                   else
00500                     s += (*it)->caption();
00501 
00502                   s = fontMetrics().elidedText( s, Qt::ElideMiddle, r.width() - 5 - iconWidth - 8 );
00503 
00504                   // draw text
00505                   if ( (*it) == currentClient() )
00506                     p.setPen(palette().color( QPalette::Active, QPalette::HighlightedText ));
00507                   else if( (*it)->isMinimized())
00508                     {
00509                     QColor c1 = palette().color( QPalette::Active, QPalette::Text );
00510                     QColor c2 = palette().color( QPalette::Active, QPalette::Background );
00511                     // from kicker's TaskContainer::blendColors()
00512                     int r1, g1, b1;
00513                     int r2, g2, b2;
00514 
00515                     c1.getRgb( &r1, &g1, &b1 );
00516                     c2.getRgb( &r2, &g2, &b2 );
00517 
00518                     r1 += (int) ( .5 * ( r2 - r1 ) );
00519                     g1 += (int) ( .5 * ( g2 - g1 ) );
00520                     b1 += (int) ( .5 * ( b2 - b1 ) );
00521 
00522                     p.setPen(QColor( r1, g1, b1 ));
00523                     }
00524                   else
00525                     p.setPen(palette().color( QPalette::Active, QPalette::Text ));
00526 
00527                   p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
00528                               Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, s);
00529 
00530                   y += lineHeight;
00531                   }
00532               if ( y >= r.height() ) break;
00533               }
00534             }
00535         }
00536     else
00537         { // TabBoxDesktopMode || TabBoxDesktopListMode
00538         int iconHeight = iconWidth;
00539 
00540         // get widest desktop name/number
00541         QFont f(font());
00542         f.setBold(true);
00543         f.setPixelSize(iconHeight - 4);  // pixel, not point because I need to know the pixels
00544         QFontMetrics fm(f);
00545 
00546         int wmax = 0;
00547         foreach (int it, desktops)
00548             {
00549             wmax = qMax(wmax, fontMetrics().width(workspace()->desktopName(it)));
00550 
00551             // calculate max width of desktop-number text
00552             QString num = QString::number(it);
00553             iconWidth = qMax(iconWidth - 4, fm.boundingRect(num).width()) + 4;
00554             }
00555 
00556         foreach (int it, desktops)
00557             {
00558             // draw highlight background
00559             if ( it == desk )  // current desktop
00560               p.fillRect(x, y, r.width(), lineHeight, palette().brush( QPalette::Active, QPalette::Highlight ));
00561 
00562             p.save();
00563 
00564             // draw "icon" (here: number of desktop)
00565             p.fillRect(x+5, y+2, iconWidth, iconHeight, palette().brush( QPalette::Active, QPalette::Base ));
00566             p.setPen(palette().color( QPalette::Active, QPalette::Text ));
00567             p.drawRect(x+5, y+2, iconWidth, iconHeight);
00568 
00569             // draw desktop-number
00570             p.setFont(f);
00571             QString num = QString::number(it);
00572             p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num);
00573 
00574             p.restore();
00575 
00576             // draw desktop name text
00577             if ( it == desk )
00578               p.setPen(palette().color( QPalette::Active, QPalette::HighlightedText ));
00579             else
00580               p.setPen(palette().color( QPalette::Active, QPalette::Text ));
00581 
00582             p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
00583                        Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
00584                        workspace()->desktopName(it));
00585 
00586             // show mini icons from that desktop aligned to each other
00587             int x1 = x + 5 + iconWidth + 8 + wmax + 5;
00588 
00589             ClientList list;
00590             createClientList(list, it, 0, false);
00591             // clients are in reversed stacking order
00592             for ( int i = list.size() - 1; i>=0; i-- )
00593               {
00594               if ( !list.at( i )->miniIcon().isNull() )
00595                 {
00596                 if ( x1+18 >= x+r.width() )  // only show full icons
00597                   break;
00598 
00599                 p.drawPixmap( x1, y + (lineHeight - 16)/2, list.at(  i )->miniIcon() );
00600                 x1 += 18;
00601                 }
00602               }
00603 
00604             // next desktop
00605             y += lineHeight;
00606             if ( y >= r.height() ) break;
00607             }
00608         }
00609     }
00610 
00611 
00616 void TabBox::show()
00617     {
00618     if( effects )
00619         static_cast<EffectsHandlerImpl*>(effects)->tabBoxAdded( mode());
00620     if( isDisplayed())
00621         return;
00622     refDisplay();
00623     QWidget::show();
00624     }
00625 
00626 
00630 void TabBox::hide()
00631     {
00632     delayedShowTimer.stop();
00633     if( isVisible())
00634         unrefDisplay();
00635     if( effects )
00636         static_cast<EffectsHandlerImpl*>(effects)->tabBoxClosed();
00637     if( isDisplayed())
00638         kDebug( 1212 ) << "Tab box was not properly closed by an effect";
00639     QWidget::hide();
00640     QApplication::syncX();
00641     XEvent otherEvent;
00642     while (XCheckTypedEvent (display(), EnterNotify, &otherEvent ) )
00643         ;
00644     }
00645 
00646 
00651 void TabBox::unrefDisplay()
00652     {
00653     --display_refcount;
00654     }
00655 
00656 void TabBox::reconfigure()
00657     {
00658     KSharedConfigPtr c(KGlobal::config());
00659     options_traverse_all = c->group("TabBox").readEntry("TraverseAll", false );
00660     }
00661 
00680 void TabBox::delayedShow()
00681     {
00682     KSharedConfigPtr c(KGlobal::config());
00683     KConfigGroup cg(c, "TabBox");
00684     bool delay = cg.readEntry("ShowDelay", true);
00685 
00686     if (!delay)
00687         {
00688         show();
00689         return;
00690         }
00691 
00692     int delayTime = cg.readEntry("DelayTime", 90);
00693     delayedShowTimer.setSingleShot(true);
00694     delayedShowTimer.start(delayTime);
00695     }
00696 
00697 
00698 void TabBox::handleMouseEvent( XEvent* e )
00699     {
00700     XAllowEvents( display(), AsyncPointer, xTime());
00701     if( !isVisible() && isDisplayed())
00702         { // tabbox has been replaced, check effects
00703         if( effects && static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowEvent( e ))
00704             return;
00705         }
00706     if( e->type != ButtonPress )
00707         return;
00708     QPoint pos( e->xbutton.x_root, e->xbutton.y_root );
00709     QPoint widgetPos = mapFromGlobal( pos ); // inside tabbox
00710 
00711     if(( !isVisible() && isDisplayed())
00712         || !geometry().contains( pos ))
00713         {
00714         workspace()->closeTabBox();  // click outside closes tab
00715         return;
00716         }
00717 
00718     int num = (widgetPos.y()-frameWidth()) / lineHeight;
00719 
00720     if( mode() == TabBoxWindowsMode )
00721         {
00722         for( ClientList::ConstIterator it = clients.begin();
00723              it != clients.end();
00724              ++it)
00725             {
00726             if( workspace()->hasClient( *it ) && (num == 0) ) // safety
00727                 {
00728                 setCurrentClient( *it );
00729                 break;
00730                 }
00731             num--;
00732             }
00733         }
00734     else
00735         {
00736         foreach( int it, desktops )
00737             {
00738             if( num == 0 )
00739                 {
00740                 setCurrentDesktop( it );
00741                 break;
00742                 }
00743             num--;
00744             }
00745         }
00746     update();
00747     }
00748 
00749 //*******************************
00750 // Workspace
00751 //*******************************
00752 
00753 
00758 static
00759 bool areKeySymXsDepressed( bool bAll, const uint keySyms[], int nKeySyms )
00760     {
00761     char keymap[32];
00762 
00763     kDebug(125) << "areKeySymXsDepressed: " << (bAll ? "all of " : "any of ") << nKeySyms;
00764 
00765     XQueryKeymap( display(), keymap );
00766 
00767     for( int iKeySym = 0; iKeySym < nKeySyms; iKeySym++ )
00768         {
00769         uint keySymX = keySyms[ iKeySym ];
00770         uchar keyCodeX = XKeysymToKeycode( display(), keySymX );
00771         int i = keyCodeX / 8;
00772         char mask = 1 << (keyCodeX - (i * 8));
00773 
00774                 // Abort if bad index value,
00775         if( i < 0 || i >= 32 )
00776                 return false;
00777 
00778         kDebug(125) << iKeySym << ": keySymX=0x" << QString::number( keySymX, 16 )
00779                 << " i=" << i << " mask=0x" << QString::number( mask, 16 )
00780                 << " keymap[i]=0x" << QString::number( keymap[i], 16 ) << endl;
00781 
00782                 // If ALL keys passed need to be depressed,
00783         if( bAll )
00784             {
00785             if( (keymap[i] & mask) == 0 )
00786                     return false;
00787             }
00788         else
00789             {
00790                         // If we are looking for ANY key press, and this key is depressed,
00791             if( keymap[i] & mask )
00792                     return true;
00793             }
00794         }
00795 
00796         // If we were looking for ANY key press, then none was found, return false,
00797         // If we were looking for ALL key presses, then all were found, return true.
00798     return bAll;
00799     }
00800 
00801 static bool areModKeysDepressed( const QKeySequence& seq )
00802     {
00803     uint rgKeySyms[10];
00804     int nKeySyms = 0;
00805     if( seq.isEmpty())
00806         return false;
00807     int mod = seq[seq.count()-1] & Qt::KeyboardModifierMask;
00808 
00809     if ( mod & Qt::SHIFT )
00810         {
00811         rgKeySyms[nKeySyms++] = XK_Shift_L;
00812         rgKeySyms[nKeySyms++] = XK_Shift_R;
00813         }
00814     if ( mod & Qt::CTRL )
00815         {
00816         rgKeySyms[nKeySyms++] = XK_Control_L;
00817         rgKeySyms[nKeySyms++] = XK_Control_R;
00818         }
00819     if( mod & Qt::ALT )
00820         {
00821         rgKeySyms[nKeySyms++] = XK_Alt_L;
00822         rgKeySyms[nKeySyms++] = XK_Alt_R;
00823         }
00824     if( mod & Qt::META )
00825         {
00826         // It would take some code to determine whether the Win key
00827         // is associated with Super or Meta, so check for both.
00828         // See bug #140023 for details.
00829         rgKeySyms[nKeySyms++] = XK_Super_L;
00830         rgKeySyms[nKeySyms++] = XK_Super_R;
00831         rgKeySyms[nKeySyms++] = XK_Meta_L;
00832         rgKeySyms[nKeySyms++] = XK_Meta_R;
00833         }
00834 
00835     return areKeySymXsDepressed( false, rgKeySyms, nKeySyms );
00836     }
00837 
00838 static bool areModKeysDepressed( const KShortcut& cut )
00839     {
00840     if( areModKeysDepressed( cut.primary()) || areModKeysDepressed( cut.alternate()) )
00841         return true;
00842 
00843     return false;
00844     }
00845 
00846 void Workspace::slotWalkThroughWindows()
00847     {
00848     if ( tab_grab || control_grab )
00849         return;
00850     if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable())
00851         {
00852         //ungrabXKeyboard(); // need that because of accelerator raw mode
00853         // CDE style raise / lower
00854         CDEWalkThroughWindows( true );
00855         }
00856     else
00857         {
00858         if ( areModKeysDepressed( cutWalkThroughWindows ) )
00859             {
00860             if ( startKDEWalkThroughWindows() )
00861                 KDEWalkThroughWindows( true );
00862             }
00863         else
00864             // if the shortcut has no modifiers, don't show the tabbox,
00865             // don't grab, but simply go to the next window
00866             KDEOneStepThroughWindows( true );
00867         }
00868     }
00869 
00870 void Workspace::slotWalkBackThroughWindows()
00871     {
00872     if( tab_grab || control_grab )
00873         return;
00874     if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable())
00875         {
00876         // CDE style raise / lower
00877         CDEWalkThroughWindows( false );
00878         }
00879     else
00880         {
00881         if ( areModKeysDepressed( cutWalkThroughWindowsReverse ) )
00882             {
00883             if ( startKDEWalkThroughWindows() )
00884                 KDEWalkThroughWindows( false );
00885             }
00886         else
00887             {
00888             KDEOneStepThroughWindows( false );
00889             }
00890         }
00891     }
00892 
00893 void Workspace::slotWalkThroughDesktops()
00894     {
00895     if( tab_grab || control_grab )
00896         return;
00897     if ( areModKeysDepressed( cutWalkThroughDesktops ) )
00898         {
00899         if ( startWalkThroughDesktops() )
00900             walkThroughDesktops( true );
00901         }
00902     else
00903         {
00904         oneStepThroughDesktops( true );
00905         }
00906     }
00907 
00908 void Workspace::slotWalkBackThroughDesktops()
00909     {
00910     if( tab_grab || control_grab )
00911         return;
00912     if ( areModKeysDepressed( cutWalkThroughDesktopsReverse ) )
00913         {
00914         if ( startWalkThroughDesktops() )
00915             walkThroughDesktops( false );
00916         }
00917     else
00918         {
00919         oneStepThroughDesktops( false );
00920         }
00921     }
00922 
00923 void Workspace::slotWalkThroughDesktopList()
00924     {
00925     if( tab_grab || control_grab )
00926         return;
00927     if ( areModKeysDepressed( cutWalkThroughDesktopList ) )
00928         {
00929         if ( startWalkThroughDesktopList() )
00930             walkThroughDesktops( true );
00931         }
00932     else
00933         {
00934         oneStepThroughDesktopList( true );
00935         }
00936     }
00937 
00938 void Workspace::slotWalkBackThroughDesktopList()
00939     {
00940     if( tab_grab || control_grab )
00941         return;
00942     if ( areModKeysDepressed( cutWalkThroughDesktopListReverse ) )
00943         {
00944         if ( startWalkThroughDesktopList() )
00945             walkThroughDesktops( false );
00946         }
00947     else
00948         {
00949         oneStepThroughDesktopList( false );
00950         }
00951     }
00952 
00953 void Workspace::modalActionsSwitch( bool enabled )
00954     {
00955     QList<KActionCollection*> collections;
00956     collections.append( keys );
00957     collections.append( disable_shortcuts_keys );
00958     collections.append( client_keys );
00959     foreach (KActionCollection* collection, collections)
00960         foreach (QAction *action, collection->actions())
00961             action->setEnabled(enabled);
00962     }
00963 
00964 bool Workspace::startKDEWalkThroughWindows()
00965     {
00966     if( !establishTabBoxGrab())
00967         return false;
00968     tab_grab = true;
00969     modalActionsSwitch( false );
00970     tab_box->setMode( TabBoxWindowsMode );
00971     tab_box->reset();
00972     return true;
00973     }
00974 
00975 bool Workspace::startWalkThroughDesktops( TabBoxMode mode )
00976     {
00977     if( !establishTabBoxGrab())
00978         return false;
00979     control_grab = true;
00980     modalActionsSwitch( false );
00981     tab_box->setMode( mode );
00982     tab_box->reset();
00983     return true;
00984     }
00985 
00986 bool Workspace::startWalkThroughDesktops()
00987     {
00988     return startWalkThroughDesktops( TabBoxDesktopMode );
00989     }
00990 
00991 bool Workspace::startWalkThroughDesktopList()
00992     {
00993     return startWalkThroughDesktops( TabBoxDesktopListMode );
00994     }
00995 
00996 void Workspace::KDEWalkThroughWindows( bool forward )
00997     {
00998     tab_box->nextPrev( forward );
00999     tab_box->delayedShow();
01000     }
01001 
01002 void Workspace::walkThroughDesktops( bool forward )
01003     {
01004     tab_box->nextPrev( forward );
01005     tab_box->delayedShow();
01006     }
01007 
01008 void Workspace::CDEWalkThroughWindows( bool forward )
01009     {
01010     Client* c = NULL;
01011 // this function find the first suitable client for unreasonable focus
01012 // policies - the topmost one, with some exceptions (can't be keepabove/below,
01013 // otherwise it gets stuck on them)
01014     Q_ASSERT( block_stacking_updates == 0 );
01015     for( int i = stacking_order.size() - 1;
01016          i >= 0 ;
01017          --i )
01018         {
01019         Client* it = stacking_order.at( i );
01020         if ( it->isOnCurrentDesktop() && !it->isSpecialWindow()
01021             && it->isShown( false ) && it->wantsTabFocus()
01022             && !it->keepAbove() && !it->keepBelow())
01023             {
01024             c = it;
01025             break;
01026             }
01027         }
01028     Client* nc = c;
01029     bool options_traverse_all;
01030         {
01031         KConfigGroup group( KGlobal::config(), "TabBox" );
01032         options_traverse_all = group.readEntry("TraverseAll", false );
01033         }
01034 
01035     Client* firstClient = 0;
01036     do
01037         {
01038         nc = forward ? nextClientStatic(nc) : previousClientStatic(nc);
01039         if (!firstClient)
01040             {
01041             // When we see our first client for the second time,
01042             // it's time to stop.
01043             firstClient = nc;
01044             }
01045         else if (nc == firstClient)
01046             {
01047             // No candidates found.
01048             nc = 0;
01049             break;
01050             }
01051         } while (nc && nc != c &&
01052             (( !options_traverse_all && !nc->isOnDesktop(currentDesktop())) ||
01053              nc->isMinimized() || !nc->wantsTabFocus() || nc->keepAbove() || nc->keepBelow() ) );
01054     if (nc)
01055         {
01056         if (c && c != nc)
01057             lowerClient( c );
01058         if ( options->focusPolicyIsReasonable() )
01059             {
01060             activateClient( nc );
01061             if( nc->isShade() && options->shadeHover )
01062                 nc->setShade( ShadeActivated );
01063             }
01064         else
01065             {
01066             if( !nc->isOnDesktop( currentDesktop()))
01067                 setCurrentDesktop( nc->desktop());
01068             raiseClient( nc );
01069             }
01070         }
01071     }
01072 
01073 void Workspace::KDEOneStepThroughWindows( bool forward )
01074     {
01075     tab_box->setMode( TabBoxWindowsMode );
01076     tab_box->reset();
01077     tab_box->nextPrev( forward );
01078     if( Client* c = tab_box->currentClient() )
01079         {
01080         activateClient( c );
01081         if( c->isShade() && options->shadeHover )
01082             c->setShade( ShadeActivated );
01083         }
01084     }
01085 
01086 void Workspace::oneStepThroughDesktops( bool forward, TabBoxMode mode )
01087     {
01088     tab_box->setMode( mode );
01089     tab_box->reset();
01090     tab_box->nextPrev( forward );
01091     if ( tab_box->currentDesktop() != -1 )
01092         setCurrentDesktop( tab_box->currentDesktop() );
01093     }
01094 
01095 void Workspace::oneStepThroughDesktops( bool forward )
01096     {
01097     oneStepThroughDesktops( forward, TabBoxDesktopMode );
01098     }
01099 
01100 void Workspace::oneStepThroughDesktopList( bool forward )
01101     {
01102     oneStepThroughDesktops( forward, TabBoxDesktopListMode );
01103     }
01104 
01108 void Workspace::tabBoxKeyPress( int keyQt )
01109     {
01110     bool forward = false;
01111     bool backward = false;
01112 
01113     if (tab_grab)
01114         {
01115         forward = cutWalkThroughWindows.contains( keyQt );
01116         backward = cutWalkThroughWindowsReverse.contains( keyQt );
01117         if (forward || backward)
01118             {
01119             kDebug(125) << "== " << cutWalkThroughWindows.toString()
01120                 << " or " << cutWalkThroughWindowsReverse.toString() << endl;
01121             KDEWalkThroughWindows( forward );
01122             }
01123         }
01124     else if (control_grab)
01125         {
01126         forward = cutWalkThroughDesktops.contains( keyQt ) ||
01127                   cutWalkThroughDesktopList.contains( keyQt );
01128         backward = cutWalkThroughDesktopsReverse.contains( keyQt ) ||
01129                    cutWalkThroughDesktopListReverse.contains( keyQt );
01130         if (forward || backward)
01131             walkThroughDesktops(forward);
01132         }
01133 
01134     if (control_grab || tab_grab)
01135         {
01136         if ( ((keyQt & ~Qt::KeyboardModifierMask) == Qt::Key_Escape)
01137             && !(forward || backward) )
01138             { // if Escape is part of the shortcut, don't cancel
01139             closeTabBox();
01140             }
01141         }
01142     }
01143 
01144 void Workspace::refTabBox()
01145     {
01146     if( tab_box )
01147         tab_box->refDisplay();
01148     }
01149 
01150 void Workspace::unrefTabBox()
01151     {
01152     if( tab_box )
01153         tab_box->unrefDisplay();
01154     }
01155 
01156 void Workspace::closeTabBox()
01157     {
01158     removeTabBoxGrab();
01159     tab_box->hide();
01160     modalActionsSwitch( true );
01161     tab_grab = false;
01162     control_grab = false;
01163     }
01164 
01168 void Workspace::tabBoxKeyRelease( const XKeyEvent& ev )
01169     {
01170     unsigned int mk = ev.state &
01171         (KKeyServer::modXShift() |
01172          KKeyServer::modXCtrl() |
01173          KKeyServer::modXAlt() |
01174          KKeyServer::modXMeta() );
01175     // ev.state is state before the key release, so just checking mk being 0 isn't enough
01176     // using XQueryPointer() also doesn't seem to work well, so the check that all
01177     // modifiers are released: only one modifier is active and the currently released
01178     // key is this modifier - if yes, release the grab
01179     int mod_index = -1;
01180     for( int i = ShiftMapIndex;
01181          i <= Mod5MapIndex;
01182          ++i )
01183         if(( mk & ( 1 << i )) != 0 )
01184         {
01185         if( mod_index >= 0 )
01186             return;
01187         mod_index = i;
01188         }
01189     bool release = false;
01190     if( mod_index == -1 )
01191         release = true;
01192     else
01193         {
01194         XModifierKeymap* xmk = XGetModifierMapping(display());
01195         for (int i=0; i<xmk->max_keypermod; i++)
01196             if (xmk->modifiermap[xmk->max_keypermod * mod_index + i]
01197                 == ev.keycode)
01198                 release = true;
01199         XFreeModifiermap(xmk);
01200         }
01201     if( !release )
01202          return;
01203     if (tab_grab)
01204         {
01205         bool old_control_grab = control_grab;
01206         closeTabBox();
01207         control_grab = old_control_grab;
01208         if( Client* c = tab_box->currentClient())
01209             {
01210             activateClient( c );
01211             if( c->isShade() && options->shadeHover )
01212                 c->setShade( ShadeActivated );
01213             }
01214         }
01215     if (control_grab)
01216         {
01217         bool old_tab_grab = tab_grab;
01218         closeTabBox();
01219         tab_grab = old_tab_grab;
01220         if ( tab_box->currentDesktop() != -1 )
01221             {
01222             setCurrentDesktop( tab_box->currentDesktop() );
01223             }
01224         }
01225     }
01226 
01227 
01228 int Workspace::nextDesktopFocusChain( int iDesktop ) const
01229     {
01230     int i = desktop_focus_chain.indexOf( iDesktop );
01231     if( i >= 0 && i+1 < (int)desktop_focus_chain.size() )
01232             return desktop_focus_chain[i+1];
01233     else if( desktop_focus_chain.size() > 0 )
01234             return desktop_focus_chain[ 0 ];
01235     else
01236             return 1;
01237     }
01238 
01239 int Workspace::previousDesktopFocusChain( int iDesktop ) const
01240     {
01241     int i = desktop_focus_chain.indexOf( iDesktop );
01242     if( i-1 >= 0 )
01243             return desktop_focus_chain[i-1];
01244     else if( desktop_focus_chain.size() > 0 )
01245             return desktop_focus_chain[desktop_focus_chain.size()-1];
01246     else
01247             return numberOfDesktops();
01248     }
01249 
01250 int Workspace::nextDesktopStatic( int iDesktop ) const
01251     {
01252     int i = ++iDesktop;
01253     if( i > numberOfDesktops())
01254         i = 1;
01255     return i;
01256     }
01257 
01258 int Workspace::previousDesktopStatic( int iDesktop ) const
01259     {
01260     int i = --iDesktop;
01261     if( i < 1 )
01262         i = numberOfDesktops();
01263     return i;
01264     }
01265 
01270 Client* Workspace::nextClientFocusChain( Client* c ) const
01271     {
01272     if ( global_focus_chain.isEmpty() )
01273         return 0;
01274     int pos = global_focus_chain.indexOf( c );
01275     if ( pos == -1 )
01276         return global_focus_chain.last();
01277     if ( pos == 0 )
01278         return global_focus_chain.last();
01279     pos--;
01280     return global_focus_chain[ pos ];
01281     }
01282 
01287 Client* Workspace::previousClientFocusChain( Client* c ) const
01288     {
01289     if ( global_focus_chain.isEmpty() )
01290         return 0;
01291     int pos = global_focus_chain.indexOf( c );
01292     if ( pos == -1 )
01293         return global_focus_chain.first();
01294     pos++;
01295     if ( pos == global_focus_chain.count() )
01296         return global_focus_chain.first();
01297     return global_focus_chain[ pos ];
01298     }
01299 
01304 Client* Workspace::nextClientStatic( Client* c ) const
01305     {
01306     if ( !c || clients.isEmpty() )
01307         return 0;
01308     int pos = clients.indexOf( c );
01309     if ( pos == -1 )
01310         return clients.first();
01311     ++pos;
01312     if ( pos == clients.count() )
01313         return clients.first();
01314     return clients[ pos ];
01315     }
01320 Client* Workspace::previousClientStatic( Client* c ) const
01321     {
01322     if ( !c || clients.isEmpty() )
01323         return 0;
01324     int pos = clients.indexOf( c );
01325     if ( pos == -1 )
01326         return clients.last();
01327     if ( pos == 0 )
01328         return clients.last();
01329     --pos;
01330     return clients[ pos ];
01331     }
01332 
01333 Client* Workspace::currentTabBoxClient() const
01334     {
01335     if( !tab_box )
01336         return 0;
01337     return tab_box->currentClient();
01338     }
01339 
01340 ClientList Workspace::currentTabBoxClientList() const
01341     {
01342     if( !tab_box )
01343         return ClientList();
01344     return tab_box->currentClientList();
01345     }
01346 
01347 int Workspace::currentTabBoxDesktop() const
01348     {
01349     if( !tab_box )
01350         return -1;
01351     return tab_box->currentDesktop();
01352     }
01353 
01354 QList< int > Workspace::currentTabBoxDesktopList() const
01355     {
01356     if( !tab_box )
01357         return QList< int >();
01358     return tab_box->currentDesktopList();
01359     }
01360 
01361 void Workspace::setTabBoxClient( Client* c )
01362     {
01363     if( tab_box )
01364         tab_box->setCurrentClient( c );
01365     }
01366 
01367 void Workspace::setTabBoxDesktop( int iDesktop )
01368     {
01369     if( tab_box )
01370         tab_box->setCurrentDesktop( iDesktop );
01371     }
01372 
01373 bool Workspace::establishTabBoxGrab()
01374     {
01375     if( !grabXKeyboard())
01376         return false;
01377     // Don't try to establish a global mouse grab using XGrabPointer, as that would prevent
01378     // using Alt+Tab while DND (#44972). However force passive grabs on all windows
01379     // in order to catch MouseRelease events and close the tabbox (#67416).
01380     // All clients already have passive grabs in their wrapper windows, so check only
01381     // the active client, which may not have it.
01382     assert( !forced_global_mouse_grab );
01383     forced_global_mouse_grab = true;
01384     if( active_client != NULL )
01385         active_client->updateMouseGrab();
01386     return true;
01387     }
01388 
01389 void Workspace::removeTabBoxGrab()
01390     {
01391     ungrabXKeyboard();
01392     assert( forced_global_mouse_grab );
01393     forced_global_mouse_grab = false;
01394     if( active_client != NULL )
01395         active_client->updateMouseGrab();
01396     }
01397 
01398 } // namespace
01399 
01400 #include "tabbox.moc"

KWin

Skip menu "KWin"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal