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

twin

  • twin
tabbox.cpp
1 /*****************************************************************
2  KWin - the KDE window manager
3  This file is part of the KDE project.
4 
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7 
8 You can Freely distribute this program under the GNU General Public
9 License. See the file "COPYING" for the exact licensing terms.
10 ******************************************************************/
11 
12 //#define QT_CLEAN_NAMESPACE
13 #include "tabbox.h"
14 #include "workspace.h"
15 #include "client.h"
16 #include <tqpainter.h>
17 #include <tqlabel.h>
18 #include <tqdrawutil.h>
19 #include <tqstyle.h>
20 #include <tdeglobal.h>
21 #include <fixx11h.h>
22 #include <tdeconfig.h>
23 #include <tdelocale.h>
24 #include <tqapplication.h>
25 #include <tqdesktopwidget.h>
26 #include <kstringhandler.h>
27 #include <stdarg.h>
28 #include <kdebug.h>
29 #include <kglobalaccel.h>
30 #include <kkeynative.h>
31 #include <tdeglobalsettings.h>
32 #include <kiconeffect.h>
33 #include <X11/keysym.h>
34 #include <X11/keysymdef.h>
35 
36 // specify externals before namespace
37 
38 namespace KWinInternal
39 {
40 
41 extern TQPixmap* twin_get_menu_pix_hack();
42 
43 TabBox::TabBox( Workspace *ws, const char *name )
44  : TQFrame( 0, name, TQt::WNoAutoErase ), current_client( NULL ), wspace(ws)
45  {
46  setFrameStyle(TQFrame::StyledPanel | TQFrame::Plain);
47  setLineWidth(2);
48  setMargin(2);
49 
50  appsOnly = false;
51  showMiniIcon = false;
52 
53  no_tasks = i18n("*** No Windows ***");
54  m = DesktopMode; // init variables
55  reconfigure();
56  reset();
57  connect(&delayedShowTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(show()));
58 
59  XSetWindowAttributes attr;
60  attr.override_redirect = 1;
61  outline_left = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), 0, 0, 1, 1, 0,
62  CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
63  outline_right = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), 0, 0, 1, 1, 0,
64  CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
65  outline_top = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), 0, 0, 1, 1, 0,
66  CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
67  outline_bottom = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), 0, 0, 1, 1, 0,
68  CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr );
69  }
70 
71 TabBox::~TabBox()
72  {
73  XDestroyWindow( tqt_xdisplay(), outline_left );
74  XDestroyWindow( tqt_xdisplay(), outline_right );
75  XDestroyWindow( tqt_xdisplay(), outline_top );
76  XDestroyWindow( tqt_xdisplay(), outline_bottom );
77  }
78 
79 
85 void TabBox::setMode( Mode mode )
86  {
87  m = mode;
88  }
89 
94 void TabBox::setAppsOnly( bool a )
95  {
96  appsOnly = a;
97  }
98 
102 void TabBox::createClientList(ClientList &list, int desktop /*-1 = all*/, Client *c, bool chain)
103  {
104  ClientList::size_type idx = 0;
105  TQString startClass;
106  list.clear();
107 
108  Client* start = c;
109 
110  if( start )
111  startClass = start->resourceClass();
112 
113  if ( chain )
114  c = workspace()->nextFocusChainClient(c);
115  else
116  c = workspace()->stackingOrder().first();
117 
118  Client* stop = c;
119 
120  while ( c )
121  {
122  Client* add = NULL;
123  if ( ((desktop == -1) || c->isOnDesktop(desktop))
124  && c->wantsTabFocus() )
125  { // don't add windows that have modal dialogs
126  Client* modal = c->findModal();
127  if( modal == NULL || modal == c )
128  add = c;
129  else if( !list.contains( modal ))
130  add = modal;
131  else
132  {
133  // nothing
134  }
135  }
136  if(appsOnly && (TQString::compare( startClass, c->resourceClass()) != 0))
137  {
138  add = NULL;
139  }
140 
141  if( options->separateScreenFocus && options->xineramaEnabled )
142  {
143  if( c->screen() != workspace()->activeScreen())
144  add = NULL;
145  }
146 
147  if( add != NULL )
148  {
149  if ( start == add )
150  {
151  list.remove( add );
152  list.prepend( add );
153  }
154  else
155  list += add;
156  }
157 
158  if ( chain )
159  c = workspace()->nextFocusChainClient( c );
160  else
161  {
162  if ( idx >= (workspace()->stackingOrder().size()-1) )
163  c = 0;
164  else
165  c = workspace()->stackingOrder()[++idx];
166  }
167 
168  if ( c == stop )
169  break;
170  }
171  }
172 
173 
178 void TabBox::reset()
179  {
180  int w, h, cw = 0, wmax = 0;
181 
182  TQRect r = workspace()->screenGeometry( workspace()->activeScreen());
183 
184  // calculate height of 1 line
185  // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below
186  lineHeight = TQMAX(fontMetrics().height() + 2, 32 + 4);
187 
188  if ( mode() == WindowsMode )
189  {
190  setCurrentClient( workspace()->activeClient());
191 
192  // get all clients to show
193  createClientList(clients, options_traverse_all ? -1 : workspace()->currentDesktop(), current_client, true);
194 
195  // calculate maximum caption width
196  cw = fontMetrics().width(no_tasks)+20;
197  for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
198  {
199  cw = fontMetrics().width( (*it)->caption() );
200  if ( cw > wmax ) wmax = cw;
201  }
202 
203  // calculate height for the popup
204  if ( clients.count() == 0 ) // height for the "not tasks" text
205  {
206  TQFont f = font();
207  f.setBold( TRUE );
208  f.setPointSize( 14 );
209 
210  h = TQFontMetrics(f).height()*4;
211  }
212  else
213  {
214  showMiniIcon = false;
215  h = clients.count() * lineHeight;
216 
217  if ( h > (r.height()-(2*frameWidth())) ) // if too high, use mini icons
218  {
219  showMiniIcon = true;
220  // fontheight + 1 pixel above + 1 pixel below, or 16x16 icon + 1 pixel above + below
221  lineHeight = TQMAX(fontMetrics().height() + 2, 16 + 2);
222 
223  h = clients.count() * lineHeight;
224 
225  if ( h > (r.height()-(2*frameWidth())) ) // if still too high, remove some clients
226  {
227  // how many clients to remove
228  int howMany = (h - (r.height()-(2*frameWidth())))/lineHeight;
229  for (; howMany; howMany--)
230  clients.remove(clients.last());
231 
232  h = clients.count() * lineHeight;
233  }
234  }
235  }
236  }
237  else
238  { // DesktopListMode
239  showMiniIcon = false;
240  desk = workspace()->currentDesktop();
241 
242  for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
243  {
244  cw = fontMetrics().width( workspace()->desktopName(i) );
245  if ( cw > wmax ) wmax = cw;
246  }
247 
248  // calculate height for the popup (max. 16 desktops always fit in a 800x600 screen)
249  h = workspace()->numberOfDesktops() * lineHeight;
250  }
251 
252  // height, width for the popup
253  h += 2 * frameWidth();
254  w = 2*frameWidth() + 5*2 + ( showMiniIcon ? 16 : 32 ) + 8 + wmax; // 5*2=margins, ()=icon, 8=space between icon+text
255  w = kClamp( w, r.width()/3 , r.width() * 4 / 5 );
256 
257  setGeometry( (r.width()-w)/2 + r.x(),
258  (r.height()-h)/2+ r.y(),
259  w, h );
260  }
261 
262 
266 void TabBox::nextPrev( bool next)
267  {
268  if ( mode() == WindowsMode )
269  {
270  Client* firstClient = NULL;
271  Client* client = current_client;
272  do
273  {
274  if ( next )
275  client = workspace()->nextFocusChainClient(client);
276  else
277  client = workspace()->previousFocusChainClient(client);
278  if (!firstClient)
279  {
280  // When we see our first client for the second time,
281  // it's time to stop.
282  firstClient = client;
283  }
284  else if (client == firstClient)
285  {
286  // No candidates found.
287  client = 0;
288  break;
289  }
290  } while ( client && !clients.contains( client ));
291  setCurrentClient( client );
292  }
293  else if( mode() == DesktopMode )
294  {
295  if ( next )
296  desk = workspace()->nextDesktopFocusChain( desk );
297  else
298  desk = workspace()->previousDesktopFocusChain( desk );
299  }
300  else
301  { // DesktopListMode
302  if ( next )
303  {
304  desk++;
305  if ( desk > workspace()->numberOfDesktops() )
306  desk = 1;
307  }
308  else
309  {
310  desk--;
311  if ( desk < 1 )
312  desk = workspace()->numberOfDesktops();
313  }
314  }
315 
316  update();
317  }
318 
319 
320 
325 Client* TabBox::currentClient()
326  {
327  if ( mode() != WindowsMode )
328  return 0;
329  if (!workspace()->hasClient( current_client ))
330  return 0;
331  return current_client;
332  }
333 
334 void TabBox::setCurrentClient( Client* c )
335  {
336  if( current_client != c )
337  {
338  current_client = c;
339  updateOutline();
340  }
341  }
342 
348 int TabBox::currentDesktop()
349  {
350  if ( mode() == DesktopListMode || mode() == DesktopMode )
351  return desk;
352  else
353  return -1;
354  }
355 
356 
360 void TabBox::showEvent( TQShowEvent* )
361  {
362  updateOutline();
363  XRaiseWindow( tqt_xdisplay(), outline_left );
364  XRaiseWindow( tqt_xdisplay(), outline_right );
365  XRaiseWindow( tqt_xdisplay(), outline_top );
366  XRaiseWindow( tqt_xdisplay(), outline_bottom );
367  raise();
368  }
369 
370 
374 void TabBox::hideEvent( TQHideEvent* )
375  {
376  XUnmapWindow( tqt_xdisplay(), outline_left );
377  XUnmapWindow( tqt_xdisplay(), outline_right );
378  XUnmapWindow( tqt_xdisplay(), outline_top );
379  XUnmapWindow( tqt_xdisplay(), outline_bottom );
380  }
381 
385 void TabBox::drawContents( TQPainter * )
386  {
387  TQRect r(contentsRect());
388  TQPixmap pix(r.size()); // do double buffering to avoid flickers
389  pix.fill(this, 0, 0);
390 
391  TQPainter p;
392  p.begin(&pix, this);
393 
394  TQPixmap* menu_pix = twin_get_menu_pix_hack();
395 
396  int iconWidth = showMiniIcon ? 16 : 32;
397  int x = 0;
398  int y = 0;
399 
400  if ( mode () == WindowsMode )
401  {
402  if ( !currentClient() )
403  {
404  TQFont f = font();
405  f.setBold( TRUE );
406  f.setPointSize( 14 );
407 
408  p.setFont(f);
409  p.drawText( r, AlignCenter, no_tasks);
410  }
411  else
412  {
413  for (ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
414  {
415  if ( workspace()->hasClient( *it ) ) // safety
416  {
417  // draw highlight background
418  if ( (*it) == current_client )
419  p.fillRect(x, y, r.width(), lineHeight, colorGroup().highlight());
420 
421  // draw icon
422  TQPixmap icon;
423  if ( showMiniIcon )
424  {
425  if ( !(*it)->miniIcon().isNull() )
426  icon = (*it)->miniIcon();
427  }
428  else
429  if ( !(*it)->icon().isNull() )
430  icon = (*it)->icon();
431  else if ( menu_pix )
432  icon = *menu_pix;
433 
434  if( !icon.isNull())
435  {
436  if( (*it)->isMinimized())
437  TDEIconEffect::semiTransparent( icon );
438  p.drawPixmap( x+5, y + (lineHeight - iconWidth)/2, icon );
439  }
440 
441  // generate text to display
442  TQString s;
443 
444  if ( !(*it)->isOnDesktop(workspace()->currentDesktop()) )
445  s = workspace()->desktopName((*it)->desktop()) + ": ";
446 
447  if ( (*it)->isMinimized() )
448  s += TQString("(") + (*it)->caption() + ")";
449  else
450  s += (*it)->caption();
451 
452  s = KStringHandler::cPixelSqueeze(s, fontMetrics(), r.width() - 5 - iconWidth - 8);
453 
454  // draw text
455  if ( (*it) == current_client )
456  p.setPen(colorGroup().highlightedText());
457  else if( (*it)->isMinimized())
458  {
459  TQColor c1 = colorGroup().text();
460  TQColor c2 = colorGroup().background();
461  // from kicker's TaskContainer::blendColors()
462  int r1, g1, b1;
463  int r2, g2, b2;
464 
465  c1.rgb( &r1, &g1, &b1 );
466  c2.rgb( &r2, &g2, &b2 );
467 
468  r1 += (int) ( .5 * ( r2 - r1 ) );
469  g1 += (int) ( .5 * ( g2 - g1 ) );
470  b1 += (int) ( .5 * ( b2 - b1 ) );
471 
472  p.setPen(TQColor( r1, g1, b1 ));
473  }
474  else
475  p.setPen(colorGroup().text());
476 
477  p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
478  Qt::AlignLeft | Qt::AlignVCenter | TQt::SingleLine, s);
479 
480  y += lineHeight;
481  }
482  if ( y >= r.height() ) break;
483  }
484  }
485  }
486  else
487  { // DesktopMode || DesktopListMode
488  int iconHeight = iconWidth;
489 
490  // get widest desktop name/number
491  TQFont f(font());
492  f.setBold(true);
493  f.setPixelSize(iconHeight - 4); // pixel, not point because I need to know the pixels
494  TQFontMetrics fm(f);
495 
496  int wmax = 0;
497  for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
498  {
499  wmax = TQMAX(wmax, fontMetrics().width(workspace()->desktopName(i)));
500 
501  // calculate max width of desktop-number text
502  TQString num = TQString::number(i);
503  iconWidth = TQMAX(iconWidth - 4, fm.boundingRect(num).width()) + 4;
504  }
505 
506  // In DesktopMode, start at the current desktop
507  // In DesktopListMode, start at desktop #1
508  int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
509  for ( int i = 1; i <= workspace()->numberOfDesktops(); i++ )
510  {
511  // draw highlight background
512  if ( iDesktop == desk ) // current desktop
513  p.fillRect(x, y, r.width(), lineHeight, colorGroup().highlight());
514 
515  p.save();
516 
517  // draw "icon" (here: number of desktop)
518  p.fillRect(x+5, y+2, iconWidth, iconHeight, colorGroup().base());
519  p.setPen(colorGroup().text());
520  p.drawRect(x+5, y+2, iconWidth, iconHeight);
521 
522  // draw desktop-number
523  p.setFont(f);
524  TQString num = TQString::number(iDesktop);
525  p.drawText(x+5, y+2, iconWidth, iconHeight, Qt::AlignCenter, num);
526 
527  p.restore();
528 
529  // draw desktop name text
530  if ( iDesktop == desk )
531  p.setPen(colorGroup().highlightedText());
532  else
533  p.setPen(colorGroup().text());
534 
535  p.drawText(x+5 + iconWidth + 8, y, r.width() - 5 - iconWidth - 8, lineHeight,
536  Qt::AlignLeft | Qt::AlignVCenter | TQt::SingleLine,
537  workspace()->desktopName(iDesktop));
538 
539  // show mini icons from that desktop aligned to each other
540  int x1 = x + 5 + iconWidth + 8 + wmax + 5;
541 
542  ClientList list;
543  createClientList(list, iDesktop, 0, false);
544  // clients are in reversed stacking order
545  for (ClientList::ConstIterator it = list.fromLast(); it != list.end(); --it)
546  {
547  if ( !(*it)->miniIcon().isNull() )
548  {
549  if ( x1+18 >= x+r.width() ) // only show full icons
550  break;
551 
552  p.drawPixmap( x1, y + (lineHeight - 16)/2, (*it)->miniIcon() );
553  x1 += 18;
554  }
555  }
556 
557  // next desktop
558  y += lineHeight;
559  if ( y >= r.height() ) break;
560 
561  if( mode() == DesktopMode )
562  iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
563  else
564  iDesktop++;
565  }
566  }
567  p.end();
568  bitBlt(this, r.x(), r.y(), &pix);
569  }
570 
571 void TabBox::updateOutline()
572  {
573  Client* c = currentClient();
574  if( !options->tabboxOutline || c == NULL || this->isHidden() || !c->isShown( true ) || !c->isOnCurrentDesktop())
575  {
576  XUnmapWindow( tqt_xdisplay(), outline_left );
577  XUnmapWindow( tqt_xdisplay(), outline_right );
578  XUnmapWindow( tqt_xdisplay(), outline_top );
579  XUnmapWindow( tqt_xdisplay(), outline_bottom );
580  return;
581  }
582  // left/right parts are between top/bottom, they don't reach as far as the corners
583  XMoveResizeWindow( tqt_xdisplay(), outline_left, c->x(), c->y() + 5, 5, c->height() - 10 );
584  XMoveResizeWindow( tqt_xdisplay(), outline_right, c->x() + c->width() - 5, c->y() + 5, 5, c->height() - 10 );
585  XMoveResizeWindow( tqt_xdisplay(), outline_top, c->x(), c->y(), c->width(), 5 );
586  XMoveResizeWindow( tqt_xdisplay(), outline_bottom, c->x(), c->y() + c->height() - 5, c->width(), 5 );
587  {
588  TQPixmap pix( 5, c->height() - 10 );
589  TQPainter p( &pix );
590  p.setPen( white );
591  p.drawLine( 0, 0, 0, pix.height() - 1 );
592  p.drawLine( 4, 0, 4, pix.height() - 1 );
593  p.setPen( gray );
594  p.drawLine( 1, 0, 1, pix.height() - 1 );
595  p.drawLine( 3, 0, 3, pix.height() - 1 );
596  p.setPen( black );
597  p.drawLine( 2, 0, 2, pix.height() - 1 );
598  p.end();
599  XSetWindowBackgroundPixmap( tqt_xdisplay(), outline_left, pix.handle());
600  XSetWindowBackgroundPixmap( tqt_xdisplay(), outline_right, pix.handle());
601  }
602  {
603  TQPixmap pix( c->width(), 5 );
604  TQPainter p( &pix );
605  p.setPen( white );
606  p.drawLine( 0, 0, pix.width() - 1 - 0, 0 );
607  p.drawLine( 4, 4, pix.width() - 1 - 4, 4 );
608  p.drawLine( 0, 0, 0, 4 );
609  p.drawLine( pix.width() - 1 - 0, 0, pix.width() - 1 - 0, 4 );
610  p.setPen( gray );
611  p.drawLine( 1, 1, pix.width() - 1 - 1, 1 );
612  p.drawLine( 3, 3, pix.width() - 1 - 3, 3 );
613  p.drawLine( 1, 1, 1, 4 );
614  p.drawLine( 3, 3, 3, 4 );
615  p.drawLine( pix.width() - 1 - 1, 1, pix.width() - 1 - 1, 4 );
616  p.drawLine( pix.width() - 1 - 3, 3, pix.width() - 1 - 3, 4 );
617  p.setPen( black );
618  p.drawLine( 2, 2, pix.width() - 1 - 2, 2 );
619  p.drawLine( 2, 2, 2, 4 );
620  p.drawLine( pix.width() - 1 - 2, 2, pix.width() - 1 - 2, 4 );
621  p.end();
622  XSetWindowBackgroundPixmap( tqt_xdisplay(), outline_top, pix.handle());
623  }
624  {
625  TQPixmap pix( c->width(), 5 );
626  TQPainter p( &pix );
627  p.setPen( white );
628  p.drawLine( 4, 0, pix.width() - 1 - 4, 0 );
629  p.drawLine( 0, 4, pix.width() - 1 - 0, 4 );
630  p.drawLine( 0, 4, 0, 0 );
631  p.drawLine( pix.width() - 1 - 0, 4, pix.width() - 1 - 0, 0 );
632  p.setPen( gray );
633  p.drawLine( 3, 1, pix.width() - 1 - 3, 1 );
634  p.drawLine( 1, 3, pix.width() - 1 - 1, 3 );
635  p.drawLine( 3, 1, 3, 0 );
636  p.drawLine( 1, 3, 1, 0 );
637  p.drawLine( pix.width() - 1 - 3, 1, pix.width() - 1 - 3, 0 );
638  p.drawLine( pix.width() - 1 - 1, 3, pix.width() - 1 - 1, 0 );
639  p.setPen( black );
640  p.drawLine( 2, 2, pix.width() - 1 - 2, 2 );
641  p.drawLine( 2, 0, 2, 2 );
642  p.drawLine( pix.width() - 1 - 2, 0, pix.width() - 1 - 2, 2 );
643  p.end();
644  XSetWindowBackgroundPixmap( tqt_xdisplay(), outline_bottom, pix.handle());
645  }
646  XClearWindow( tqt_xdisplay(), outline_left );
647  XClearWindow( tqt_xdisplay(), outline_right );
648  XClearWindow( tqt_xdisplay(), outline_top );
649  XClearWindow( tqt_xdisplay(), outline_bottom );
650  XMapWindow( tqt_xdisplay(), outline_left );
651  XMapWindow( tqt_xdisplay(), outline_right );
652  XMapWindow( tqt_xdisplay(), outline_top );
653  XMapWindow( tqt_xdisplay(), outline_bottom );
654  }
655 
656 void TabBox::hide()
657  {
658  delayedShowTimer.stop();
659  TQWidget::hide();
660  TQApplication::syncX();
661  XEvent otherEvent;
662  while (XCheckTypedEvent (tqt_xdisplay(), EnterNotify, &otherEvent ) )
663  ;
664  appsOnly = false;
665  }
666 
667 
668 void TabBox::reconfigure()
669  {
670  TDEConfig * c(TDEGlobal::config());
671  c->setGroup("TabBox");
672  options_traverse_all = c->readBoolEntry("TraverseAll", false );
673  }
674 
693 void TabBox::delayedShow()
694  {
695  TDEConfig * c(TDEGlobal::config());
696  c->setGroup("TabBox");
697  bool delay = c->readBoolEntry("ShowDelay", true);
698 
699  if (!delay)
700  {
701  show();
702  return;
703  }
704 
705  int delayTime = c->readNumEntry("DelayTime", 90);
706  delayedShowTimer.start(delayTime, true);
707  }
708 
709 
710 void TabBox::handleMouseEvent( XEvent* e )
711  {
712  XAllowEvents( tqt_xdisplay(), AsyncPointer, GET_QT_X_TIME() );
713  if( e->type != ButtonPress )
714  return;
715  TQPoint pos( e->xbutton.x_root, e->xbutton.y_root );
716  if( !geometry().contains( pos ))
717  {
718  workspace()->closeTabBox(); // click outside closes tab
719  return;
720  }
721  pos.rx() -= x(); // pos is now inside tabbox
722  pos.ry() -= y();
723  int num = (pos.y()-frameWidth()) / lineHeight;
724 
725  if( mode() == WindowsMode )
726  {
727  for( ClientList::ConstIterator it = clients.begin();
728  it != clients.end();
729  ++it)
730  {
731  if( workspace()->hasClient( *it ) && (num == 0) ) // safety
732  {
733  setCurrentClient( *it );
734  break;
735  }
736  num--;
737  }
738  }
739  else
740  {
741  int iDesktop = (mode() == DesktopMode) ? workspace()->currentDesktop() : 1;
742  for( int i = 1;
743  i <= workspace()->numberOfDesktops();
744  ++i )
745  {
746  if( num == 0 )
747  {
748  desk = iDesktop;
749  break;
750  }
751  num--;
752  if( mode() == DesktopMode )
753  iDesktop = workspace()->nextDesktopFocusChain( iDesktop );
754  else
755  iDesktop++;
756  }
757  }
758  update();
759  }
760 
761 //*******************************
762 // Workspace
763 //*******************************
764 
765 
770 static
771 bool areKeySymXsDepressed( bool bAll, const uint keySyms[], int nKeySyms )
772  {
773  char keymap[32];
774 
775  kdDebug(125) << "areKeySymXsDepressed: " << (bAll ? "all of " : "any of ") << nKeySyms << endl;
776 
777  XQueryKeymap( tqt_xdisplay(), keymap );
778 
779  for( int iKeySym = 0; iKeySym < nKeySyms; iKeySym++ )
780  {
781  uint keySymX = keySyms[ iKeySym ];
782  uchar keyCodeX = XKeysymToKeycode( tqt_xdisplay(), keySymX );
783  int i = keyCodeX / 8;
784  char mask = 1 << (keyCodeX - (i * 8));
785 
786  kdDebug(125) << iKeySym << ": keySymX=0x" << TQString::number( keySymX, 16 )
787  << " i=" << i << " mask=0x" << TQString::number( mask, 16 )
788  << " keymap[i]=0x" << TQString::number( keymap[i], 16 ) << endl;
789 
790  // Abort if bad index value,
791  if( i < 0 || i >= 32 )
792  return false;
793 
794  // If ALL keys passed need to be depressed,
795  if( bAll )
796  {
797  if( (keymap[i] & mask) == 0 )
798  return false;
799  }
800  else
801  {
802  // If we are looking for ANY key press, and this key is depressed,
803  if( keymap[i] & mask )
804  return true;
805  }
806  }
807 
808  // If we were looking for ANY key press, then none was found, return false,
809  // If we were looking for ALL key presses, then all were found, return true.
810  return bAll;
811  }
812 
813 static bool areModKeysDepressed( const KKeySequence& seq )
814  {
815  uint rgKeySyms[10];
816  int nKeySyms = 0;
817  if( seq.isNull())
818  return false;
819  int mod = seq.key(seq.count()-1).modFlags();
820 
821  if ( mod & KKey::SHIFT )
822  {
823  rgKeySyms[nKeySyms++] = XK_Shift_L;
824  rgKeySyms[nKeySyms++] = XK_Shift_R;
825  }
826  if ( mod & KKey::CTRL )
827  {
828  rgKeySyms[nKeySyms++] = XK_Control_L;
829  rgKeySyms[nKeySyms++] = XK_Control_R;
830  }
831  if( mod & KKey::ALT )
832  {
833  rgKeySyms[nKeySyms++] = XK_Alt_L;
834  rgKeySyms[nKeySyms++] = XK_Alt_R;
835  }
836  if( mod & KKey::WIN )
837  {
838  // It would take some code to determine whether the Win key
839  // is associated with Super or Meta, so check for both.
840  // See bug #140023 for details.
841  rgKeySyms[nKeySyms++] = XK_Super_L;
842  rgKeySyms[nKeySyms++] = XK_Super_R;
843  rgKeySyms[nKeySyms++] = XK_Meta_L;
844  rgKeySyms[nKeySyms++] = XK_Meta_R;
845  }
846 
847  return areKeySymXsDepressed( false, rgKeySyms, nKeySyms );
848  }
849 
850 static bool areModKeysDepressed( const TDEShortcut& cut )
851  {
852  for( unsigned int i = 0;
853  i < cut.count();
854  ++i )
855  {
856  if( areModKeysDepressed( cut.seq( i )))
857  return true;
858  }
859  return false;
860  }
861 
862 void Workspace::slotWalkThroughWindows()
863  {
864  if ( root != tqt_xrootwin() )
865  return;
866  if ( tab_grab || control_grab )
867  return;
868  if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable())
869  {
870  //XUngrabKeyboard(tqt_xdisplay(), GET_QT_X_TIME()); // need that because of accelerator raw mode
871  // CDE style raise / lower
872  CDEWalkThroughWindows( true );
873  }
874  else
875  {
876  if ( areModKeysDepressed( cutWalkThroughWindows ) )
877  {
878  if ( startKDEWalkThroughWindows() )
879  KDEWalkThroughWindows( true );
880  }
881  else
882  // if the shortcut has no modifiers, don't show the tabbox,
883  // don't grab, but simply go to the next window
884  KDEOneStepThroughWindows( true );
885  }
886  }
887 
888 void Workspace::slotWalkBackThroughWindows()
889  {
890  if ( root != tqt_xrootwin() )
891  return;
892  if( tab_grab || control_grab )
893  return;
894  if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable())
895  {
896  // CDE style raise / lower
897  CDEWalkThroughWindows( false );
898  }
899  else
900  {
901  if ( areModKeysDepressed( cutWalkThroughWindowsReverse ) )
902  {
903  if ( startKDEWalkThroughWindows() )
904  KDEWalkThroughWindows( false );
905  }
906  else
907  {
908  KDEOneStepThroughWindows( false );
909  }
910  }
911  }
912 
913 void Workspace::slotWalkThroughApps()
914  {
915  tab_box->setAppsOnly(true);
916  slotWalkThroughWindows();
917  }
918 
919 void Workspace::slotWalkBackThroughApps()
920  {
921  tab_box->setAppsOnly(true);
922  slotWalkBackThroughWindows();
923  }
924 
925 void Workspace::slotWalkThroughDesktops()
926  {
927  if ( root != tqt_xrootwin() )
928  return;
929  if( tab_grab || control_grab )
930  return;
931  if ( areModKeysDepressed( cutWalkThroughDesktops ) )
932  {
933  if ( startWalkThroughDesktops() )
934  walkThroughDesktops( true );
935  }
936  else
937  {
938  oneStepThroughDesktops( true );
939  }
940  }
941 
942 void Workspace::slotWalkBackThroughDesktops()
943  {
944  if ( root != tqt_xrootwin() )
945  return;
946  if( tab_grab || control_grab )
947  return;
948  if ( areModKeysDepressed( cutWalkThroughDesktopsReverse ) )
949  {
950  if ( startWalkThroughDesktops() )
951  walkThroughDesktops( false );
952  }
953  else
954  {
955  oneStepThroughDesktops( false );
956  }
957  }
958 
959 void Workspace::slotWalkThroughDesktopList()
960  {
961  if ( root != tqt_xrootwin() )
962  return;
963  if( tab_grab || control_grab )
964  return;
965  if ( areModKeysDepressed( cutWalkThroughDesktopList ) )
966  {
967  if ( startWalkThroughDesktopList() )
968  walkThroughDesktops( true );
969  }
970  else
971  {
972  oneStepThroughDesktopList( true );
973  }
974  }
975 
976 void Workspace::slotWalkBackThroughDesktopList()
977  {
978  if ( root != tqt_xrootwin() )
979  return;
980  if( tab_grab || control_grab )
981  return;
982  if ( areModKeysDepressed( cutWalkThroughDesktopListReverse ) )
983  {
984  if ( startWalkThroughDesktopList() )
985  walkThroughDesktops( false );
986  }
987  else
988  {
989  oneStepThroughDesktopList( false );
990  }
991  }
992 
993 bool Workspace::startKDEWalkThroughWindows()
994  {
995  if( !establishTabBoxGrab())
996  return false;
997  tab_grab = TRUE;
998  keys->suspend( true );
999  disable_shortcuts_keys->suspend( true );
1000  client_keys->suspend( true );
1001  tab_box->setMode( TabBox::WindowsMode );
1002  tab_box->reset();
1003  return TRUE;
1004  }
1005 
1006 bool Workspace::startWalkThroughDesktops( int mode )
1007  {
1008  if( !establishTabBoxGrab())
1009  return false;
1010  control_grab = TRUE;
1011  keys->suspend( true );
1012  disable_shortcuts_keys->suspend( true );
1013  client_keys->suspend( true );
1014  tab_box->setMode( (TabBox::Mode) mode );
1015  tab_box->reset();
1016  return TRUE;
1017  }
1018 
1019 bool Workspace::startWalkThroughDesktops()
1020  {
1021  return startWalkThroughDesktops( TabBox::DesktopMode );
1022  }
1023 
1024 bool Workspace::startWalkThroughDesktopList()
1025  {
1026  return startWalkThroughDesktops( TabBox::DesktopListMode );
1027  }
1028 
1029 void Workspace::KDEWalkThroughWindows( bool forward )
1030  {
1031  tab_box->nextPrev( forward );
1032  tab_box->delayedShow();
1033  }
1034 
1035 void Workspace::walkThroughDesktops( bool forward )
1036  {
1037  tab_box->nextPrev( forward );
1038  tab_box->delayedShow();
1039  }
1040 
1041 void Workspace::CDEWalkThroughWindows( bool forward )
1042  {
1043  Client* c = NULL;
1044 // this function find the first suitable client for unreasonable focus
1045 // policies - the topmost one, with some exceptions (can't be keepabove/below,
1046 // otherwise it gets stuck on them)
1047  Q_ASSERT( block_stacking_updates == 0 );
1048  for( ClientList::ConstIterator it = stacking_order.fromLast();
1049  it != stacking_order.end();
1050  --it )
1051  {
1052  if ( (*it)->isOnCurrentDesktop() && !(*it)->isSpecialWindow()
1053  && (*it)->isShown( false ) && (*it)->wantsTabFocus()
1054  && !(*it)->keepAbove() && !(*it)->keepBelow())
1055  {
1056  c = *it;
1057  break;
1058  }
1059  }
1060  Client* nc = c;
1061  bool options_traverse_all;
1062  {
1063  TDEConfigGroupSaver saver( TDEGlobal::config(), "TabBox" );
1064  options_traverse_all = TDEGlobal::config()->readBoolEntry("TraverseAll", false );
1065  }
1066 
1067  Client* firstClient = 0;
1068  do
1069  {
1070  nc = forward ? nextStaticClient(nc) : previousStaticClient(nc);
1071  if (!firstClient)
1072  {
1073  // When we see our first client for the second time,
1074  // it's time to stop.
1075  firstClient = nc;
1076  }
1077  else if (nc == firstClient)
1078  {
1079  // No candidates found.
1080  nc = 0;
1081  break;
1082  }
1083  } while (nc && nc != c &&
1084  (( !options_traverse_all && !nc->isOnDesktop(currentDesktop())) ||
1085  nc->isMinimized() || !nc->wantsTabFocus() || nc->keepAbove() || nc->keepBelow() ) );
1086  if (nc)
1087  {
1088  if (c && c != nc)
1089  lowerClient( c );
1090  if ( options->focusPolicyIsReasonable() )
1091  {
1092  activateClient( nc );
1093  if( nc->isShade() && options->shadeHover )
1094  nc->setShade( ShadeActivated );
1095  }
1096  else
1097  {
1098  if( !nc->isOnDesktop( currentDesktop()))
1099  setCurrentDesktop( nc->desktop());
1100  raiseClient( nc );
1101  }
1102  }
1103  }
1104 
1105 void Workspace::KDEOneStepThroughWindows( bool forward )
1106  {
1107  tab_box->setMode( TabBox::WindowsMode );
1108  tab_box->reset();
1109  tab_box->nextPrev( forward );
1110  if( Client* c = tab_box->currentClient() )
1111  {
1112  activateClient( c );
1113  if( c->isShade() && options->shadeHover )
1114  c->setShade( ShadeActivated );
1115  }
1116  }
1117 
1118 void Workspace::oneStepThroughDesktops( bool forward, int mode )
1119  {
1120  tab_box->setMode( (TabBox::Mode) mode );
1121  tab_box->reset();
1122  tab_box->nextPrev( forward );
1123  if ( tab_box->currentDesktop() != -1 )
1124  setCurrentDesktop( tab_box->currentDesktop() );
1125  }
1126 
1127 void Workspace::oneStepThroughDesktops( bool forward )
1128  {
1129  oneStepThroughDesktops( forward, TabBox::DesktopMode );
1130  }
1131 
1132 void Workspace::oneStepThroughDesktopList( bool forward )
1133  {
1134  oneStepThroughDesktops( forward, TabBox::DesktopListMode );
1135  }
1136 
1140 void Workspace::tabBoxKeyPress( const KKeyNative& keyX )
1141  {
1142  bool forward = false;
1143  bool backward = false;
1144  bool forwardapps = false;
1145  bool backwardapps = false;
1146 
1147  if (tab_grab)
1148  {
1149  forward = cutWalkThroughWindows.contains( keyX );
1150  backward = cutWalkThroughWindowsReverse.contains( keyX );
1151 
1152  forwardapps = cutWalkThroughApps.contains( keyX );
1153  backwardapps = cutWalkThroughAppsReverse.contains( keyX );
1154 
1155  if ( (forward || backward) && (!tab_box->isAppsOnly()) )
1156  {
1157  kdDebug(125) << "== " << cutWalkThroughWindows.toStringInternal()
1158  << " or " << cutWalkThroughWindowsReverse.toStringInternal() << endl;
1159 
1160  KDEWalkThroughWindows( forward );
1161  }
1162 
1163  if ( (forwardapps || backwardapps) && (tab_box->isAppsOnly()) )
1164  {
1165  kdDebug(125) << "== " << cutWalkThroughWindows.toStringInternal()
1166  << " or " << cutWalkThroughWindowsReverse.toStringInternal() << endl;
1167  KDEWalkThroughWindows( forwardapps );
1168  }
1169  }
1170 
1171  else if (control_grab)
1172  {
1173  forward = cutWalkThroughDesktops.contains( keyX ) ||
1174  cutWalkThroughDesktopList.contains( keyX );
1175  backward = cutWalkThroughDesktopsReverse.contains( keyX ) ||
1176  cutWalkThroughDesktopListReverse.contains( keyX );
1177  if (forward || backward)
1178  walkThroughDesktops(forward);
1179  }
1180 
1181  if (control_grab || tab_grab)
1182  {
1183  uint keyQt = keyX.keyCodeQt();
1184  if ( ((keyQt & 0xffff) == Qt::Key_Escape)
1185  && !(forward || backward) )
1186  { // if Escape is part of the shortcut, don't cancel
1187  closeTabBox();
1188  }
1189  }
1190  }
1191 
1192 void Workspace::closeTabBox()
1193  {
1194  removeTabBoxGrab();
1195  tab_box->hide();
1196  keys->suspend( false );
1197  disable_shortcuts_keys->suspend( false );
1198  client_keys->suspend( false );
1199  tab_grab = FALSE;
1200  control_grab = FALSE;
1201  }
1202 
1206 void Workspace::tabBoxKeyRelease( const XKeyEvent& ev )
1207  {
1208  unsigned int mk = ev.state &
1209  (KKeyNative::modX(KKey::SHIFT) |
1210  KKeyNative::modX(KKey::CTRL) |
1211  KKeyNative::modX(KKey::ALT) |
1212  KKeyNative::modX(KKey::WIN));
1213  // ev.state is state before the key release, so just checking mk being 0 isn't enough
1214  // using XQueryPointer() also doesn't seem to work well, so the check that all
1215  // modifiers are released: only one modifier is active and the currently released
1216  // key is this modifier - if yes, release the grab
1217  int mod_index = -1;
1218  for( int i = ShiftMapIndex;
1219  i <= Mod5MapIndex;
1220  ++i )
1221  if(( mk & ( 1 << i )) != 0 )
1222  {
1223  if( mod_index >= 0 )
1224  return;
1225  mod_index = i;
1226  }
1227  bool release = false;
1228  if( mod_index == -1 )
1229  release = true;
1230  else
1231  {
1232  XModifierKeymap* xmk = XGetModifierMapping(tqt_xdisplay());
1233  for (int i=0; i<xmk->max_keypermod; i++)
1234  if (xmk->modifiermap[xmk->max_keypermod * mod_index + i]
1235  == ev.keycode)
1236  release = true;
1237  XFreeModifiermap(xmk);
1238  }
1239  if( !release )
1240  return;
1241  if (tab_grab)
1242  {
1243  removeTabBoxGrab();
1244  tab_box->hide();
1245  keys->suspend( false );
1246  disable_shortcuts_keys->suspend( false );
1247  client_keys->suspend( false );
1248  tab_grab = false;
1249  if( Client* c = tab_box->currentClient())
1250  {
1251  activateClient( c );
1252  if( c->isShade() && options->shadeHover )
1253  c->setShade( ShadeActivated );
1254  }
1255  }
1256  if (control_grab)
1257  {
1258  removeTabBoxGrab();
1259  tab_box->hide();
1260  keys->suspend( false );
1261  disable_shortcuts_keys->suspend( false );
1262  client_keys->suspend( false );
1263  control_grab = False;
1264  if ( tab_box->currentDesktop() != -1 )
1265  {
1266  setCurrentDesktop( tab_box->currentDesktop() );
1267  }
1268  }
1269  }
1270 
1271 
1272 int Workspace::nextDesktopFocusChain( int iDesktop ) const
1273  {
1274  int i = desktop_focus_chain.find( iDesktop );
1275  if( i >= 0 && i+1 < (int)desktop_focus_chain.size() )
1276  return desktop_focus_chain[i+1];
1277  else if( desktop_focus_chain.size() > 0 )
1278  return desktop_focus_chain[ 0 ];
1279  else
1280  return 1;
1281  }
1282 
1283 int Workspace::previousDesktopFocusChain( int iDesktop ) const
1284  {
1285  int i = desktop_focus_chain.find( iDesktop );
1286  if( i-1 >= 0 )
1287  return desktop_focus_chain[i-1];
1288  else if( desktop_focus_chain.size() > 0 )
1289  return desktop_focus_chain[desktop_focus_chain.size()-1];
1290  else
1291  return numberOfDesktops();
1292  }
1293 
1298 Client* Workspace::nextFocusChainClient( Client* c ) const
1299  {
1300  if ( global_focus_chain.isEmpty() )
1301  return 0;
1302  ClientList::ConstIterator it = global_focus_chain.find( c );
1303  if ( it == global_focus_chain.end() )
1304  return global_focus_chain.last();
1305  if ( it == global_focus_chain.begin() )
1306  return global_focus_chain.last();
1307  --it;
1308  return *it;
1309  }
1310 
1315 Client* Workspace::previousFocusChainClient( Client* c ) const
1316  {
1317  if ( global_focus_chain.isEmpty() )
1318  return 0;
1319  ClientList::ConstIterator it = global_focus_chain.find( c );
1320  if ( it == global_focus_chain.end() )
1321  return global_focus_chain.first();
1322  ++it;
1323  if ( it == global_focus_chain.end() )
1324  return global_focus_chain.first();
1325  return *it;
1326  }
1327 
1332 Client* Workspace::nextStaticClient( Client* c ) const
1333  {
1334  if ( !c || clients.isEmpty() )
1335  return 0;
1336  ClientList::ConstIterator it = clients.find( c );
1337  if ( it == clients.end() )
1338  return clients.first();
1339  ++it;
1340  if ( it == clients.end() )
1341  return clients.first();
1342  return *it;
1343  }
1348 Client* Workspace::previousStaticClient( Client* c ) const
1349  {
1350  if ( !c || clients.isEmpty() )
1351  return 0;
1352  ClientList::ConstIterator it = clients.find( c );
1353  if ( it == clients.end() )
1354  return clients.last();
1355  if ( it == clients.begin() )
1356  return clients.last();
1357  --it;
1358  return *it;
1359  }
1360 
1361 bool Workspace::establishTabBoxGrab()
1362  {
1363  if( XGrabKeyboard( tqt_xdisplay(), root, FALSE,
1364  GrabModeAsync, GrabModeAsync, GET_QT_X_TIME()) != GrabSuccess )
1365  return false;
1366  // Don't try to establish a global mouse grab using XGrabPointer, as that would prevent
1367  // using Alt+Tab while DND (#44972). However force passive grabs on all windows
1368  // in order to catch MouseRelease events and close the tabbox (#67416).
1369  // All clients already have passive grabs in their wrapper windows, so check only
1370  // the active client, which may not have it.
1371  assert( !forced_global_mouse_grab );
1372  forced_global_mouse_grab = true;
1373  if( active_client != NULL )
1374  active_client->updateMouseGrab();
1375  return true;
1376  }
1377 
1378 void Workspace::removeTabBoxGrab()
1379  {
1380  XUngrabKeyboard(tqt_xdisplay(), GET_QT_X_TIME());
1381  assert( forced_global_mouse_grab );
1382  forced_global_mouse_grab = false;
1383  if( active_client != NULL )
1384  active_client->updateMouseGrab();
1385  }
1386 
1387 } // namespace
1388 
1389 #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.8.1.2
This website is maintained by Timothy Pearson.