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->isMinimized() || !c->isTransient() || c->isUtility()) && 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 00644 bool areModKeysDepressed( const KShortcut& cut ) 00645 { 00646 00647 uint rgKeySyms[10]; 00648 int nKeySyms = 0; 00649 int mod = cut.seq(0).key(0).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 void Workspace::slotWalkThroughWindows() 00683 { 00684 if ( root != qt_xrootwin() ) 00685 return; 00686 if ( tab_grab || control_grab ) 00687 return; 00688 if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable() ) 00689 { 00690 //XUngrabKeyboard(qt_xdisplay(), qt_x_time); // need that because of accelerator raw mode 00691 // CDE style raise / lower 00692 CDEWalkThroughWindows( true ); 00693 } 00694 else 00695 { 00696 if ( areModKeysDepressed( cutWalkThroughWindows ) ) 00697 { 00698 if ( startKDEWalkThroughWindows() ) 00699 KDEWalkThroughWindows( true ); 00700 } 00701 else 00702 // if the shortcut has no modifiers, don't show the tabbox, 00703 // don't grab, but simply go to the next window 00704 // use the CDE style, because with KDE style it would cycle 00705 // between the active and previously active window 00706 CDEWalkThroughWindows( true ); 00707 } 00708 } 00709 00710 void Workspace::slotWalkBackThroughWindows() 00711 { 00712 if ( root != qt_xrootwin() ) 00713 return; 00714 if( tab_grab || control_grab ) 00715 return; 00716 if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable() ) 00717 { 00718 // CDE style raise / lower 00719 CDEWalkThroughWindows( false ); 00720 } 00721 else 00722 { 00723 if ( areModKeysDepressed( cutWalkThroughWindowsReverse ) ) 00724 { 00725 if ( startKDEWalkThroughWindows() ) 00726 KDEWalkThroughWindows( false ); 00727 } 00728 else 00729 { 00730 CDEWalkThroughWindows( false ); 00731 } 00732 } 00733 } 00734 00735 void Workspace::slotWalkThroughDesktops() 00736 { 00737 if ( root != qt_xrootwin() ) 00738 return; 00739 if( tab_grab || control_grab ) 00740 return; 00741 if ( areModKeysDepressed( cutWalkThroughDesktops ) ) 00742 { 00743 if ( startWalkThroughDesktops() ) 00744 walkThroughDesktops( true ); 00745 } 00746 else 00747 { 00748 oneStepThroughDesktops( true ); 00749 } 00750 } 00751 00752 void Workspace::slotWalkBackThroughDesktops() 00753 { 00754 if ( root != qt_xrootwin() ) 00755 return; 00756 if( tab_grab || control_grab ) 00757 return; 00758 if ( areModKeysDepressed( cutWalkThroughDesktopsReverse ) ) 00759 { 00760 if ( startWalkThroughDesktops() ) 00761 walkThroughDesktops( false ); 00762 } 00763 else 00764 { 00765 oneStepThroughDesktops( false ); 00766 } 00767 } 00768 00769 void Workspace::slotWalkThroughDesktopList() 00770 { 00771 if ( root != qt_xrootwin() ) 00772 return; 00773 if( tab_grab || control_grab ) 00774 return; 00775 if ( areModKeysDepressed( cutWalkThroughDesktopList ) ) 00776 { 00777 if ( startWalkThroughDesktopList() ) 00778 walkThroughDesktops( true ); 00779 } 00780 else 00781 { 00782 oneStepThroughDesktopList( true ); 00783 } 00784 } 00785 00786 void Workspace::slotWalkBackThroughDesktopList() 00787 { 00788 if ( root != qt_xrootwin() ) 00789 return; 00790 if( tab_grab || control_grab ) 00791 return; 00792 if ( areModKeysDepressed( cutWalkThroughDesktopListReverse ) ) 00793 { 00794 if ( startWalkThroughDesktopList() ) 00795 walkThroughDesktops( false ); 00796 } 00797 else 00798 { 00799 oneStepThroughDesktopList( false ); 00800 } 00801 } 00802 00803 bool Workspace::startKDEWalkThroughWindows() 00804 { 00805 if( !establishTabBoxGrab()) 00806 return false; 00807 tab_grab = TRUE; 00808 keys->setEnabled( false ); 00809 tab_box->setMode( TabBox::WindowsMode ); 00810 tab_box->reset(); 00811 return TRUE; 00812 } 00813 00814 bool Workspace::startWalkThroughDesktops( int mode ) 00815 { 00816 if( !establishTabBoxGrab()) 00817 return false; 00818 control_grab = TRUE; 00819 keys->setEnabled( false ); 00820 tab_box->setMode( (TabBox::Mode) mode ); 00821 tab_box->reset(); 00822 return TRUE; 00823 } 00824 00825 bool Workspace::startWalkThroughDesktops() 00826 { 00827 return startWalkThroughDesktops( TabBox::DesktopMode ); 00828 } 00829 00830 bool Workspace::startWalkThroughDesktopList() 00831 { 00832 return startWalkThroughDesktops( TabBox::DesktopListMode ); 00833 } 00834 00835 void Workspace::KDEWalkThroughWindows( bool forward ) 00836 { 00837 tab_box->nextPrev( forward ); 00838 tab_box->delayedShow(); 00839 } 00840 00841 void Workspace::walkThroughDesktops( bool forward ) 00842 { 00843 tab_box->nextPrev( forward ); 00844 tab_box->delayedShow(); 00845 } 00846 00847 void Workspace::CDEWalkThroughWindows( bool forward ) 00848 { 00849 Client* c = topClientOnDesktop( currentDesktop()); 00850 Client* nc = c; 00851 bool options_traverse_all; 00852 { 00853 KConfigGroupSaver saver( KGlobal::config(), "TabBox" ); 00854 options_traverse_all = KGlobal::config()->readNumEntry("TraverseAll", false ); 00855 } 00856 00857 if ( !forward ) 00858 { 00859 do 00860 { 00861 nc = previousStaticClient(nc); 00862 } while (nc && nc != c && 00863 (( !options_traverse_all && !nc->isOnDesktop(currentDesktop())) || 00864 nc->isMinimized() || !nc->wantsTabFocus() ) ); 00865 } 00866 else 00867 { 00868 do 00869 { 00870 nc = nextStaticClient(nc); 00871 } while (nc && nc != c && 00872 (( !options_traverse_all && !nc->isOnDesktop(currentDesktop())) || 00873 nc->isMinimized() || !nc->wantsTabFocus() ) ); 00874 } 00875 if (c && c != nc) 00876 lowerClient( c ); 00877 if (nc) 00878 { 00879 if ( options->focusPolicyIsReasonable() ) 00880 { 00881 activateClient( nc ); 00882 if( nc->isShade()) 00883 nc->setShade( ShadeActivated ); 00884 } 00885 else 00886 { 00887 if( !nc->isOnDesktop( currentDesktop())) 00888 setCurrentDesktop( nc->desktop()); 00889 raiseClient( nc ); 00890 } 00891 } 00892 } 00893 00894 void Workspace::KDEOneStepThroughWindows( bool forward ) 00895 { 00896 tab_box->setMode( TabBox::WindowsMode ); 00897 tab_box->reset(); 00898 tab_box->nextPrev( forward ); 00899 if( Client* c = tab_box->currentClient() ) 00900 { 00901 activateClient( c ); 00902 if( c->isShade()) 00903 c->setShade( ShadeActivated ); 00904 } 00905 } 00906 00907 void Workspace::oneStepThroughDesktops( bool forward, int mode ) 00908 { 00909 tab_box->setMode( (TabBox::Mode) mode ); 00910 tab_box->reset(); 00911 tab_box->nextPrev( forward ); 00912 if ( tab_box->currentDesktop() != -1 ) 00913 setCurrentDesktop( tab_box->currentDesktop() ); 00914 } 00915 00916 void Workspace::oneStepThroughDesktops( bool forward ) 00917 { 00918 oneStepThroughDesktops( forward, TabBox::DesktopMode ); 00919 } 00920 00921 void Workspace::oneStepThroughDesktopList( bool forward ) 00922 { 00923 oneStepThroughDesktops( forward, TabBox::DesktopListMode ); 00924 } 00925 00929 void Workspace::tabBoxKeyPress( const KKeyNative& keyX ) 00930 { 00931 bool forward = false; 00932 bool backward = false; 00933 00934 if (tab_grab) 00935 { 00936 forward = cutWalkThroughWindows.contains( keyX ); 00937 backward = cutWalkThroughWindowsReverse.contains( keyX ); 00938 if (forward || backward) 00939 { 00940 kdDebug(125) << "== " << cutWalkThroughWindows.toStringInternal() 00941 << " or " << cutWalkThroughWindowsReverse.toStringInternal() << endl; 00942 KDEWalkThroughWindows( forward ); 00943 } 00944 } 00945 else if (control_grab) 00946 { 00947 forward = cutWalkThroughDesktops.contains( keyX ) || 00948 cutWalkThroughDesktopList.contains( keyX ); 00949 backward = cutWalkThroughDesktopsReverse.contains( keyX ) || 00950 cutWalkThroughDesktopListReverse.contains( keyX ); 00951 if (forward || backward) 00952 walkThroughDesktops(forward); 00953 } 00954 00955 if (control_grab || tab_grab) 00956 { 00957 uint keyQt = keyX.keyCodeQt(); 00958 if ( ((keyQt & 0xffff) == Qt::Key_Escape) 00959 && !(forward || backward) ) 00960 { // if Escape is part of the shortcut, don't cancel 00961 closeTabBox(); 00962 } 00963 } 00964 } 00965 00966 void Workspace::closeTabBox() 00967 { 00968 removeTabBoxGrab(); 00969 tab_box->hide(); 00970 keys->setEnabled( true ); 00971 tab_grab = FALSE; 00972 control_grab = FALSE; 00973 } 00974 00978 void Workspace::tabBoxKeyRelease( const XKeyEvent& ev ) 00979 { 00980 unsigned int mk = ev.state & 00981 (KKeyNative::modX(KKey::SHIFT) | 00982 KKeyNative::modX(KKey::CTRL) | 00983 KKeyNative::modX(KKey::ALT) | 00984 KKeyNative::modX(KKey::WIN)); 00985 // ev.state is state before the key release, so just checking mk being 0 isn't enough 00986 // using XQueryPointer() also doesn't seem to work well, so the check that all 00987 // modifiers are released: only one modifier is active and the currently released 00988 // key is this modifier - if yes, release the grab 00989 int mod_index = -1; 00990 for( int i = ShiftMapIndex; 00991 i <= Mod5MapIndex; 00992 ++i ) 00993 if(( mk & ( 1 << i )) != 0 ) 00994 { 00995 if( mod_index >= 0 ) 00996 return; 00997 mod_index = i; 00998 } 00999 bool release = false; 01000 if( mod_index == -1 ) 01001 release = true; 01002 else 01003 { 01004 XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay()); 01005 for (int i=0; i<xmk->max_keypermod; i++) 01006 if (xmk->modifiermap[xmk->max_keypermod * mod_index + i] 01007 == ev.keycode) 01008 release = true; 01009 XFreeModifiermap(xmk); 01010 } 01011 if( !release ) 01012 return; 01013 if (tab_grab) 01014 { 01015 removeTabBoxGrab(); 01016 tab_box->hide(); 01017 keys->setEnabled( true ); 01018 tab_grab = false; 01019 if( Client* c = tab_box->currentClient()) 01020 { 01021 activateClient( c ); 01022 if( c->isShade()) 01023 c->setShade( ShadeActivated ); 01024 } 01025 } 01026 if (control_grab) 01027 { 01028 removeTabBoxGrab(); 01029 tab_box->hide(); 01030 keys->setEnabled( true ); 01031 control_grab = False; 01032 if ( tab_box->currentDesktop() != -1 ) 01033 { 01034 setCurrentDesktop( tab_box->currentDesktop() ); 01035 // popupinfo->showInfo( desktopName(currentDesktop()) ); // AK - not sure 01036 } 01037 } 01038 } 01039 01040 01041 int Workspace::nextDesktopFocusChain( int iDesktop ) const 01042 { 01043 int i = desktop_focus_chain.find( iDesktop ); 01044 if( i >= 0 && i+1 < (int)desktop_focus_chain.size() ) 01045 return desktop_focus_chain[i+1]; 01046 else if( desktop_focus_chain.size() > 0 ) 01047 return desktop_focus_chain[ 0 ]; 01048 else 01049 return 1; 01050 } 01051 01052 int Workspace::previousDesktopFocusChain( int iDesktop ) const 01053 { 01054 int i = desktop_focus_chain.find( iDesktop ); 01055 if( i-1 >= 0 ) 01056 return desktop_focus_chain[i-1]; 01057 else if( desktop_focus_chain.size() > 0 ) 01058 return desktop_focus_chain[desktop_focus_chain.size()-1]; 01059 else 01060 return numberOfDesktops(); 01061 } 01062 01067 Client* Workspace::nextFocusChainClient( Client* c ) const 01068 { 01069 if ( focus_chain.isEmpty() ) 01070 return 0; 01071 ClientList::ConstIterator it = focus_chain.find( c ); 01072 if ( it == focus_chain.end() ) 01073 return focus_chain.last(); 01074 if ( it == focus_chain.begin() ) 01075 return focus_chain.last(); 01076 --it; 01077 return *it; 01078 } 01079 01084 Client* Workspace::previousFocusChainClient( Client* c ) const 01085 { 01086 if ( focus_chain.isEmpty() ) 01087 return 0; 01088 ClientList::ConstIterator it = focus_chain.find( c ); 01089 if ( it == focus_chain.end() ) 01090 return focus_chain.first(); 01091 ++it; 01092 if ( it == focus_chain.end() ) 01093 return focus_chain.first(); 01094 return *it; 01095 } 01096 01101 Client* Workspace::nextStaticClient( Client* c ) const 01102 { 01103 if ( !c || clients.isEmpty() ) 01104 return 0; 01105 ClientList::ConstIterator it = clients.find( c ); 01106 if ( it == clients.end() ) 01107 return clients.first(); 01108 ++it; 01109 if ( it == clients.end() ) 01110 return clients.first(); 01111 return *it; 01112 } 01117 Client* Workspace::previousStaticClient( Client* c ) const 01118 { 01119 if ( !c || clients.isEmpty() ) 01120 return 0; 01121 ClientList::ConstIterator it = clients.find( c ); 01122 if ( it == clients.end() ) 01123 return clients.last(); 01124 if ( it == clients.begin() ) 01125 return clients.last(); 01126 --it; 01127 return *it; 01128 } 01129 01130 bool Workspace::establishTabBoxGrab() 01131 { 01132 if( XGrabKeyboard( qt_xdisplay(), root, FALSE, 01133 GrabModeAsync, GrabModeAsync, qt_x_time) != GrabSuccess ) 01134 return false; 01135 // Don't try to establish a global mouse grab using XGrabPointer, as that would prevent 01136 // using Alt+Tab while DND (#44972). However force passive grabs on all windows 01137 // in order to catch MouseRelease events and close the tabbox (#67416). 01138 // All clients already have passive grabs in their wrapper windows, so check only 01139 // the active client, which may not have it. 01140 assert( !forced_global_mouse_grab ); 01141 forced_global_mouse_grab = true; 01142 if( active_client != NULL ) 01143 active_client->updateMouseGrab(); 01144 return true; 01145 } 01146 01147 void Workspace::removeTabBoxGrab() 01148 { 01149 XUngrabKeyboard(qt_xdisplay(), qt_x_time); 01150 assert( forced_global_mouse_grab ); 01151 forced_global_mouse_grab = false; 01152 if( active_client != NULL ) 01153 active_client->updateMouseGrab(); 01154 } 01155 01156 } // namespace 01157 01158 #include "tabbox.moc"
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 13 21:47:06 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003