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

twin

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

twin

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

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.