• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kwin
 

kwin

tabbox.cpp

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 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 <tqpainter.h>
00017 #include <tqlabel.h>
00018 #include <tqdrawutil.h>
00019 #include <tqstyle.h>
00020 #include <kglobal.h>
00021 #include <fixx11h.h>
00022 #include <kconfig.h>
00023 #include <klocale.h>
00024 #include <tqapplication.h>
00025 #include <tqdesktopwidget.h>
00026 #include <kstringhandler.h>
00027 #include <stdarg.h>
00028 #include <kdebug.h>
00029 #include <kglobalaccel.h>
00030 #include <kkeynative.h>
00031 #include <kglobalsettings.h>
00032 #include <kiconeffect.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 TQPixmap* kwin_get_menu_pix_hack();
00044 
00045 TabBox::TabBox( Workspace *ws, const char *name )
00046     : TQFrame( 0, name, Qt::WNoAutoErase ), current_client( NULL ), wspace(ws)
00047     {
00048     setFrameStyle(TQFrame::StyledPanel | TQFrame::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, TQT_SIGNAL(timeout()), this, TQT_SLOT(show()));
00059     
00060     XSetWindowAttributes attr;
00061     attr.override_redirect = 1;
00062     outline_left = XCreateWindow( qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0,
00063         CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
00064     outline_right = XCreateWindow( qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0,
00065         CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
00066     outline_top = XCreateWindow( qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0,
00067         CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
00068     outline_bottom = XCreateWindow( qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0,
00069         CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
00070     }
00071 
00072 TabBox::~TabBox()
00073     {
00074     XDestroyWindow( qt_xdisplay(), outline_left );
00075     XDestroyWindow( qt_xdisplay(), outline_right );
00076     XDestroyWindow( qt_xdisplay(), outline_top );
00077     XDestroyWindow( qt_xdisplay(), outline_bottom );
00078     }
00079 
00080 
00086 void TabBox::setMode( Mode mode )
00087     {
00088     m = mode;
00089     }
00090 
00091 
00095 void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client *c, bool chain)
00096     {
00097     ClientList::size_type idx = 0;
00098 
00099     list.clear();
00100 
00101     Client* start = c;
00102 
00103     if ( chain )
00104         c = workspace()->nextFocusChainClient(c);
00105     else
00106         c = workspace()->stackingOrder().first();
00107 
00108     Client* stop = c;
00109 
00110     while ( c )
00111         {
00112         Client* add = NULL;
00113         if ( ((desktop == -1) || c->isOnDesktop(desktop))
00114              && c->wantsTabFocus() )
00115             { // don't add windows that have modal dialogs
00116             Client* modal = c->findModal();
00117             if( modal == NULL || modal == c )
00118                 add = c;
00119             else if( !list.contains( modal ))
00120                 add = modal;
00121             else
00122                 {
00123                 // nothing
00124                 }
00125             }
00126 
00127         if( options->separateScreenFocus && options->xineramaEnabled )
00128             {
00129             if( c->screen() != workspace()->activeScreen())
00130                 add = NULL;
00131             }
00132 
00133         if( add != NULL )
00134             {
00135             if ( start == add )
00136                 {
00137                 list.remove( add );
00138                 list.prepend( add );
00139                 }
00140             else
00141                 list += add;
00142             }
00143 
00144         if ( chain )
00145           c = workspace()->nextFocusChainClient( 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 
00164 void TabBox::reset()
00165     {
00166     int w, h, cw = 0, wmax = 0;
00167 
00168     TQRect r = workspace()->screenGeometry( workspace()->activeScreen());
00169 
00170     // calculate height of 1 line
00171     // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below
00172     lineHeight = QMAX(fontMetrics().height() + 2, 32 + 4);
00173 
00174     if ( mode() == WindowsMode )
00175         {
00176         setCurrentClient( workspace()->activeClient());
00177 
00178         // get all clients to show
00179         createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), current_client, true);
00180 
00181         // calculate maximum caption width
00182         cw = fontMetrics().width(no_tasks)+20;
00183         for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00184           {
00185           cw = fontMetrics().width( (*it)->caption() );
00186           if ( cw > wmax ) wmax = cw;
00187           }
00188 
00189         // calculate height for the popup
00190         if ( clients.count() == 0 )  // height for the "not tasks" text
00191           {
00192           TQFont f = font();
00193           f.setBold( TRUE );
00194           f.setPointSize( 14 );
00195 
00196           h = TQFontMetrics(f).height()*4;
00197           }
00198         else
00199           {
00200           showMiniIcon = false;
00201           h = clients.count() * lineHeight;
00202 
00203           if ( h > (r.height()-(2*frameWidth())) )  // if too high, use mini icons
00204             {
00205             showMiniIcon = true;
00206             // fontheight + 1 pixel above + 1 pixel below, or 16x16 icon + 1 pixel above + below
00207             lineHeight = QMAX(fontMetrics().height() + 2, 16 + 2);
00208 
00209             h = clients.count() * lineHeight;
00210 
00211             if ( h > (r.height()-(2*frameWidth())) ) // if still too high, remove some clients
00212               {
00213                 // how many clients to remove
00214                 int howMany = (h - (r.height()-(2*frameWidth())))/lineHeight;
00215                 for (; howMany; howMany--)
00216                   clients.remove(clients.last());
00217 
00218                 h = clients.count() * lineHeight;
00219               }
00220             }
00221           }
00222         }
00223     else
00224         { // DesktopListMode
00225         showMiniIcon = false;
00226         desk = workspace()->currentDesktop();
00227 
00228         for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
00229           {
00230           cw = fontMetrics().width( workspace()->desktopName(i) );
00231           if ( cw > wmax ) wmax = cw;
00232           }
00233 
00234         // calculate height for the popup (max. 16 desktops always fit in a 800x600 screen)
00235         h = workspace()->numberOfDesktops() * lineHeight;
00236         }
00237 
00238     // height, width for the popup
00239     h += 2 * frameWidth();
00240     w = 2*frameWidth() + 5*2 + ( showMiniIcon ? 16 : 32 ) + 8 + wmax; // 5*2=margins, ()=icon, 8=space between icon+text
00241     w = kClamp( w, r.width()/3 , r.width() * 4 / 5 );
00242 
00243     setGeometry( (r.width()-w)/2 + r.x(),
00244                  (r.height()-h)/2+ r.y(),
00245                  w, h );
00246     }
00247 
00248 
00252 void TabBox::nextPrev( bool next)
00253     {
00254     if ( mode() == WindowsMode )
00255         {
00256         Client* firstClient = NULL;
00257         Client* client = current_client;
00258         do
00259             {
00260             if ( next )
00261                 client = workspace()->nextFocusChainClient(client);
00262             else
00263                 client = workspace()->previousFocusChainClient(client);
00264             if (!firstClient)
00265                 {
00266         // When we see our first client for the second time,
00267         // it's time to stop.
00268                 firstClient = client;
00269                 }
00270             else if (client == firstClient)
00271                 {
00272         // No candidates found.
00273                 client = 0;
00274                 break;
00275                 }
00276             } while ( client && !clients.contains( client ));
00277         setCurrentClient( client );
00278         }
00279     else if( mode() == DesktopMode )
00280         {
00281         if ( next )
00282             desk = workspace()->nextDesktopFocusChain( desk );
00283         else
00284             desk = workspace()->previousDesktopFocusChain( desk );
00285         }
00286     else
00287         { // DesktopListMode
00288         if ( next )
00289             {
00290             desk++;
00291             if ( desk > workspace()->numberOfDesktops() )
00292                 desk = 1;
00293             }
00294         else
00295             {
00296             desk--;
00297             if ( desk < 1 )
00298                 desk = workspace()->numberOfDesktops();
00299             }
00300         }
00301 
00302     update();
00303     }
00304 
00305 
00306 
00311 Client* TabBox::currentClient()
00312     {
00313     if ( mode() != WindowsMode )
00314         return 0;
00315     if (!workspace()->hasClient( current_client ))
00316         return 0;
00317     return current_client;
00318     }
00319 
00320 void TabBox::setCurrentClient( Client* c )
00321     {
00322     if( current_client != c )
00323         {
00324         current_client = c;
00325         updateOutline();
00326         }
00327     }
00328 
00334 int TabBox::currentDesktop()
00335     {
00336     if ( mode() == DesktopListMode || mode() == DesktopMode )
00337         return desk;
00338     else
00339         return -1;
00340     }
00341 
00342 
00346 void TabBox::showEvent( TQShowEvent* )
00347     {
00348     updateOutline();
00349     XRaiseWindow( qt_xdisplay(), outline_left );
00350     XRaiseWindow( qt_xdisplay(), outline_right );
00351     XRaiseWindow( qt_xdisplay(), outline_top );
00352     XRaiseWindow( qt_xdisplay(), outline_bottom );
00353     raise();
00354     }
00355 
00356 
00360 void TabBox::hideEvent( TQHideEvent* )
00361     {
00362     XUnmapWindow( qt_xdisplay(), outline_left );
00363     XUnmapWindow( qt_xdisplay(), outline_right );
00364     XUnmapWindow( qt_xdisplay(), outline_top );
00365     XUnmapWindow( qt_xdisplay(), outline_bottom );
00366     }
00367 
00371 void TabBox::drawContents( TQPainter * )
00372     {
00373     TQRect r(contentsRect());
00374     TQPixmap pix(r.size());  // do double buffering to avoid flickers
00375     pix.fill(this, 0, 0);
00376 
00377     TQPainter p;
00378     p.begin(&pix, this);
00379 
00380     TQPixmap* menu_pix = kwin_get_menu_pix_hack();
00381 
00382     int iconWidth = showMiniIcon ? 16 : 32;
00383     int x = 0;
00384     int y = 0;
00385 
00386     if ( mode () == WindowsMode )
00387         {
00388         if ( !currentClient() )
00389             {
00390             TQFont f = font();
00391             f.setBold( TRUE );
00392             f.setPointSize( 14 );
00393 
00394             p.setFont(f);
00395             p.drawText( r, AlignCenter, no_tasks);
00396             }
00397         else
00398             {
00399             for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00400               {
00401               if ( workspace()->hasClient( *it ) )  // safety
00402                   {
00403                   // draw highlight background
00404                   if ( (*it) == current_client )
00405                     p.fillRect(x, y, r.width(), lineHeight, colorGroup().highlight());
00406 
00407                   // draw icon
00408                   TQPixmap icon;
00409                   if ( showMiniIcon )
00410                     {
00411                     if ( !(*it)->miniIcon().isNull() )
00412                       icon = (*it)->miniIcon();
00413                     }
00414                   else
00415                     if ( !(*it)->icon().isNull() )
00416                       icon = (*it)->icon();
00417                     else if ( menu_pix )
00418                       icon = *menu_pix;
00419                 
00420                   if( !icon.isNull())
00421                     {
00422                     if( (*it)->isMinimized())
00423                         KIconEffect::semiTransparent( icon );
00424                     p.drawPixmap( x+5, y + (lineHeight - iconWidth)/2, icon );
00425                     }
00426 
00427                   // generate text to display
00428                   TQString s;
00429 
00430                   if ( !(*it)->isOnDesktop(workspace()->currentDesktop()) )
00431                     s = workspace()->desktopName((*it)->desktop()) + ": ";
00432 
00433                   if ( (*it)->isMinimized() )
00434                     s += TQString("(") + (*it)->caption() + ")";
00435                   else
00436                     s += (*it)->caption();
00437 
00438                   s = KStringHandler::cPixelSqueeze(s, fontMetrics(), r.width() - 5 - iconWidth - 8);
00439 
00440                   // draw text
00441                   if ( (*it) == current_client )
00442                     p.setPen(colorGroup().highlightedText());
00443                   else if( (*it)->isMinimized())
00444                     {
00445                     TQColor c1 = colorGroup().text();
00446                     TQColor c2 = colorGroup().background();
00447                     // from kicker's TaskContainer::blendColors()
00448                     int r1, g1, b1;
00449                     int r2, g2, b2;
00450 
00451                     c1.rgb( &r1, &g1, &b1 );
00452                     c2.rgb( &r2, &g2, &b2 );
00453 
00454                     r1 += (int) ( .5 * ( r2 - r1 ) );
00455                     g1 += (int) ( .5 * ( g2 - g1 ) );
00456                     b1 += (int) ( .5 * ( b2 - b1 ) );
00457 
00458                     p.setPen(TQColor( r1, g1, b1 ));
00459                     }
00460                   else
00461                     p.setPen(colorGroup().text());
00462 
00463                   p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
00464                               Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine, s);
00465 
00466                   y += lineHeight;
00467                   }
00468               if ( y >= r.height() ) break;
00469               }
00470             }
00471         }
00472     else
00473         { // DesktopMode || DesktopListMode
00474         int iconHeight = iconWidth;
00475 
00476         // get widest desktop name/number
00477         TQFont f(font());
00478         f.setBold(true);
00479         f.setPixelSize(iconHeight - 4);  // pixel, not point because I need to know the pixels
00480         TQFontMetrics fm(f);
00481 
00482         int wmax = 0;
00483         for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
00484             {
00485             wmax = QMAX(wmax, fontMetrics().width(workspace()->desktopName(i)));
00486 
00487             // calculate max width of desktop-number text
00488             TQString num = TQString::number(i);
00489             iconWidth = QMAX(iconWidth - 4, fm.boundingRect(num).width()) + 4;
00490             }
00491 
00492         // In DesktopMode, start at the current desktop
00493         // In DesktopListMode, start at desktop #1
00494         int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
00495         for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
00496             {
00497             // draw highlight background
00498             if ( iDesktop == desk )  // current desktop
00499               p.fillRect(x, y, r.width(), lineHeight, colorGroup().highlight());
00500 
00501             p.save();
00502 
00503             // draw "icon" (here: number of desktop)
00504             p.fillRect(x+5, y+2, iconWidth, iconHeight, colorGroup().base());
00505             p.setPen(colorGroup().text());
00506             p.drawRect(x+5, y+2, iconWidth, iconHeight);
00507 
00508             // draw desktop-number
00509             p.setFont(f);
00510             TQString num = TQString::number(iDesktop);
00511             p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num);
00512 
00513             p.restore();
00514 
00515             // draw desktop name text
00516             if ( iDesktop == desk )
00517               p.setPen(colorGroup().highlightedText());
00518             else
00519               p.setPen(colorGroup().text());
00520 
00521             p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
00522                        Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine,
00523                        workspace()->desktopName(iDesktop));
00524 
00525             // show mini icons from that desktop aligned to each other
00526             int x1 = x + 5 + iconWidth + 8 + wmax + 5;
00527 
00528             ClientList list;
00529             createClientList(list, iDesktop, 0, false);
00530             // clients are in reversed stacking order
00531             for (ClientList::ConstIterator it = list.fromLast(); it != list.end(); --it)
00532               {
00533               if ( !(*it)->miniIcon().isNull() )
00534                 {
00535                 if ( x1+18 >= x+r.width() )  // only show full icons
00536                   break;
00537 
00538                 p.drawPixmap( x1, y + (lineHeight - 16)/2, (*it)->miniIcon() );
00539                 x1 += 18;
00540                 }
00541               }
00542 
00543             // next desktop
00544             y += lineHeight;
00545             if ( y >= r.height() ) break;
00546 
00547             if( mode() == DesktopMode )
00548                 iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
00549             else
00550                 iDesktop++;
00551             }
00552         }
00553     p.end();
00554     bitBlt(this, r.x(), r.y(), &pix);
00555     }
00556 
00557 void TabBox::updateOutline()
00558     {
00559     Client* c = currentClient();
00560     if( !options->tabboxOutline || c == NULL || this->isHidden() || !c->isShown( true ) || !c->isOnCurrentDesktop())
00561         {
00562         XUnmapWindow( qt_xdisplay(), outline_left );
00563         XUnmapWindow( qt_xdisplay(), outline_right );
00564         XUnmapWindow( qt_xdisplay(), outline_top );
00565         XUnmapWindow( qt_xdisplay(), outline_bottom );
00566         return;
00567         }
00568     // left/right parts are between top/bottom, they don't reach as far as the corners
00569     XMoveResizeWindow( qt_xdisplay(), outline_left, c->x(), c->y() + 5, 5, c->height() - 10 );
00570     XMoveResizeWindow( qt_xdisplay(), outline_right, c->x() + c->width() - 5, c->y() + 5, 5, c->height() - 10 );
00571     XMoveResizeWindow( qt_xdisplay(), outline_top, c->x(), c->y(), c->width(), 5 );
00572     XMoveResizeWindow( qt_xdisplay(), outline_bottom, c->x(), c->y() + c->height() - 5, c->width(), 5 );
00573     {
00574     TQPixmap pix( 5, c->height() - 10 );
00575     TQPainter p( &pix );
00576     p.setPen( white );
00577     p.drawLine( 0, 0, 0, pix.height() - 1 );
00578     p.drawLine( 4, 0, 4, pix.height() - 1 );
00579     p.setPen( gray );
00580     p.drawLine( 1, 0, 1, pix.height() - 1 );
00581     p.drawLine( 3, 0, 3, pix.height() - 1 );
00582     p.setPen( black );
00583     p.drawLine( 2, 0, 2, pix.height() - 1 );
00584     p.end();
00585     XSetWindowBackgroundPixmap( qt_xdisplay(), outline_left, pix.handle());
00586     XSetWindowBackgroundPixmap( qt_xdisplay(), outline_right, pix.handle());
00587     }
00588     {
00589     TQPixmap pix( c->width(), 5 );
00590     TQPainter p( &pix );
00591     p.setPen( white );
00592     p.drawLine( 0, 0, pix.width() - 1 - 0, 0 );
00593     p.drawLine( 4, 4, pix.width() - 1 - 4, 4 );
00594     p.drawLine( 0, 0, 0, 4 );
00595     p.drawLine( pix.width() - 1 - 0, 0, pix.width() - 1 - 0, 4 );
00596     p.setPen( gray );
00597     p.drawLine( 1, 1, pix.width() - 1 - 1, 1 );
00598     p.drawLine( 3, 3, pix.width() - 1 - 3, 3 );
00599     p.drawLine( 1, 1, 1, 4 );
00600     p.drawLine( 3, 3, 3, 4 );
00601     p.drawLine( pix.width() - 1 - 1, 1, pix.width() - 1 - 1, 4 );
00602     p.drawLine( pix.width() - 1 - 3, 3, pix.width() - 1 - 3, 4 );
00603     p.setPen( black );
00604     p.drawLine( 2, 2, pix.width() - 1 - 2, 2 );
00605     p.drawLine( 2, 2, 2, 4 );
00606     p.drawLine( pix.width() - 1 - 2, 2, pix.width() - 1 - 2, 4 );
00607     p.end();
00608     XSetWindowBackgroundPixmap( qt_xdisplay(), outline_top, pix.handle());
00609     }
00610     {
00611     TQPixmap pix( c->width(), 5 );
00612     TQPainter p( &pix );
00613     p.setPen( white );
00614     p.drawLine( 4, 0, pix.width() - 1 - 4, 0 );
00615     p.drawLine( 0, 4, pix.width() - 1 - 0, 4 );
00616     p.drawLine( 0, 4, 0, 0 );
00617     p.drawLine( pix.width() - 1 - 0, 4, pix.width() - 1 - 0, 0 );
00618     p.setPen( gray );
00619     p.drawLine( 3, 1, pix.width() - 1 - 3, 1 );
00620     p.drawLine( 1, 3, pix.width() - 1 - 1, 3 );
00621     p.drawLine( 3, 1, 3, 0 );
00622     p.drawLine( 1, 3, 1, 0 );
00623     p.drawLine( pix.width() - 1 - 3, 1, pix.width() - 1 - 3, 0 );
00624     p.drawLine( pix.width() - 1 - 1, 3, pix.width() - 1 - 1, 0 );
00625     p.setPen( black );
00626     p.drawLine( 2, 2, pix.width() - 1 - 2, 2 );
00627     p.drawLine( 2, 0, 2, 2 );
00628     p.drawLine( pix.width() - 1 - 2, 0, pix.width() - 1 - 2, 2 );
00629     p.end();
00630     XSetWindowBackgroundPixmap( qt_xdisplay(), outline_bottom, pix.handle());
00631     }
00632     XClearWindow( qt_xdisplay(), outline_left );
00633     XClearWindow( qt_xdisplay(), outline_right );
00634     XClearWindow( qt_xdisplay(), outline_top );
00635     XClearWindow( qt_xdisplay(), outline_bottom );
00636     XMapWindow( qt_xdisplay(), outline_left );
00637     XMapWindow( qt_xdisplay(), outline_right );
00638     XMapWindow( qt_xdisplay(), outline_top );
00639     XMapWindow( qt_xdisplay(), outline_bottom );
00640     }
00641 
00642 void TabBox::hide()
00643     {
00644     delayedShowTimer.stop();
00645     TQWidget::hide();
00646     TQApplication::syncX();
00647     XEvent otherEvent;
00648     while (XCheckTypedEvent (qt_xdisplay(), EnterNotify, &otherEvent ) )
00649         ;
00650     }
00651 
00652 
00653 void TabBox::reconfigure()
00654     {
00655     KConfig * c(KGlobal::config());
00656     c->setGroup("TabBox");
00657     options_traverse_all = c->readBoolEntry("TraverseAll", false );
00658     }
00659 
00678 void TabBox::delayedShow()
00679     {
00680     KConfig * c(KGlobal::config());
00681     c->setGroup("TabBox");
00682     bool delay = c->readBoolEntry("ShowDelay", true);
00683 
00684     if (!delay)
00685         {
00686         show();
00687         return;
00688         }
00689 
00690     int delayTime = c->readNumEntry("DelayTime", 90);
00691     delayedShowTimer.start(delayTime, true);
00692     }
00693 
00694 
00695 void TabBox::handleMouseEvent( XEvent* e )
00696     {
00697     XAllowEvents( qt_xdisplay(), AsyncPointer, qt_x_time );
00698     if( e->type != ButtonPress )
00699         return;
00700     TQPoint pos( e->xbutton.x_root, e->xbutton.y_root );
00701     if( !geometry().contains( pos ))
00702         {
00703         workspace()->closeTabBox();  // click outside closes tab
00704         return;
00705         }
00706     pos.rx() -= x(); // pos is now inside tabbox
00707     pos.ry() -= y();
00708     int num = (pos.y()-frameWidth()) / lineHeight;
00709 
00710     if( mode() == WindowsMode )
00711         {
00712         for( ClientList::ConstIterator it = clients.begin();
00713              it != clients.end();
00714              ++it)
00715             {
00716             if( workspace()->hasClient( *it ) && (num == 0) ) // safety
00717                 {
00718                 setCurrentClient( *it );
00719                 break;
00720                 }
00721             num--;
00722             }
00723         }
00724     else
00725         {
00726         int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
00727         for( int i = 1;
00728              i <= workspace()->numberOfDesktops();
00729              ++i )
00730             {
00731             if( num == 0 )
00732                 {
00733                 desk = iDesktop;
00734                 break;
00735                 }
00736             num--;
00737             if( mode() == DesktopMode )
00738                 iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
00739             else
00740                 iDesktop++;
00741             }
00742         }
00743     update();
00744     }
00745 
00746 //*******************************
00747 // Workspace
00748 //*******************************
00749 
00750 
00755 static
00756 bool areKeySymXsDepressed( bool bAll, const uint keySyms[], int nKeySyms )
00757     {
00758     char keymap[32];
00759 
00760     kdDebug(125) << "areKeySymXsDepressed: " << (bAll ? "all of " : "any of ") << nKeySyms << endl;
00761 
00762     XQueryKeymap( qt_xdisplay(), keymap );
00763 
00764     for( int iKeySym = 0; iKeySym < nKeySyms; iKeySym++ )
00765         {
00766         uint keySymX = keySyms[ iKeySym ];
00767         uchar keyCodeX = XKeysymToKeycode( qt_xdisplay(), keySymX );
00768         int i = keyCodeX / 8;
00769         char mask = 1 << (keyCodeX - (i * 8));
00770 
00771         kdDebug(125) << iKeySym << ": keySymX=0x" << TQString::number( keySymX, 16 )
00772                 << " i=" << i << " mask=0x" << TQString::number( mask, 16 )
00773                 << " keymap[i]=0x" << TQString::number( keymap[i], 16 ) << endl;
00774 
00775                 // Abort if bad index value,
00776         if( i < 0 || i >= 32 )
00777                 return false;
00778 
00779                 // If ALL keys passed need to be depressed,
00780         if( bAll )
00781             {
00782             if( (keymap[i] & mask) == 0 )
00783                     return false;
00784             }
00785         else
00786             {
00787                         // If we are looking for ANY key press, and this key is depressed,
00788             if( keymap[i] & mask )
00789                     return true;
00790             }
00791         }
00792 
00793         // If we were looking for ANY key press, then none was found, return false,
00794         // If we were looking for ALL key presses, then all were found, return true.
00795     return bAll;
00796     }
00797 
00798 static bool areModKeysDepressed( const KKeySequence& seq )
00799     {
00800     uint rgKeySyms[10];
00801     int nKeySyms = 0;
00802     if( seq.isNull())
00803     return false;
00804     int mod = seq.key(seq.count()-1).modFlags();
00805 
00806     if ( mod & KKey::SHIFT )
00807         {
00808         rgKeySyms[nKeySyms++] = XK_Shift_L;
00809         rgKeySyms[nKeySyms++] = XK_Shift_R;
00810         }
00811     if ( mod & KKey::CTRL )
00812         {
00813         rgKeySyms[nKeySyms++] = XK_Control_L;
00814         rgKeySyms[nKeySyms++] = XK_Control_R;
00815         }
00816     if( mod & KKey::ALT )
00817         {
00818         rgKeySyms[nKeySyms++] = XK_Alt_L;
00819         rgKeySyms[nKeySyms++] = XK_Alt_R;
00820         }
00821     if( mod & KKey::WIN )
00822         {
00823         // It would take some code to determine whether the Win key
00824         // is associated with Super or Meta, so check for both.
00825         // See bug #140023 for details.
00826         rgKeySyms[nKeySyms++] = XK_Super_L;
00827         rgKeySyms[nKeySyms++] = XK_Super_R;
00828         rgKeySyms[nKeySyms++] = XK_Meta_L;
00829         rgKeySyms[nKeySyms++] = XK_Meta_R;
00830         }
00831 
00832     return areKeySymXsDepressed( false, rgKeySyms, nKeySyms );
00833     }
00834 
00835 static bool areModKeysDepressed( const KShortcut& cut )
00836     {
00837     for( unsigned int i = 0;
00838      i < cut.count();
00839      ++i )
00840     {
00841     if( areModKeysDepressed( cut.seq( i )))
00842         return true;
00843     }
00844     return false;
00845     }
00846 
00847 void Workspace::slotWalkThroughWindows()
00848     {
00849     if ( root != qt_xrootwin() )
00850         return;
00851     if ( tab_grab || control_grab )
00852         return;
00853     if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable())
00854         {
00855         //XUngrabKeyboard(qt_xdisplay(), qt_x_time); // need that because of accelerator raw mode
00856         // CDE style raise / lower
00857         CDEWalkThroughWindows( true );
00858         }
00859     else
00860         {
00861         if ( areModKeysDepressed( cutWalkThroughWindows ) )
00862             {
00863             if ( startKDEWalkThroughWindows() )
00864                 KDEWalkThroughWindows( true );
00865             }
00866         else
00867             // if the shortcut has no modifiers, don't show the tabbox,
00868             // don't grab, but simply go to the next window
00869             KDEOneStepThroughWindows( true );
00870         }
00871     }
00872 
00873 void Workspace::slotWalkBackThroughWindows()
00874     {
00875     if ( root != qt_xrootwin() )
00876         return;
00877     if( tab_grab || control_grab )
00878         return;
00879     if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable())
00880         {
00881         // CDE style raise / lower
00882         CDEWalkThroughWindows( false );
00883         }
00884     else
00885         {
00886         if ( areModKeysDepressed( cutWalkThroughWindowsReverse ) )
00887             {
00888             if ( startKDEWalkThroughWindows() )
00889                 KDEWalkThroughWindows( false );
00890             }
00891         else
00892             {
00893             KDEOneStepThroughWindows( false );
00894             }
00895         }
00896     }
00897 
00898 void Workspace::slotWalkThroughDesktops()
00899     {
00900     if ( root != qt_xrootwin() )
00901         return;
00902     if( tab_grab || control_grab )
00903         return;
00904     if ( areModKeysDepressed( cutWalkThroughDesktops ) )
00905         {
00906         if ( startWalkThroughDesktops() )
00907             walkThroughDesktops( true );
00908         }
00909     else
00910         {
00911         oneStepThroughDesktops( true );
00912         }
00913     }
00914 
00915 void Workspace::slotWalkBackThroughDesktops()
00916     {
00917     if ( root != qt_xrootwin() )
00918         return;
00919     if( tab_grab || control_grab )
00920         return;
00921     if ( areModKeysDepressed( cutWalkThroughDesktopsReverse ) )
00922         {
00923         if ( startWalkThroughDesktops() )
00924             walkThroughDesktops( false );
00925         }
00926     else
00927         {
00928         oneStepThroughDesktops( false );
00929         }
00930     }
00931 
00932 void Workspace::slotWalkThroughDesktopList()
00933     {
00934     if ( root != qt_xrootwin() )
00935         return;
00936     if( tab_grab || control_grab )
00937         return;
00938     if ( areModKeysDepressed( cutWalkThroughDesktopList ) )
00939         {
00940         if ( startWalkThroughDesktopList() )
00941             walkThroughDesktops( true );
00942         }
00943     else
00944         {
00945         oneStepThroughDesktopList( true );
00946         }
00947     }
00948 
00949 void Workspace::slotWalkBackThroughDesktopList()
00950     {
00951     if ( root != qt_xrootwin() )
00952         return;
00953     if( tab_grab || control_grab )
00954         return;
00955     if ( areModKeysDepressed( cutWalkThroughDesktopListReverse ) )
00956         {
00957         if ( startWalkThroughDesktopList() )
00958             walkThroughDesktops( false );
00959         }
00960     else
00961         {
00962         oneStepThroughDesktopList( false );
00963         }
00964     }
00965 
00966 bool Workspace::startKDEWalkThroughWindows()
00967     {
00968     if( !establishTabBoxGrab())
00969         return false;
00970     tab_grab        = TRUE;
00971     keys->suspend( true );
00972     disable_shortcuts_keys->suspend( true );
00973     client_keys->suspend( true );
00974     tab_box->setMode( TabBox::WindowsMode );
00975     tab_box->reset();
00976     return TRUE;
00977     }
00978 
00979 bool Workspace::startWalkThroughDesktops( int mode )
00980     {
00981     if( !establishTabBoxGrab())
00982         return false;
00983     control_grab = TRUE;
00984     keys->suspend( true );
00985     disable_shortcuts_keys->suspend( true );
00986     client_keys->suspend( true );
00987     tab_box->setMode( (TabBox::Mode) mode );
00988     tab_box->reset();
00989     return TRUE;
00990     }
00991 
00992 bool Workspace::startWalkThroughDesktops()
00993     {
00994     return startWalkThroughDesktops( TabBox::DesktopMode );
00995     }
00996 
00997 bool Workspace::startWalkThroughDesktopList()
00998     {
00999     return startWalkThroughDesktops( TabBox::DesktopListMode );
01000     }
01001 
01002 void Workspace::KDEWalkThroughWindows( bool forward )
01003     {
01004     tab_box->nextPrev( forward );
01005     tab_box->delayedShow();
01006     }
01007 
01008 void Workspace::walkThroughDesktops( bool forward )
01009     {
01010     tab_box->nextPrev( forward );
01011     tab_box->delayedShow();
01012     }
01013 
01014 void Workspace::CDEWalkThroughWindows( bool forward )
01015     {
01016     Client* c = NULL;
01017 // this function find the first suitable client for unreasonable focus
01018 // policies - the topmost one, with some exceptions (can't be keepabove/below,
01019 // otherwise it gets stuck on them)
01020     Q_ASSERT( block_stacking_updates == 0 );
01021     for( ClientList::ConstIterator it = stacking_order.fromLast();
01022          it != stacking_order.end();
01023          --it )
01024         {
01025         if ( (*it)->isOnCurrentDesktop() && !(*it)->isSpecialWindow()
01026             && (*it)->isShown( false ) && (*it)->wantsTabFocus()
01027             && !(*it)->keepAbove() && !(*it)->keepBelow())
01028             {
01029             c = *it;
01030             break;
01031             }
01032         }
01033     Client* nc = c;
01034     bool options_traverse_all;
01035         {
01036         KConfigGroupSaver saver( KGlobal::config(), "TabBox" );
01037         options_traverse_all = KGlobal::config()->readBoolEntry("TraverseAll", false );
01038         }
01039 
01040     Client* firstClient = 0;
01041     do
01042         {
01043         nc = forward ? nextStaticClient(nc) : previousStaticClient(nc);
01044         if (!firstClient)
01045             {
01046             // When we see our first client for the second time,
01047             // it's time to stop.
01048             firstClient = nc;
01049             }
01050         else if (nc == firstClient)
01051             {
01052             // No candidates found.
01053             nc = 0;
01054             break;
01055             }
01056         } while (nc && nc != c &&
01057             (( !options_traverse_all && !nc->isOnDesktop(currentDesktop())) ||
01058              nc->isMinimized() || !nc->wantsTabFocus() || nc->keepAbove() || nc->keepBelow() ) );
01059     if (nc)
01060         {
01061         if (c && c != nc)
01062             lowerClient( c );
01063         if ( options->focusPolicyIsReasonable() )
01064             {
01065             activateClient( nc );
01066             if( nc->isShade() && options->shadeHover )
01067                 nc->setShade( ShadeActivated );
01068             }
01069         else
01070             {
01071             if( !nc->isOnDesktop( currentDesktop()))
01072                 setCurrentDesktop( nc->desktop());
01073             raiseClient( nc );
01074             }
01075         }
01076     }
01077 
01078 void Workspace::KDEOneStepThroughWindows( bool forward )
01079     {
01080     tab_box->setMode( TabBox::WindowsMode );
01081     tab_box->reset();
01082     tab_box->nextPrev( forward );
01083     if( Client* c = tab_box->currentClient() )
01084         {
01085         activateClient( c );
01086         if( c->isShade() && options->shadeHover )
01087             c->setShade( ShadeActivated );
01088         }
01089     }
01090 
01091 void Workspace::oneStepThroughDesktops( bool forward, int mode )
01092     {
01093     tab_box->setMode( (TabBox::Mode) mode );
01094     tab_box->reset();
01095     tab_box->nextPrev( forward );
01096     if ( tab_box->currentDesktop() != -1 )
01097         setCurrentDesktop( tab_box->currentDesktop() );
01098     }
01099 
01100 void Workspace::oneStepThroughDesktops( bool forward )
01101     {
01102     oneStepThroughDesktops( forward, TabBox::DesktopMode );
01103     }
01104 
01105 void Workspace::oneStepThroughDesktopList( bool forward )
01106     {
01107     oneStepThroughDesktops( forward, TabBox::DesktopListMode );
01108     }
01109 
01113 void Workspace::tabBoxKeyPress( const KKeyNative& keyX )
01114     {
01115     bool forward = false;
01116     bool backward = false;
01117 
01118     if (tab_grab)
01119         {
01120         forward = cutWalkThroughWindows.contains( keyX );
01121         backward = cutWalkThroughWindowsReverse.contains( keyX );
01122         if (forward || backward)
01123             {
01124             kdDebug(125) << "== " << cutWalkThroughWindows.toStringInternal()
01125                 << " or " << cutWalkThroughWindowsReverse.toStringInternal() << endl;
01126             KDEWalkThroughWindows( forward );
01127             }
01128         }
01129     else if (control_grab)
01130         {
01131         forward = cutWalkThroughDesktops.contains( keyX ) ||
01132                   cutWalkThroughDesktopList.contains( keyX );
01133         backward = cutWalkThroughDesktopsReverse.contains( keyX ) ||
01134                    cutWalkThroughDesktopListReverse.contains( keyX );
01135         if (forward || backward)
01136             walkThroughDesktops(forward);
01137         }
01138 
01139     if (control_grab || tab_grab)
01140         {
01141         uint keyQt = keyX.keyCodeQt();
01142         if ( ((keyQt & 0xffff) == Qt::Key_Escape)
01143             && !(forward || backward) )
01144             { // if Escape is part of the shortcut, don't cancel
01145             closeTabBox();
01146             }
01147         }
01148     }
01149 
01150 void Workspace::closeTabBox()
01151     {
01152     removeTabBoxGrab();
01153     tab_box->hide();
01154     keys->suspend( false );
01155     disable_shortcuts_keys->suspend( false );
01156     client_keys->suspend( false );
01157     tab_grab = FALSE;
01158     control_grab = FALSE;
01159     }
01160 
01164 void Workspace::tabBoxKeyRelease( const XKeyEvent& ev )
01165     {
01166     unsigned int mk = ev.state &
01167         (KKeyNative::modX(KKey::SHIFT) |
01168          KKeyNative::modX(KKey::CTRL) |
01169          KKeyNative::modX(KKey::ALT) |
01170          KKeyNative::modX(KKey::WIN));
01171     // ev.state is state before the key release, so just checking mk being 0 isn't enough
01172     // using XQueryPointer() also doesn't seem to work well, so the check that all
01173     // modifiers are released: only one modifier is active and the currently released
01174     // key is this modifier - if yes, release the grab
01175     int mod_index = -1;
01176     for( int i = ShiftMapIndex;
01177          i <= Mod5MapIndex;
01178          ++i )
01179         if(( mk & ( 1 << i )) != 0 )
01180         {
01181         if( mod_index >= 0 )
01182             return;
01183         mod_index = i;
01184         }
01185     bool release = false;
01186     if( mod_index == -1 )
01187         release = true;
01188     else
01189         {
01190         XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay());
01191         for (int i=0; i<xmk->max_keypermod; i++)
01192             if (xmk->modifiermap[xmk->max_keypermod * mod_index + i]
01193                 == ev.keycode)
01194                 release = true;
01195         XFreeModifiermap(xmk);
01196         }
01197     if( !release )
01198          return;
01199     if (tab_grab)
01200         {
01201         removeTabBoxGrab();
01202         tab_box->hide();
01203         keys->suspend( false );
01204         disable_shortcuts_keys->suspend( false );
01205         client_keys->suspend( false );
01206         tab_grab = false;
01207         if( Client* c = tab_box->currentClient())
01208             {
01209             activateClient( c );
01210             if( c->isShade() && options->shadeHover )
01211                 c->setShade( ShadeActivated );
01212             }
01213         }
01214     if (control_grab)
01215         {
01216         removeTabBoxGrab();
01217         tab_box->hide();
01218         keys->suspend( false );
01219         disable_shortcuts_keys->suspend( false );
01220         client_keys->suspend( false );
01221         control_grab = False;
01222         if ( tab_box->currentDesktop() != -1 )
01223             {
01224             setCurrentDesktop( tab_box->currentDesktop() );
01225             }
01226         }
01227     }
01228 
01229 
01230 int Workspace::nextDesktopFocusChain( int iDesktop ) const
01231     {
01232     int i = desktop_focus_chain.find( iDesktop );
01233     if( i >= 0 && i+1 < (int)desktop_focus_chain.size() )
01234             return desktop_focus_chain[i+1];
01235     else if( desktop_focus_chain.size() > 0 )
01236             return desktop_focus_chain[ 0 ];
01237     else
01238             return 1;
01239     }
01240 
01241 int Workspace::previousDesktopFocusChain( int iDesktop ) const
01242     {
01243     int i = desktop_focus_chain.find( iDesktop );
01244     if( i-1 >= 0 )
01245             return desktop_focus_chain[i-1];
01246     else if( desktop_focus_chain.size() > 0 )
01247             return desktop_focus_chain[desktop_focus_chain.size()-1];
01248     else
01249             return numberOfDesktops();
01250     }
01251 
01256 Client* Workspace::nextFocusChainClient( Client* c ) const
01257     {
01258     if ( global_focus_chain.isEmpty() )
01259         return 0;
01260     ClientList::ConstIterator it = global_focus_chain.find( c );
01261     if ( it == global_focus_chain.end() )
01262         return global_focus_chain.last();
01263     if ( it == global_focus_chain.begin() )
01264         return global_focus_chain.last();
01265     --it;
01266     return *it;
01267     }
01268 
01273 Client* Workspace::previousFocusChainClient( Client* c ) const
01274     {
01275     if ( global_focus_chain.isEmpty() )
01276         return 0;
01277     ClientList::ConstIterator it = global_focus_chain.find( c );
01278     if ( it == global_focus_chain.end() )
01279         return global_focus_chain.first();
01280     ++it;
01281     if ( it == global_focus_chain.end() )
01282         return global_focus_chain.first();
01283     return *it;
01284     }
01285 
01290 Client* Workspace::nextStaticClient( Client* c ) const
01291     {
01292     if ( !c || clients.isEmpty() )
01293         return 0;
01294     ClientList::ConstIterator it = clients.find( c );
01295     if ( it == clients.end() )
01296         return clients.first();
01297     ++it;
01298     if ( it == clients.end() )
01299         return clients.first();
01300     return *it;
01301     }
01306 Client* Workspace::previousStaticClient( Client* c ) const
01307     {
01308     if ( !c || clients.isEmpty() )
01309         return 0;
01310     ClientList::ConstIterator it = clients.find( c );
01311     if ( it == clients.end() )
01312         return clients.last();
01313     if ( it == clients.begin() )
01314         return clients.last();
01315     --it;
01316     return *it;
01317     }
01318 
01319 bool Workspace::establishTabBoxGrab()
01320     {
01321     if( XGrabKeyboard( qt_xdisplay(), root, FALSE,
01322         GrabModeAsync, GrabModeAsync, qt_x_time) != GrabSuccess )
01323         return false;
01324     // Don't try to establish a global mouse grab using XGrabPointer, as that would prevent
01325     // using Alt+Tab while DND (#44972). However force passive grabs on all windows
01326     // in order to catch MouseRelease events and close the tabbox (#67416).
01327     // All clients already have passive grabs in their wrapper windows, so check only
01328     // the active client, which may not have it.
01329     assert( !forced_global_mouse_grab );
01330     forced_global_mouse_grab = true;
01331     if( active_client != NULL )
01332         active_client->updateMouseGrab();
01333     return true;
01334     }
01335 
01336 void Workspace::removeTabBoxGrab()
01337     {
01338     XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01339     assert( forced_global_mouse_grab );
01340     forced_global_mouse_grab = false;
01341     if( active_client != NULL )
01342         active_client->updateMouseGrab();
01343     }
01344 
01345 } // namespace
01346 
01347 #include "tabbox.moc"

kwin

Skip menu "kwin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kwin

Skip menu "kwin"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for kwin by doxygen 1.5.6
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |