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

kwin

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

kwin

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

kwin

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