kwin Library API Documentation

tabbox.cpp

00001 /********x*********************************************************
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 You can Freely distribute this program under the GNU General Public
00009 License. See the file "COPYING" for the exact licensing terms.
00010 ******************************************************************/
00011 
00012 //#define QT_CLEAN_NAMESPACE
00013 #include "tabbox.h"
00014 #include "workspace.h"
00015 #include "client.h"
00016 #include <qpainter.h>
00017 #include <qlabel.h>
00018 #include <qdrawutil.h>
00019 #include <qstyle.h>
00020 #include <kglobal.h>
00021 #include <fixx11h.h>
00022 #include <kconfig.h>
00023 #include <klocale.h>
00024 #include <qapplication.h>
00025 #include <qdesktopwidget.h>
00026 #include <qcursor.h>
00027 #include <kstringhandler.h>
00028 #include <stdarg.h>
00029 #include <kdebug.h>
00030 #include <kglobalaccel.h>
00031 #include <kkeynative.h>
00032 #include <kglobalsettings.h>
00033 #include <X11/keysym.h>
00034 #include <X11/keysymdef.h>
00035 
00036 // specify externals before namespace
00037 
00038 extern Time qt_x_time;
00039 
00040 namespace KWinInternal
00041 {
00042 
00043 extern QPixmap* kwin_get_menu_pix_hack();
00044 
00045 TabBox::TabBox( Workspace *ws, const char *name )
00046     : QFrame( 0, name, Qt::WNoAutoErase ), client(0), wspace(ws)
00047     {
00048     setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
00049     setLineWidth(2);
00050     setMargin(2);
00051 
00052     showMiniIcon = false;
00053 
00054     no_tasks = i18n("*** No Windows ***");
00055     m = DesktopMode; // init variables
00056     reconfigure();
00057     reset();
00058     connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show()));
00059     }
00060 
00061 TabBox::~TabBox()
00062     {
00063     }
00064 
00065 
00071 void TabBox::setMode( Mode mode )
00072     {
00073     m = mode;
00074     }
00075 
00076 
00080 void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client *c, bool chain)
00081     {
00082     ClientList::size_type idx = 0;
00083 
00084     list.clear();
00085 
00086     Client* start = c;
00087 
00088     if ( chain )
00089         c = workspace()->nextFocusChainClient(c);
00090     else
00091         c = workspace()->stackingOrder().first();
00092 
00093     Client* stop = c;
00094 
00095     while ( c )
00096         {
00097         if ( ((desktop == -1) || c->isOnDesktop(desktop))
00098              && c->wantsTabFocus() )
00099             {
00100             if ( start == c )
00101                 {
00102                 list.remove( c );
00103                 list.prepend( c );
00104                 }
00105             else
00106                 { // don't add windows that have modal dialogs
00107                 Client* modal = c->findModal();
00108                 if( modal == NULL || modal == c )
00109                     list += c;
00110                 else if( !list.contains( modal ))
00111                     list += modal;
00112                 else
00113                     ; // nothing
00114                 }
00115             }
00116 
00117         if ( chain )
00118           c = workspace()->nextFocusChainClient( c );
00119         else
00120           {
00121           if ( idx >= (workspace()->stackingOrder().size()-1) )
00122             c = 0;
00123           else
00124             c = workspace()->stackingOrder()[++idx];
00125           }
00126 
00127         if ( c == stop )
00128             break;
00129         }
00130     }
00131 
00132 
00137 void TabBox::reset()
00138     {
00139     int w, h, cw = 0, wmax = 0;
00140 
00141     QRect r = KGlobalSettings::desktopGeometry(QCursor::pos());
00142 
00143     // calculate height of 1 line
00144     // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below
00145     lineHeight = QMAX(fontMetrics().height() + 2, 32 + 4);
00146 
00147     if ( mode() == WindowsMode )
00148         {
00149         client = workspace()->activeClient();
00150 
00151         // get all clients to show
00152         createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), client, true);
00153 
00154         // calculate maximum caption width
00155         cw = fontMetrics().width(no_tasks)+20;
00156         for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00157           {
00158           cw = fontMetrics().width( (*it)->caption() );
00159           if ( cw > wmax ) wmax = cw;
00160           }
00161 
00162         // calculate height for the popup
00163         if ( clients.count() == 0 )  // height for the "not tasks" text
00164           {
00165           QFont f = font();
00166           f.setBold( TRUE );
00167           f.setPointSize( 14 );
00168 
00169           h = QFontMetrics(f).height()*4;
00170           }
00171         else
00172           {
00173           showMiniIcon = false;
00174           h = clients.count() * lineHeight;
00175 
00176           if ( h > (r.height()-(2*frameWidth())) )  // if too high, use mini icons
00177             {
00178             showMiniIcon = true;
00179             // fontheight + 1 pixel above + 1 pixel below, or 16x16 icon + 1 pixel above + below
00180             lineHeight = QMAX(fontMetrics().height() + 2, 16 + 2);
00181 
00182             h = clients.count() * lineHeight;
00183 
00184             if ( h > (r.height()-(2*frameWidth())) ) // if still too high, remove some clients
00185               {
00186                 // how many clients to remove
00187                 int howMany = (h - (r.height()-(2*frameWidth())))/lineHeight;
00188                 for (; howMany; howMany--)
00189                   clients.remove(clients.last());
00190 
00191                 h = clients.count() * lineHeight;
00192               }
00193             }
00194           }
00195         }
00196     else
00197         { // DesktopListMode
00198         showMiniIcon = false;
00199         desk = workspace()->currentDesktop();
00200 
00201         for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
00202           {
00203           cw = fontMetrics().width( workspace()->desktopName(i) );
00204           if ( cw > wmax ) wmax = cw;
00205           }
00206 
00207         // calculate height for the popup (max. 16 desktops always fit in a 800x600 screen)
00208         h = workspace()->numberOfDesktops() * lineHeight;
00209         }
00210 
00211     // height, width for the popup
00212     h += 2 * frameWidth();
00213     w = 2*frameWidth() + 5*2 + ( showMiniIcon ? 16 : 32 ) + 8 + wmax; // 5*2=margins, ()=icon, 8=space between icon+text
00214     w = kClamp( w, r.width()/3 , r.width() );
00215 
00216     setGeometry( (r.width()-w)/2 + r.x(),
00217                  (r.height()-h)/2+ r.y(),
00218                  w, h );
00219     }
00220 
00221 
00225 void TabBox::nextPrev( bool next)
00226     {
00227     if ( mode() == WindowsMode )
00228         {
00229         Client* firstClient = 0;
00230         do
00231             {
00232             if ( next )
00233                 client = workspace()->nextFocusChainClient(client);
00234             else
00235                 client = workspace()->previousFocusChainClient(client);
00236             if (!firstClient)
00237                 {
00238         // When we see our first client for the second time,
00239         // it's time to stop.
00240                 firstClient = client;
00241                 }
00242             else if (client == firstClient)
00243                 {
00244         // No candidates found.
00245                 client = 0;
00246                 break;
00247                 }
00248             } while ( client && !clients.contains( client ));
00249         }
00250     else if( mode() == DesktopMode )
00251         {
00252         if ( next )
00253             desk = workspace()->nextDesktopFocusChain( desk );
00254         else
00255             desk = workspace()->previousDesktopFocusChain( desk );
00256         }
00257     else
00258         { // DesktopListMode
00259         if ( next )
00260             {
00261             desk++;
00262             if ( desk > workspace()->numberOfDesktops() )
00263                 desk = 1;
00264             }
00265         else
00266             {
00267             desk--;
00268             if ( desk < 1 )
00269                 desk = workspace()->numberOfDesktops();
00270             }
00271         }
00272 
00273     update();
00274     }
00275 
00276 
00277 
00282 Client* TabBox::currentClient()
00283     {
00284     if ( mode() != WindowsMode )
00285         return 0;
00286     if (!workspace()->hasClient( client ))
00287         return 0;
00288     return client;
00289     }
00290 
00296 int TabBox::currentDesktop()
00297     {
00298     if ( mode() == DesktopListMode || mode() == DesktopMode )
00299         return desk;
00300     else
00301         return -1;
00302     }
00303 
00304 
00308 void TabBox::showEvent( QShowEvent* )
00309     {
00310     raise();
00311     }
00312 
00313 
00317 void TabBox::hideEvent( QHideEvent* )
00318     {
00319     }
00320 
00324 void TabBox::drawContents( QPainter * )
00325     {
00326     QRect r(contentsRect());
00327     QPixmap pix(r.size());  // do double buffering to avoid flickers
00328     pix.fill(this, 0, 0);
00329 
00330     QPainter p;
00331     p.begin(&pix, this);
00332 
00333     QPixmap* menu_pix = kwin_get_menu_pix_hack();
00334 
00335     int iconWidth = showMiniIcon ? 16 : 32;
00336     int x = 0;
00337     int y = 0;
00338 
00339     if ( mode () == WindowsMode )
00340         {
00341         if ( !currentClient() )
00342             {
00343             QFont f = font();
00344             f.setBold( TRUE );
00345             f.setPointSize( 14 );
00346 
00347             p.setFont(f);
00348             p.drawText( r, AlignCenter, no_tasks);
00349             }
00350         else
00351             {
00352             for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00353               {
00354               if ( workspace()->hasClient( *it ) )  // safety
00355                   {
00356                   // draw highlight background
00357                   if ( (*it) == currentClient() )
00358                     p.fillRect(x, y, r.width(), lineHeight, colorGroup().highlight());
00359 
00360                   // draw icon
00361                   if ( showMiniIcon )
00362                     {
00363                     if ( !(*it)->miniIcon().isNull() )
00364                       p.drawPixmap( x+5, y + (lineHeight - iconWidth)/2, (*it)->miniIcon() );
00365                     }
00366                   else
00367                     if ( !(*it)->icon().isNull() )
00368                       p.drawPixmap( x+5, y + (lineHeight - iconWidth)/2, (*it)->icon() );
00369                     else if ( menu_pix )
00370                       p.drawPixmap( x, y + (lineHeight - iconWidth)/2, *menu_pix );
00371 
00372                   // generate text to display
00373                   QString s;
00374 
00375                   if ( !(*it)->isOnDesktop(workspace()->currentDesktop()) )
00376                     s = workspace()->desktopName((*it)->desktop()) + ": ";
00377 
00378                   if ( (*it)->isMinimized() )
00379                     s += QString("(") + (*it)->caption() + ")";
00380                   else
00381                     s += (*it)->caption();
00382 
00383                   s = KStringHandler::cPixelSqueeze(s, fontMetrics(), r.width() - 5 - iconWidth - 8);
00384 
00385                   // draw text
00386                   if ( (*it) == currentClient() )
00387                     p.setPen(colorGroup().highlightedText());
00388                   else
00389                     p.setPen(colorGroup().text());
00390 
00391                   p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
00392                               Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine, s);
00393 
00394                   y += lineHeight;
00395                   }
00396               if ( y >= r.height() ) break;
00397               }
00398             }
00399         }
00400     else
00401         { // DesktopMode || DesktopListMode
00402         int iconHeight = iconWidth;
00403 
00404         // get widest desktop name/number
00405         QFont f(font());
00406         f.setBold(true);
00407         f.setPixelSize(iconHeight - 4);  // pixel, not point because I need to know the pixels
00408         QFontMetrics fm(f);
00409 
00410         int wmax = 0;
00411         for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
00412             {
00413             wmax = QMAX(wmax, fontMetrics().width(workspace()->desktopName(i)));
00414 
00415             // calculate max width of desktop-number text
00416             QString num = QString::number(i);
00417             iconWidth = QMAX(iconWidth - 4, fm.boundingRect(num).width()) + 4;
00418             }
00419 
00420         // In DesktopMode, start at the current desktop
00421         // In DesktopListMode, start at desktop #1
00422         int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
00423         for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
00424             {
00425             // draw highlight background
00426             if ( iDesktop == desk )  // current desktop
00427               p.fillRect(x, y, r.width(), lineHeight, colorGroup().highlight());
00428 
00429             p.save();
00430 
00431             // draw "icon" (here: number of desktop)
00432             p.fillRect(x+5, y+2, iconWidth, iconHeight, colorGroup().base());
00433             p.setPen(colorGroup().text());
00434             p.drawRect(x+5, y+2, iconWidth, iconHeight);
00435 
00436             // draw desktop-number
00437             p.setFont(f);
00438             QString num = QString::number(iDesktop);
00439             p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num);
00440 
00441             p.restore();
00442 
00443             // draw desktop name text
00444             if ( iDesktop == desk )
00445               p.setPen(colorGroup().highlightedText());
00446             else
00447               p.setPen(colorGroup().text());
00448 
00449             p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
00450                        Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine,
00451                        workspace()->desktopName(iDesktop));
00452 
00453             // show mini icons from that desktop aligned to each other
00454             int x1 = x + 5 + iconWidth + 8 + wmax + 5;
00455 
00456             ClientList list;
00457             createClientList(list, iDesktop, 0, false);
00458             // clients are in reversed stacking order
00459             for (ClientList::ConstIterator it = list.fromLast(); it != list.end(); --it)
00460               {
00461               if ( !(*it)->miniIcon().isNull() )
00462                 {
00463                 if ( x1+18 >= x+r.width() )  // only show full icons
00464                   break;
00465 
00466                 p.drawPixmap( x1, y + (lineHeight - 16)/2, (*it)->miniIcon() );
00467                 x1 += 18;
00468                 }
00469               }
00470 
00471             // next desktop
00472             y += lineHeight;
00473             if ( y >= r.height() ) break;
00474 
00475             if( mode() == DesktopMode )
00476                 iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
00477             else
00478                 iDesktop++;
00479             }
00480         }
00481     p.end();
00482     bitBlt(this, r.x(), r.y(), &pix);
00483     }
00484 
00485 void TabBox::hide()
00486     {
00487     delayedShowTimer.stop();
00488     QWidget::hide();
00489     QApplication::syncX();
00490     XEvent otherEvent;
00491     while (XCheckTypedEvent (qt_xdisplay(), EnterNotify, &otherEvent ) )
00492         ;
00493     }
00494 
00495 
00496 void TabBox::reconfigure()
00497     {
00498     KConfig * c(KGlobal::config());
00499     c->setGroup("TabBox");
00500     options_traverse_all = c->readNumEntry("TraverseAll", false );
00501     }
00502 
00521 void TabBox::delayedShow()
00522     {
00523     KConfig * c(KGlobal::config());
00524     c->setGroup("TabBox");
00525     bool delay = c->readNumEntry("ShowDelay", true);
00526 
00527     if (!delay)
00528         {
00529         show();
00530         return;
00531         }
00532 
00533     int delayTime = c->readNumEntry("DelayTime", 90);
00534     delayedShowTimer.start(delayTime, true);
00535     }
00536 
00537 
00538 void TabBox::handleMouseEvent( XEvent* e )
00539     {
00540     XAllowEvents( qt_xdisplay(), AsyncPointer, qt_x_time );
00541     if( e->type != ButtonPress )
00542         return;
00543     QPoint pos( e->xbutton.x_root, e->xbutton.y_root );
00544     if( !geometry().contains( pos ))
00545         {
00546         workspace()->closeTabBox();  // click outside closes tab
00547         return;
00548         }
00549     pos.rx() -= x(); // pos is now inside tabbox
00550     pos.ry() -= y();
00551     int num = (pos.y()-frameWidth()) / lineHeight;
00552 
00553     if( mode() == WindowsMode )
00554         {
00555         for( ClientList::ConstIterator it = clients.begin();
00556              it != clients.end();
00557              ++it)
00558             {
00559             if( workspace()->hasClient( *it ) && (num == 0) ) // safety
00560                 {
00561                 client = *it;
00562                 break;
00563                 }
00564             num--;
00565             }
00566         }
00567     else
00568         {
00569         int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
00570         for( int i = 1;
00571              i <= workspace()->numberOfDesktops();
00572              ++i )
00573             {
00574             if( num == 0 )
00575                 {
00576                 desk = iDesktop;
00577                 break;
00578                 }
00579             num--;
00580             if( mode() == DesktopMode )
00581                 iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
00582             else
00583                 iDesktop++;
00584             }
00585         }
00586     update();
00587     }
00588 
00589 //*******************************
00590 // Workspace
00591 //*******************************
00592 
00593 
00598 static
00599 bool areKeySymXsDepressed( bool bAll, int nKeySyms, ... )
00600     {
00601     va_list args;
00602     char keymap[32];
00603 
00604     kdDebug(125) << "areKeySymXsDepressed: " << (bAll ? "all of " : "any of ") << nKeySyms << endl;
00605 
00606     va_start( args, nKeySyms );
00607     XQueryKeymap( qt_xdisplay(), keymap );
00608 
00609     for( int iKeySym = 0; iKeySym < nKeySyms; iKeySym++ )
00610         {
00611         uint keySymX = va_arg( args, uint );
00612         uchar keyCodeX = XKeysymToKeycode( qt_xdisplay(), keySymX );
00613         int i = keyCodeX / 8;
00614         char mask = 1 << (keyCodeX - (i * 8));
00615 
00616         kdDebug(125) << iKeySym << ": keySymX=0x" << QString::number( keySymX, 16 )
00617                 << " i=" << i << " mask=0x" << QString::number( mask, 16 )
00618                 << " keymap[i]=0x" << QString::number( keymap[i], 16 ) << endl;
00619 
00620                 // Abort if bad index value,
00621         if( i < 0 || i >= 32 )
00622                 return false;
00623 
00624                 // If ALL keys passed need to be depressed,
00625         if( bAll )
00626             {
00627             if( (keymap[i] & mask) == 0 )
00628                     return false;
00629             }
00630         else
00631             {
00632                         // If we are looking for ANY key press, and this key is depressed,
00633             if( keymap[i] & mask )
00634                     return true;
00635             }
00636         }
00637 
00638         // If we were looking for ANY key press, then none was found, return false,
00639         // If we were looking for ALL key presses, then all were found, return true.
00640     return bAll;
00641     }
00642 
00643 static bool areModKeysDepressed( const KKeySequence& seq )
00644     {
00645     uint rgKeySyms[10];
00646     int nKeySyms = 0;
00647     if( seq.isNull())
00648     return false;
00649     int mod = seq.key(seq.count()-1).modFlags();
00650 
00651     if ( mod & KKey::SHIFT )
00652         {
00653         rgKeySyms[nKeySyms++] = XK_Shift_L;
00654         rgKeySyms[nKeySyms++] = XK_Shift_R;
00655         }
00656     if ( mod & KKey::CTRL )
00657         {
00658         rgKeySyms[nKeySyms++] = XK_Control_L;
00659         rgKeySyms[nKeySyms++] = XK_Control_R;
00660         }
00661     if( mod & KKey::ALT )
00662         {
00663         rgKeySyms[nKeySyms++] = XK_Alt_L;
00664         rgKeySyms[nKeySyms++] = XK_Alt_R;
00665         }
00666     if( mod & KKey::WIN )
00667         {
00668         // HACK: it would take a lot of code to determine whether the Win key
00669         //  is associated with Super or Meta, so check for both
00670         rgKeySyms[nKeySyms++] = XK_Super_L;
00671         rgKeySyms[nKeySyms++] = XK_Super_R;
00672         rgKeySyms[nKeySyms++] = XK_Meta_L;
00673         rgKeySyms[nKeySyms++] = XK_Meta_R;
00674         }
00675 
00676     // Is there a better way to push all 8 integer onto the stack?
00677     return areKeySymXsDepressed( false, nKeySyms,
00678         rgKeySyms[0], rgKeySyms[1], rgKeySyms[2], rgKeySyms[3],
00679         rgKeySyms[4], rgKeySyms[5], rgKeySyms[6], rgKeySyms[7] );
00680     }
00681 
00682 static bool areModKeysDepressed( const KShortcut& cut )
00683     {
00684     for( unsigned int i = 0;
00685      i < cut.count();
00686      ++i )
00687     {
00688     if( areModKeysDepressed( cut.seq( i )))
00689         return true;
00690     }
00691     return false;
00692     }
00693 
00694 void Workspace::slotWalkThroughWindows()
00695     {
00696     if ( root != qt_xrootwin() )
00697         return;
00698     if ( tab_grab || control_grab )
00699         return;
00700     if ( options->altTabStyle == Options::CDE  || !options->focusPolicyIsReasonable() )
00701         {
00702         //XUngrabKeyboard(qt_xdisplay(), qt_x_time); // need that because of accelerator raw mode
00703         // CDE style raise / lower
00704         CDEWalkThroughWindows( true );
00705         }
00706     else
00707         {
00708         if ( areModKeysDepressed( cutWalkThroughWindows ) )
00709             {
00710             if ( startKDEWalkThroughWindows() )
00711                 KDEWalkThroughWindows( true );
00712             }
00713         else
00714             // if the shortcut has no modifiers, don't show the tabbox,
00715             // don't grab, but simply go to the next window
00716             // use the CDE style, because with KDE style it would cycle
00717             // between the active and previously active window
00718             CDEWalkThroughWindows( true );
00719         }
00720     }
00721 
00722 void Workspace::slotWalkBackThroughWindows()
00723     {
00724     if ( root != qt_xrootwin() )
00725         return;
00726     if( tab_grab || control_grab )
00727         return;
00728     if ( options->altTabStyle == Options::CDE  || !options->focusPolicyIsReasonable() )
00729         {
00730         // CDE style raise / lower
00731         CDEWalkThroughWindows( false );
00732         }
00733     else
00734         {
00735         if ( areModKeysDepressed( cutWalkThroughWindowsReverse ) )
00736             {
00737             if ( startKDEWalkThroughWindows() )
00738                 KDEWalkThroughWindows( false );
00739             }
00740         else
00741             {
00742             CDEWalkThroughWindows( false );
00743             }
00744         }
00745     }
00746 
00747 void Workspace::slotWalkThroughDesktops()
00748     {
00749     if ( root != qt_xrootwin() )
00750         return;
00751     if( tab_grab || control_grab )
00752         return;
00753     if ( areModKeysDepressed( cutWalkThroughDesktops ) )
00754         {
00755         if ( startWalkThroughDesktops() )
00756             walkThroughDesktops( true );
00757         }
00758     else
00759         {
00760         oneStepThroughDesktops( true );
00761         }
00762     }
00763 
00764 void Workspace::slotWalkBackThroughDesktops()
00765     {
00766     if ( root != qt_xrootwin() )
00767         return;
00768     if( tab_grab || control_grab )
00769         return;
00770     if ( areModKeysDepressed( cutWalkThroughDesktopsReverse ) )
00771         {
00772         if ( startWalkThroughDesktops() )
00773             walkThroughDesktops( false );
00774         }
00775     else
00776         {
00777         oneStepThroughDesktops( false );
00778         }
00779     }
00780 
00781 void Workspace::slotWalkThroughDesktopList()
00782     {
00783     if ( root != qt_xrootwin() )
00784         return;
00785     if( tab_grab || control_grab )
00786         return;
00787     if ( areModKeysDepressed( cutWalkThroughDesktopList ) )
00788         {
00789         if ( startWalkThroughDesktopList() )
00790             walkThroughDesktops( true );
00791         }
00792     else
00793         {
00794         oneStepThroughDesktopList( true );
00795         }
00796     }
00797 
00798 void Workspace::slotWalkBackThroughDesktopList()
00799     {
00800     if ( root != qt_xrootwin() )
00801         return;
00802     if( tab_grab || control_grab )
00803         return;
00804     if ( areModKeysDepressed( cutWalkThroughDesktopListReverse ) )
00805         {
00806         if ( startWalkThroughDesktopList() )
00807             walkThroughDesktops( false );
00808         }
00809     else
00810         {
00811         oneStepThroughDesktopList( false );
00812         }
00813     }
00814 
00815 bool Workspace::startKDEWalkThroughWindows()
00816     {
00817     if( !establishTabBoxGrab())
00818         return false;
00819     tab_grab        = TRUE;
00820     keys->setEnabled( false );
00821     tab_box->setMode( TabBox::WindowsMode );
00822     tab_box->reset();
00823     return TRUE;
00824     }
00825 
00826 bool Workspace::startWalkThroughDesktops( int mode )
00827     {
00828     if( !establishTabBoxGrab())
00829         return false;
00830     control_grab = TRUE;
00831     keys->setEnabled( false );
00832     tab_box->setMode( (TabBox::Mode) mode );
00833     tab_box->reset();
00834     return TRUE;
00835     }
00836 
00837 bool Workspace::startWalkThroughDesktops()
00838     {
00839     return startWalkThroughDesktops( TabBox::DesktopMode );
00840     }
00841 
00842 bool Workspace::startWalkThroughDesktopList()
00843     {
00844     return startWalkThroughDesktops( TabBox::DesktopListMode );
00845     }
00846 
00847 void Workspace::KDEWalkThroughWindows( bool forward )
00848     {
00849     tab_box->nextPrev( forward );
00850     tab_box->delayedShow();
00851     }
00852 
00853 void Workspace::walkThroughDesktops( bool forward )
00854     {
00855     tab_box->nextPrev( forward );
00856     tab_box->delayedShow();
00857     }
00858 
00859 void Workspace::CDEWalkThroughWindows( bool forward )
00860     {
00861     Client* c = topClientOnDesktop( currentDesktop());
00862     Client* nc = c;
00863     bool options_traverse_all;
00864         {
00865         KConfigGroupSaver saver( KGlobal::config(), "TabBox" );
00866         options_traverse_all = KGlobal::config()->readNumEntry("TraverseAll", false );
00867         }
00868 
00869     if ( !forward )
00870         {
00871         do
00872             {
00873             nc = previousStaticClient(nc);
00874             } while (nc && nc != c &&
00875         (( !options_traverse_all && !nc->isOnDesktop(currentDesktop())) ||
00876          nc->isMinimized() || !nc->wantsTabFocus() ) );
00877         }
00878     else
00879         {
00880             do
00881             {
00882             nc = nextStaticClient(nc);
00883             } while (nc && nc != c &&
00884                     (( !options_traverse_all && !nc->isOnDesktop(currentDesktop())) ||
00885                      nc->isMinimized() || !nc->wantsTabFocus() ) );
00886         }
00887     if (c && c != nc)
00888         lowerClient( c );
00889     if (nc)
00890         {
00891         if ( options->focusPolicyIsReasonable() )
00892             {
00893             activateClient( nc );
00894             if( nc->isShade())
00895                 nc->setShade( ShadeActivated );
00896             }
00897         else
00898             {
00899             if( !nc->isOnDesktop( currentDesktop()))
00900                 setCurrentDesktop( nc->desktop());
00901             raiseClient( nc );
00902             }
00903         }
00904     }
00905 
00906 void Workspace::KDEOneStepThroughWindows( bool forward )
00907     {
00908     tab_box->setMode( TabBox::WindowsMode );
00909     tab_box->reset();
00910     tab_box->nextPrev( forward );
00911     if( Client* c = tab_box->currentClient() )
00912         {
00913         activateClient( c );
00914         if( c->isShade())
00915             c->setShade( ShadeActivated );
00916         }
00917     }
00918 
00919 void Workspace::oneStepThroughDesktops( bool forward, int mode )
00920     {
00921     tab_box->setMode( (TabBox::Mode) mode );
00922     tab_box->reset();
00923     tab_box->nextPrev( forward );
00924     if ( tab_box->currentDesktop() != -1 )
00925         setCurrentDesktop( tab_box->currentDesktop() );
00926     }
00927 
00928 void Workspace::oneStepThroughDesktops( bool forward )
00929     {
00930     oneStepThroughDesktops( forward, TabBox::DesktopMode );
00931     }
00932 
00933 void Workspace::oneStepThroughDesktopList( bool forward )
00934     {
00935     oneStepThroughDesktops( forward, TabBox::DesktopListMode );
00936     }
00937 
00941 void Workspace::tabBoxKeyPress( const KKeyNative& keyX )
00942     {
00943     bool forward = false;
00944     bool backward = false;
00945 
00946     if (tab_grab)
00947         {
00948         forward = cutWalkThroughWindows.contains( keyX );
00949         backward = cutWalkThroughWindowsReverse.contains( keyX );
00950         if (forward || backward)
00951             {
00952             kdDebug(125) << "== " << cutWalkThroughWindows.toStringInternal()
00953                 << " or " << cutWalkThroughWindowsReverse.toStringInternal() << endl;
00954             KDEWalkThroughWindows( forward );
00955             }
00956         }
00957     else if (control_grab)
00958         {
00959         forward = cutWalkThroughDesktops.contains( keyX ) ||
00960                   cutWalkThroughDesktopList.contains( keyX );
00961         backward = cutWalkThroughDesktopsReverse.contains( keyX ) ||
00962                    cutWalkThroughDesktopListReverse.contains( keyX );
00963         if (forward || backward)
00964             walkThroughDesktops(forward);
00965         }
00966 
00967     if (control_grab || tab_grab)
00968         {
00969         uint keyQt = keyX.keyCodeQt();
00970         if ( ((keyQt & 0xffff) == Qt::Key_Escape)
00971             && !(forward || backward) )
00972             { // if Escape is part of the shortcut, don't cancel
00973             closeTabBox();
00974             }
00975         }
00976     }
00977 
00978 void Workspace::closeTabBox()
00979     {
00980     removeTabBoxGrab();
00981     tab_box->hide();
00982     keys->setEnabled( true );
00983     tab_grab = FALSE;
00984     control_grab = FALSE;
00985     }
00986 
00990 void Workspace::tabBoxKeyRelease( const XKeyEvent& ev )
00991     {
00992     unsigned int mk = ev.state &
00993         (KKeyNative::modX(KKey::SHIFT) |
00994          KKeyNative::modX(KKey::CTRL) |
00995          KKeyNative::modX(KKey::ALT) |
00996          KKeyNative::modX(KKey::WIN));
00997     // ev.state is state before the key release, so just checking mk being 0 isn't enough
00998     // using XQueryPointer() also doesn't seem to work well, so the check that all
00999     // modifiers are released: only one modifier is active and the currently released
01000     // key is this modifier - if yes, release the grab
01001     int mod_index = -1;
01002     for( int i = ShiftMapIndex;
01003          i <= Mod5MapIndex;
01004          ++i )
01005         if(( mk & ( 1 << i )) != 0 )
01006         {
01007         if( mod_index >= 0 )
01008             return;
01009         mod_index = i;
01010         }
01011     bool release = false;
01012     if( mod_index == -1 )
01013         release = true;
01014     else
01015         {
01016         XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay());
01017         for (int i=0; i<xmk->max_keypermod; i++)
01018             if (xmk->modifiermap[xmk->max_keypermod * mod_index + i]
01019                 == ev.keycode)
01020                 release = true;
01021         XFreeModifiermap(xmk);
01022         }
01023     if( !release )
01024          return;
01025     if (tab_grab)
01026         {
01027         removeTabBoxGrab();
01028         tab_box->hide();
01029         keys->setEnabled( true );
01030         tab_grab = false;
01031         if( Client* c = tab_box->currentClient())
01032             {
01033             activateClient( c );
01034             if( c->isShade())
01035                 c->setShade( ShadeActivated );
01036             }
01037         }
01038     if (control_grab)
01039         {
01040         removeTabBoxGrab();
01041         tab_box->hide();
01042         keys->setEnabled( true );
01043         control_grab = False;
01044         if ( tab_box->currentDesktop() != -1 )
01045             {
01046             setCurrentDesktop( tab_box->currentDesktop() );
01047                     // popupinfo->showInfo( desktopName(currentDesktop()) ); // AK - not sure
01048             }
01049         }
01050     }
01051 
01052 
01053 int Workspace::nextDesktopFocusChain( int iDesktop ) const
01054     {
01055     int i = desktop_focus_chain.find( iDesktop );
01056     if( i >= 0 && i+1 < (int)desktop_focus_chain.size() )
01057             return desktop_focus_chain[i+1];
01058     else if( desktop_focus_chain.size() > 0 )
01059             return desktop_focus_chain[ 0 ];
01060     else
01061             return 1;
01062     }
01063 
01064 int Workspace::previousDesktopFocusChain( int iDesktop ) const
01065     {
01066     int i = desktop_focus_chain.find( iDesktop );
01067     if( i-1 >= 0 )
01068             return desktop_focus_chain[i-1];
01069     else if( desktop_focus_chain.size() > 0 )
01070             return desktop_focus_chain[desktop_focus_chain.size()-1];
01071     else
01072             return numberOfDesktops();
01073     }
01074 
01079 Client* Workspace::nextFocusChainClient( Client* c ) const
01080     {
01081     if ( focus_chain.isEmpty() )
01082         return 0;
01083     ClientList::ConstIterator it = focus_chain.find( c );
01084     if ( it == focus_chain.end() )
01085         return focus_chain.last();
01086     if ( it == focus_chain.begin() )
01087         return focus_chain.last();
01088     --it;
01089     return *it;
01090     }
01091 
01096 Client* Workspace::previousFocusChainClient( Client* c ) const
01097     {
01098     if ( focus_chain.isEmpty() )
01099         return 0;
01100     ClientList::ConstIterator it = focus_chain.find( c );
01101     if ( it == focus_chain.end() )
01102         return focus_chain.first();
01103     ++it;
01104     if ( it == focus_chain.end() )
01105         return focus_chain.first();
01106     return *it;
01107     }
01108 
01113 Client* Workspace::nextStaticClient( Client* c ) const
01114     {
01115     if ( !c || clients.isEmpty() )
01116         return 0;
01117     ClientList::ConstIterator it = clients.find( c );
01118     if ( it == clients.end() )
01119         return clients.first();
01120     ++it;
01121     if ( it == clients.end() )
01122         return clients.first();
01123     return *it;
01124     }
01129 Client* Workspace::previousStaticClient( Client* c ) const
01130     {
01131     if ( !c || clients.isEmpty() )
01132         return 0;
01133     ClientList::ConstIterator it = clients.find( c );
01134     if ( it == clients.end() )
01135         return clients.last();
01136     if ( it == clients.begin() )
01137         return clients.last();
01138     --it;
01139     return *it;
01140     }
01141 
01142 bool Workspace::establishTabBoxGrab()
01143     {
01144     if( XGrabKeyboard( qt_xdisplay(), root, FALSE,
01145         GrabModeAsync, GrabModeAsync, qt_x_time) != GrabSuccess )
01146         return false;
01147     // Don't try to establish a global mouse grab using XGrabPointer, as that would prevent
01148     // using Alt+Tab while DND (#44972). However force passive grabs on all windows
01149     // in order to catch MouseRelease events and close the tabbox (#67416).
01150     // All clients already have passive grabs in their wrapper windows, so check only
01151     // the active client, which may not have it.
01152     assert( !forced_global_mouse_grab );
01153     forced_global_mouse_grab = true;
01154     if( active_client != NULL )
01155         active_client->updateMouseGrab();
01156     return true;
01157     }
01158 
01159 void Workspace::removeTabBoxGrab()
01160     {
01161     XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01162     assert( forced_global_mouse_grab );
01163     forced_global_mouse_grab = false;
01164     if( active_client != NULL )
01165         active_client->updateMouseGrab();
01166     }
01167 
01168 } // namespace
01169 
01170 #include "tabbox.moc"
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 8 02:43:21 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003