• 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
5Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7
8You can Freely distribute this program under the GNU General Public
9License. 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 <tdeglobalaccel.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
37namespace KWinInternal
38{
39
40extern TQPixmap* twin_get_menu_pix_hack();
41
42TabBox::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
70TabBox::~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
84void TabBox::setMode( Mode mode )
85 {
86 m = mode;
87 }
88
93void TabBox::setAppsOnly( bool a )
94 {
95 appsOnly = a;
96 }
97
101void 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
177void 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
265void 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
324Client* 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
333void TabBox::setCurrentClient( Client* c )
334 {
335 if( current_client != c )
336 {
337 current_client = c;
338 updateOutline();
339 }
340 }
341
347int TabBox::currentDesktop()
348 {
349 if ( mode() == DesktopListMode || mode() == DesktopMode )
350 return desk;
351 else
352 return -1;
353 }
354
355
359void 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
373void 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
384void 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
570void 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
655void 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
667void TabBox::reconfigure()
668 {
669 TDEConfig * c(TDEGlobal::config());
670 c->setGroup("TabBox");
671 options_traverse_all = c->readBoolEntry("TraverseAll", false );
672 }
673
692void 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
709void 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
769static
770bool 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
812static 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
849static 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
861void 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
887void 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
912void Workspace::slotWalkThroughApps()
913 {
914 tab_box->setAppsOnly(true);
915 slotWalkThroughWindows();
916 }
917
918void Workspace::slotWalkBackThroughApps()
919 {
920 tab_box->setAppsOnly(true);
921 slotWalkBackThroughWindows();
922 }
923
924void 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
941void 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
958void 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
975void 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
992bool 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
1005bool 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
1018bool Workspace::startWalkThroughDesktops()
1019 {
1020 return startWalkThroughDesktops( TabBox::DesktopMode );
1021 }
1022
1023bool Workspace::startWalkThroughDesktopList()
1024 {
1025 return startWalkThroughDesktops( TabBox::DesktopListMode );
1026 }
1027
1028void Workspace::KDEWalkThroughWindows( bool forward )
1029 {
1030 tab_box->nextPrev( forward );
1031 tab_box->delayedShow();
1032 }
1033
1034void Workspace::walkThroughDesktops( bool forward )
1035 {
1036 tab_box->nextPrev( forward );
1037 tab_box->delayedShow();
1038 }
1039
1040void 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
1104void 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
1117void 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
1126void Workspace::oneStepThroughDesktops( bool forward )
1127 {
1128 oneStepThroughDesktops( forward, TabBox::DesktopMode );
1129 }
1130
1131void Workspace::oneStepThroughDesktopList( bool forward )
1132 {
1133 oneStepThroughDesktops( forward, TabBox::DesktopListMode );
1134 }
1135
1139void 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
1191void 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
1205void 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
1271int 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
1282int 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
1297Client* 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
1314Client* 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
1331Client* 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 }
1347Client* 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
1360bool 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
1377void 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.4
This website is maintained by Timothy Pearson.