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