~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kwin/tabbox.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
Copyright (C) 2009 Martin Gräßlin <kde@martin-graesslin.com>
 
8
 
 
9
This program is free software; you can redistribute it and/or modify
 
10
it under the terms of the GNU General Public License as published by
 
11
the Free Software Foundation; either version 2 of the License, or
 
12
(at your option) any later version.
 
13
 
 
14
This program is distributed in the hope that it will be useful,
 
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
GNU General Public License for more details.
 
18
 
 
19
You should have received a copy of the GNU General Public License
 
20
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
*********************************************************************/
 
22
 
 
23
//#define QT_CLEAN_NAMESPACE
 
24
// own
 
25
#include "tabbox.h"
 
26
// tabbox
 
27
#include "tabbox/clientmodel.h"
 
28
#include "tabbox/desktopmodel.h"
 
29
#include "tabbox/tabboxconfig.h"
 
30
// kwin
 
31
#include "client.h"
 
32
#include "effects.h"
 
33
#include "workspace.h"
 
34
// Qt
 
35
#include <QAction>
 
36
#include <QX11Info>
 
37
// KDE
 
38
#include <KActionCollection>
 
39
#include <KConfig>
 
40
#include <KConfigGroup>
 
41
#include <KDebug>
 
42
#include <KLocale>
 
43
#include <kkeyserver.h>
 
44
// X11
 
45
#include <fixx11h.h>
 
46
#include <X11/keysym.h>
 
47
#include <X11/keysymdef.h>
 
48
#include "outline.h"
 
49
 
 
50
// specify externals before namespace
 
51
 
 
52
namespace KWin
 
53
{
 
54
 
 
55
extern QPixmap* kwin_get_menu_pix_hack();
 
56
 
 
57
namespace TabBox
 
58
{
 
59
 
 
60
TabBoxHandlerImpl::TabBoxHandlerImpl()
 
61
    : TabBoxHandler()
 
62
{
 
63
}
 
64
 
 
65
TabBoxHandlerImpl::~TabBoxHandlerImpl()
 
66
{
 
67
}
 
68
 
 
69
int TabBoxHandlerImpl::activeScreen() const
 
70
{
 
71
    return Workspace::self()->activeScreen();
 
72
}
 
73
 
 
74
int TabBoxHandlerImpl::currentDesktop() const
 
75
{
 
76
    return Workspace::self()->currentDesktop();
 
77
}
 
78
 
 
79
QString TabBoxHandlerImpl::desktopName(TabBoxClient* client) const
 
80
{
 
81
    if (TabBoxClientImpl* c = static_cast< TabBoxClientImpl* >(client)) {
 
82
        if (!c->client()->isOnAllDesktops())
 
83
            return Workspace::self()->desktopName(c->client()->desktop());
 
84
    }
 
85
    return Workspace::self()->desktopName(Workspace::self()->currentDesktop());
 
86
}
 
87
 
 
88
QString TabBoxHandlerImpl::desktopName(int desktop) const
 
89
{
 
90
    return Workspace::self()->desktopName(desktop);
 
91
}
 
92
 
 
93
TabBoxClient* TabBoxHandlerImpl::nextClientFocusChain(TabBoxClient* client) const
 
94
{
 
95
    if (TabBoxClientImpl* c = static_cast< TabBoxClientImpl* >(client)) {
 
96
        Client* next = Workspace::self()->nextClientFocusChain(c->client());
 
97
        if (next)
 
98
            return next->tabBoxClient();
 
99
    }
 
100
    return NULL;
 
101
}
 
102
 
 
103
int TabBoxHandlerImpl::nextDesktopFocusChain(int desktop) const
 
104
{
 
105
    return Workspace::self()->nextDesktopFocusChain(desktop);
 
106
}
 
107
 
 
108
int TabBoxHandlerImpl::numberOfDesktops() const
 
109
{
 
110
    return Workspace::self()->numberOfDesktops();
 
111
}
 
112
 
 
113
TabBoxClient* TabBoxHandlerImpl::activeClient() const
 
114
{
 
115
    if (Workspace::self()->activeClient())
 
116
        return Workspace::self()->activeClient()->tabBoxClient();
 
117
    else
 
118
        return NULL;
 
119
}
 
120
 
 
121
TabBoxClient* TabBoxHandlerImpl::clientToAddToList(TabBoxClient* client, int desktop, bool allDesktops) const
 
122
{
 
123
    Workspace* workspace = Workspace::self();
 
124
    Client* ret = NULL;
 
125
    Client* current = (static_cast< TabBoxClientImpl* >(client))->client();
 
126
    bool addClient = false;
 
127
    bool applications = (config().clientListMode() == TabBoxConfig::AllDesktopsApplicationList ||
 
128
                         config().clientListMode() == TabBoxConfig::CurrentDesktopApplicationList);
 
129
    if (allDesktops)
 
130
        addClient = true;
 
131
    else
 
132
        addClient = current->isOnDesktop(desktop);
 
133
    addClient = addClient && current->isOnCurrentActivity();
 
134
    addClient = addClient && current->wantsTabFocus() && !current->skipSwitcher();
 
135
    if (addClient) {
 
136
        // don't add windows that have modal dialogs
 
137
        Client* modal = current->findModal();
 
138
        if (modal == NULL || modal == current)
 
139
            ret = current;
 
140
        else if (!clientList().contains(modal->tabBoxClient()))
 
141
            ret = modal;
 
142
        else {
 
143
            // nothing
 
144
        }
 
145
        if (ret && applications) {
 
146
            // check if the list already contains an entry of this application
 
147
            foreach (TabBoxClient * tabBoxClient, clientList()) {
 
148
                if (TabBoxClientImpl* c = dynamic_cast< TabBoxClientImpl* >(tabBoxClient)) {
 
149
                    if (c->client()->resourceClass() == ret->resourceClass()) {
 
150
                        ret = NULL;
 
151
                        break;
 
152
                    }
 
153
                }
 
154
            }
 
155
        }
 
156
    }
 
157
    if (options->separateScreenFocus && options->xineramaEnabled) {
 
158
        if (current->screen() != workspace->activeScreen())
 
159
            ret = NULL;
 
160
    }
 
161
    if (ret)
 
162
        return ret->tabBoxClient();
 
163
    else
 
164
        return NULL;
 
165
}
 
166
 
 
167
TabBoxClientList TabBoxHandlerImpl::stackingOrder() const
 
168
{
 
169
    ClientList stacking = Workspace::self()->stackingOrder();
 
170
    TabBoxClientList ret;
 
171
    foreach (const Client * client, stacking) {
 
172
        ret.append(client->tabBoxClient());
 
173
    }
 
174
    return ret;
 
175
}
 
176
 
 
177
void TabBoxHandlerImpl::raiseClient(TabBoxClient* c) const
 
178
{
 
179
    Workspace::self()->raiseClient(static_cast<TabBoxClientImpl*>(c)->client());
 
180
}
 
181
 
 
182
void TabBoxHandlerImpl::restack(TabBoxClient *c, TabBoxClient *under)
 
183
{
 
184
    Workspace::self()->restack(static_cast<TabBoxClientImpl*>(c)->client(),
 
185
                               static_cast<TabBoxClientImpl*>(under)->client());
 
186
}
 
187
 
 
188
 
 
189
TabBoxClient* TabBoxHandlerImpl::desktopClient() const
 
190
{
 
191
    foreach (const Client * client, Workspace::self()->stackingOrder()) {
 
192
        if (client->isDesktop() && client->isOnCurrentDesktop() && client->screen() == Workspace::self()->activeScreen()) {
 
193
            return client->tabBoxClient();
 
194
        }
 
195
    }
 
196
    return NULL;
 
197
}
 
198
 
 
199
void TabBoxHandlerImpl::showOutline(const QRect &outline)
 
200
{
 
201
    Workspace::self()->outline()->show(outline);
 
202
}
 
203
 
 
204
void TabBoxHandlerImpl::hideOutline()
 
205
{
 
206
    Workspace::self()->outline()->hide();
 
207
}
 
208
 
 
209
QVector< Window > TabBoxHandlerImpl::outlineWindowIds() const
 
210
{
 
211
    return Workspace::self()->outline()->windowIds();
 
212
}
 
213
 
 
214
 
 
215
/*********************************************************
 
216
* TabBoxClientImpl
 
217
*********************************************************/
 
218
 
 
219
TabBoxClientImpl::TabBoxClientImpl()
 
220
    : TabBoxClient()
 
221
{
 
222
}
 
223
 
 
224
TabBoxClientImpl::~TabBoxClientImpl()
 
225
{
 
226
}
 
227
 
 
228
QString TabBoxClientImpl::caption() const
 
229
{
 
230
    if (m_client->isDesktop())
 
231
        return i18nc("Special entry in alt+tab list for minimizing all windows",
 
232
                     "Show Desktop");
 
233
    return m_client->caption();
 
234
}
 
235
 
 
236
QPixmap TabBoxClientImpl::icon(const QSize& size) const
 
237
{
 
238
    return m_client->icon(size);
 
239
}
 
240
 
 
241
WId TabBoxClientImpl::window() const
 
242
{
 
243
    return m_client->window();
 
244
}
 
245
 
 
246
bool TabBoxClientImpl::isMinimized() const
 
247
{
 
248
    return m_client->isMinimized();
 
249
}
 
250
 
 
251
int TabBoxClientImpl::x() const
 
252
{
 
253
    return m_client->x();
 
254
}
 
255
 
 
256
int TabBoxClientImpl::y() const
 
257
{
 
258
    return m_client->y();
 
259
}
 
260
 
 
261
int TabBoxClientImpl::width() const
 
262
{
 
263
    return m_client->width();
 
264
}
 
265
 
 
266
int TabBoxClientImpl::height() const
 
267
{
 
268
    return m_client->height();
 
269
}
 
270
 
 
271
 
 
272
/*********************************************************
 
273
* TabBox
 
274
*********************************************************/
 
275
TabBox::TabBox(Workspace *ws)
 
276
    : QObject()
 
277
    , wspace(ws)
 
278
    , display_refcount(0)
 
279
{
 
280
    m_isShown = false;
 
281
    m_defaultConfig = TabBoxConfig();
 
282
    m_defaultConfig.setTabBoxMode(TabBoxConfig::ClientTabBox);
 
283
    m_defaultConfig.setClientListMode(TabBoxConfig::CurrentDesktopClientList);
 
284
    m_defaultConfig.setClientSwitchingMode(TabBoxConfig::FocusChainSwitching);
 
285
    m_defaultConfig.setLayout(TabBoxConfig::VerticalLayout);
 
286
 
 
287
    m_alternativeConfig = TabBoxConfig();
 
288
    m_alternativeConfig.setTabBoxMode(TabBoxConfig::ClientTabBox);
 
289
    m_alternativeConfig.setClientListMode(TabBoxConfig::AllDesktopsClientList);
 
290
    m_alternativeConfig.setClientSwitchingMode(TabBoxConfig::FocusChainSwitching);
 
291
    m_alternativeConfig.setLayout(TabBoxConfig::VerticalLayout);
 
292
 
 
293
    m_desktopConfig = TabBoxConfig();
 
294
    m_desktopConfig.setTabBoxMode(TabBoxConfig::DesktopTabBox);
 
295
    m_desktopConfig.setShowTabBox(true);
 
296
    m_desktopConfig.setShowDesktop(false);
 
297
    m_desktopConfig.setDesktopSwitchingMode(TabBoxConfig::MostRecentlyUsedDesktopSwitching);
 
298
    m_desktopConfig.setLayout(TabBoxConfig::VerticalLayout);
 
299
 
 
300
    m_desktopListConfig = TabBoxConfig();
 
301
    m_desktopListConfig.setTabBoxMode(TabBoxConfig::DesktopTabBox);
 
302
    m_desktopListConfig.setShowTabBox(true);
 
303
    m_desktopListConfig.setShowDesktop(false);
 
304
    m_desktopListConfig.setDesktopSwitchingMode(TabBoxConfig::StaticDesktopSwitching);
 
305
    m_desktopListConfig.setLayout(TabBoxConfig::VerticalLayout);
 
306
    m_tabBox = new TabBoxHandlerImpl();
 
307
    m_tabBox->setConfig(m_defaultConfig);
 
308
 
 
309
 
 
310
    m_tabBoxMode = TabBoxDesktopMode; // init variables
 
311
    reconfigure();
 
312
    connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show()));
 
313
}
 
314
 
 
315
TabBox::~TabBox()
 
316
{
 
317
}
 
318
 
 
319
 
 
320
/*!
 
321
  Sets the current mode to \a mode, either TabBoxDesktopListMode or TabBoxWindowsMode
 
322
 
 
323
  \sa mode()
 
324
 */
 
325
void TabBox::setMode(TabBoxMode mode)
 
326
{
 
327
    m_tabBoxMode = mode;
 
328
    switch(mode) {
 
329
    case TabBoxWindowsMode:
 
330
        m_tabBox->setConfig(m_defaultConfig);
 
331
        break;
 
332
    case TabBoxWindowsAlternativeMode:
 
333
        m_tabBox->setConfig(m_alternativeConfig);
 
334
        break;
 
335
    case TabBoxDesktopMode:
 
336
        m_tabBox->setConfig(m_desktopConfig);
 
337
        break;
 
338
    case TabBoxDesktopListMode:
 
339
        m_tabBox->setConfig(m_desktopListConfig);
 
340
        break;
 
341
    }
 
342
}
 
343
 
 
344
/*!
 
345
  Resets the tab box to display the active client in TabBoxWindowsMode, or the
 
346
  current desktop in TabBoxDesktopListMode
 
347
 */
 
348
void TabBox::reset(bool partial_reset)
 
349
{
 
350
    switch(m_tabBox->config().tabBoxMode()) {
 
351
    case TabBoxConfig::ClientTabBox:
 
352
        m_tabBox->createModel(partial_reset);
 
353
        if (!partial_reset) {
 
354
            if (workspace()->activeClient())
 
355
                setCurrentClient(workspace()->activeClient());
 
356
            // it's possible that the active client is not part of the model
 
357
            // in that case the index is invalid
 
358
            if (!m_index.isValid())
 
359
                setCurrentIndex(m_tabBox->first());
 
360
        } else {
 
361
            if (!m_index.isValid() || !m_tabBox->client(m_index))
 
362
                setCurrentIndex(m_tabBox->first());
 
363
        }
 
364
        break;
 
365
    case TabBoxConfig::DesktopTabBox:
 
366
        m_tabBox->createModel();
 
367
 
 
368
        if (!partial_reset)
 
369
            setCurrentDesktop(workspace()->currentDesktop());
 
370
        break;
 
371
    }
 
372
 
 
373
    emit tabBoxUpdated();
 
374
}
 
375
 
 
376
/*!
 
377
  Shows the next or previous item, depending on \a next
 
378
 */
 
379
void TabBox::nextPrev(bool next)
 
380
{
 
381
    setCurrentIndex(m_tabBox->nextPrev(next), false);
 
382
    emit tabBoxUpdated();
 
383
}
 
384
 
 
385
 
 
386
/*!
 
387
  Returns the currently displayed client ( only works in TabBoxWindowsMode ).
 
388
  Returns 0 if no client is displayed.
 
389
 */
 
390
Client* TabBox::currentClient()
 
391
{
 
392
    if (TabBoxClientImpl* client = static_cast< TabBoxClientImpl* >(m_tabBox->client(m_index))) {
 
393
        if (!workspace()->hasClient(client->client()))
 
394
            return NULL;
 
395
        return client->client();
 
396
    } else
 
397
        return NULL;
 
398
}
 
399
 
 
400
/*!
 
401
  Returns the list of clients potentially displayed ( only works in
 
402
  TabBoxWindowsMode ).
 
403
  Returns an empty list if no clients are available.
 
404
 */
 
405
ClientList TabBox::currentClientList()
 
406
{
 
407
    TabBoxClientList list = m_tabBox->clientList();
 
408
    ClientList ret;
 
409
    foreach (const TabBoxClient * client, list) {
 
410
        if (const TabBoxClientImpl* c = static_cast< const TabBoxClientImpl* >(client))
 
411
            ret.append(c->client());
 
412
    }
 
413
    return ret;
 
414
}
 
415
 
 
416
 
 
417
/*!
 
418
  Returns the currently displayed virtual desktop ( only works in
 
419
  TabBoxDesktopListMode )
 
420
  Returns -1 if no desktop is displayed.
 
421
 */
 
422
int TabBox::currentDesktop()
 
423
{
 
424
    return m_tabBox->desktop(m_index);
 
425
}
 
426
 
 
427
 
 
428
/*!
 
429
  Returns the list of desktops potentially displayed ( only works in
 
430
  TabBoxDesktopListMode )
 
431
  Returns an empty list if no are available.
 
432
 */
 
433
QList< int > TabBox::currentDesktopList()
 
434
{
 
435
    return m_tabBox->desktopList();
 
436
}
 
437
 
 
438
 
 
439
/*!
 
440
  Change the currently selected client, and notify the effects.
 
441
 
 
442
  \sa setCurrentDesktop()
 
443
 */
 
444
void TabBox::setCurrentClient(Client* newClient)
 
445
{
 
446
    setCurrentIndex(m_tabBox->index(newClient->tabBoxClient()));
 
447
}
 
448
 
 
449
/*!
 
450
  Change the currently selected desktop, and notify the effects.
 
451
 
 
452
  \sa setCurrentClient()
 
453
 */
 
454
void TabBox::setCurrentDesktop(int newDesktop)
 
455
{
 
456
    setCurrentIndex(m_tabBox->desktopIndex(newDesktop));
 
457
}
 
458
 
 
459
void TabBox::TabBox::setCurrentIndex(QModelIndex index, bool notifyEffects)
 
460
{
 
461
    if (!index.isValid())
 
462
        return;
 
463
    m_index = index;
 
464
    m_tabBox->setCurrentIndex(index);
 
465
    if (notifyEffects) {
 
466
        emit tabBoxUpdated();
 
467
    }
 
468
}
 
469
 
 
470
/*!
 
471
  Notify effects that the tab box is being shown, and only display the
 
472
  default tab box QFrame if no effect has referenced the tab box.
 
473
*/
 
474
void TabBox::show()
 
475
{
 
476
    emit tabBoxAdded(m_tabBoxMode);
 
477
    if (isDisplayed()) {
 
478
        m_isShown = false;
 
479
        return;
 
480
    }
 
481
    refDisplay();
 
482
    m_isShown = true;
 
483
    m_tabBox->show();
 
484
}
 
485
 
 
486
 
 
487
/*!
 
488
  Notify effects that the tab box is being hidden.
 
489
*/
 
490
void TabBox::hide(bool abort)
 
491
{
 
492
    delayedShowTimer.stop();
 
493
    if (m_isShown) {
 
494
        m_isShown = false;
 
495
        unrefDisplay();
 
496
    }
 
497
    emit tabBoxClosed();
 
498
    if (isDisplayed())
 
499
        kDebug(1212) << "Tab box was not properly closed by an effect";
 
500
    m_index = QModelIndex();
 
501
    m_tabBox->hide(abort);
 
502
    QApplication::syncX();
 
503
    XEvent otherEvent;
 
504
    while (XCheckTypedEvent(display(), EnterNotify, &otherEvent))
 
505
        ;
 
506
}
 
507
 
 
508
 
 
509
/*!
 
510
  Decrease the reference count.  Only when the reference count is 0 will
 
511
  the default tab box be shown.
 
512
 */
 
513
void TabBox::unrefDisplay()
 
514
{
 
515
    --display_refcount;
 
516
}
 
517
 
 
518
void TabBox::reconfigure()
 
519
{
 
520
    KSharedConfigPtr c(KGlobal::config());
 
521
    KConfigGroup config = c->group("TabBox");
 
522
 
 
523
    loadConfig(c->group("TabBox"), m_defaultConfig);
 
524
    loadConfig(c->group("TabBoxAlternative"), m_alternativeConfig);
 
525
 
 
526
    m_tabBox->setConfig(m_defaultConfig);
 
527
 
 
528
    m_delayShow = config.readEntry<bool>("ShowDelay", true);
 
529
    m_delayShowTime = config.readEntry<int>("DelayTime", 90);
 
530
}
 
531
 
 
532
void TabBox::loadConfig(const KConfigGroup& config, TabBoxConfig& tabBoxConfig)
 
533
{
 
534
    tabBoxConfig.setClientListMode(TabBoxConfig::ClientListMode(
 
535
                                       config.readEntry<int>("ListMode", TabBoxConfig::defaultListMode())));
 
536
    tabBoxConfig.setClientSwitchingMode(TabBoxConfig::ClientSwitchingMode(
 
537
                                            config.readEntry<int>("SwitchingMode", TabBoxConfig::defaultSwitchingMode())));
 
538
    tabBoxConfig.setLayout(TabBoxConfig::LayoutMode(
 
539
                               config.readEntry<int>("LayoutMode", TabBoxConfig::defaultLayoutMode())));
 
540
    tabBoxConfig.setSelectedItemViewPosition(TabBoxConfig::SelectedItemViewPosition(
 
541
                config.readEntry<int>("SelectedItem", TabBoxConfig::defaultSelectedItemViewPosition())));
 
542
 
 
543
    tabBoxConfig.setShowOutline(config.readEntry<bool>("ShowOutline",
 
544
                                TabBoxConfig::defaultShowOutline()));
 
545
    tabBoxConfig.setShowTabBox(config.readEntry<bool>("ShowTabBox",
 
546
                               TabBoxConfig::defaultShowTabBox()));
 
547
    tabBoxConfig.setHighlightWindows(config.readEntry<bool>("HighlightWindows",
 
548
                                     TabBoxConfig::defaultHighlightWindow()));
 
549
    tabBoxConfig.setShowDesktop(config.readEntry<bool>("ShowDesktop",
 
550
                                TabBoxConfig::defaultShowDesktop()));
 
551
 
 
552
    tabBoxConfig.setMinWidth(config.readEntry<int>("MinWidth",
 
553
                             TabBoxConfig::defaultMinWidth()));
 
554
    tabBoxConfig.setMinHeight(config.readEntry<int>("MinHeight",
 
555
                              TabBoxConfig::defaultMinHeight()));
 
556
 
 
557
    tabBoxConfig.setLayoutName(config.readEntry<QString>("LayoutName", TabBoxConfig::defaultLayoutName()));
 
558
    tabBoxConfig.setSelectedItemLayoutName(config.readEntry<QString>("SelectedLayoutName", TabBoxConfig::defaultSelectedItemLayoutName()));
 
559
}
 
560
 
 
561
/*!
 
562
  Rikkus: please document!   (Matthias)
 
563
 
 
564
  Ok, here's the docs :)
 
565
 
 
566
  You call delayedShow() instead of show() directly.
 
567
 
 
568
  If the 'ShowDelay' setting is false, show() is simply called.
 
569
 
 
570
  Otherwise, we start a timer for the delay given in the settings and only
 
571
  do a show() when it times out.
 
572
 
 
573
  This means that you can alt-tab between windows and you don't see the
 
574
  tab box immediately. Not only does this make alt-tabbing faster, it gives
 
575
  less 'flicker' to the eyes. You don't need to see the tab box if you're
 
576
  just quickly switching between 2 or 3 windows. It seems to work quite
 
577
  nicely.
 
578
 */
 
579
void TabBox::delayedShow()
 
580
{
 
581
    if (isDisplayed() || delayedShowTimer.isActive())
 
582
        // already called show - no need to call it twice
 
583
        return;
 
584
 
 
585
    if (!m_delayShowTime) {
 
586
        show();
 
587
        return;
 
588
    }
 
589
 
 
590
    delayedShowTimer.setSingleShot(true);
 
591
    delayedShowTimer.start(m_delayShowTime);
 
592
}
 
593
 
 
594
 
 
595
void TabBox::handleMouseEvent(XEvent* e)
 
596
{
 
597
    XAllowEvents(display(), AsyncPointer, xTime());
 
598
    if (!m_isShown && isDisplayed()) {
 
599
        // tabbox has been replaced, check effects
 
600
        if (effects && static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowEvent(e))
 
601
            return;
 
602
    }
 
603
    if (e->type != ButtonPress)
 
604
        return;
 
605
    QPoint pos(e->xbutton.x_root, e->xbutton.y_root);
 
606
 
 
607
    if ((!m_isShown && isDisplayed())
 
608
            || (!m_tabBox->containsPos(pos) &&
 
609
                (e->xbutton.button == Button1 || e->xbutton.button == Button2 || e->xbutton.button == Button3))) {
 
610
        workspace()->closeTabBox();  // click outside closes tab
 
611
        return;
 
612
    }
 
613
 
 
614
    QModelIndex index;
 
615
    if (e->xbutton.button == Button1 || e->xbutton.button == Button2 || e->xbutton.button == Button3) {
 
616
        index = m_tabBox->indexAt(pos);
 
617
        if (e->xbutton.button == Button2 && index.isValid()) {
 
618
            if (TabBoxClientImpl* client = static_cast< TabBoxClientImpl* >(m_tabBox->client(index))) {
 
619
                if (workspace()->hasClient(client->client())) {
 
620
                    client->client()->closeWindow();
 
621
                    return;
 
622
                }
 
623
            }
 
624
        }
 
625
    } else {
 
626
        // mouse wheel event
 
627
        index = m_tabBox->nextPrev(e->xbutton.button == Button5);
 
628
    }
 
629
 
 
630
    if (index.isValid())
 
631
        setCurrentIndex(index);
 
632
}
 
633
 
 
634
void TabBox::TabBox::grabbedKeyEvent(QKeyEvent* event)
 
635
{
 
636
    emit tabBoxKeyEvent(event);
 
637
    if (!m_isShown && isDisplayed()) {
 
638
        // tabbox has been replaced, check effects
 
639
        return;
 
640
    }
 
641
    setCurrentIndex(m_tabBox->grabbedKeyEvent(event));
 
642
}
 
643
 
 
644
} // namespace TabBox
 
645
 
 
646
 
 
647
//*******************************
 
648
// Workspace
 
649
//*******************************
 
650
 
 
651
 
 
652
/*!
 
653
  Handles alt-tab / control-tab
 
654
 */
 
655
 
 
656
static
 
657
bool areKeySymXsDepressed(bool bAll, const uint keySyms[], int nKeySyms)
 
658
{
 
659
    char keymap[32];
 
660
 
 
661
    kDebug(125) << "areKeySymXsDepressed: " << (bAll ? "all of " : "any of ") << nKeySyms;
 
662
 
 
663
    XQueryKeymap(display(), keymap);
 
664
 
 
665
    for (int iKeySym = 0; iKeySym < nKeySyms; iKeySym++) {
 
666
        uint keySymX = keySyms[ iKeySym ];
 
667
        uchar keyCodeX = XKeysymToKeycode(display(), keySymX);
 
668
        int i = keyCodeX / 8;
 
669
        char mask = 1 << (keyCodeX - (i * 8));
 
670
 
 
671
        // Abort if bad index value,
 
672
        if (i < 0 || i >= 32)
 
673
            return false;
 
674
 
 
675
        kDebug(125) << iKeySym << ": keySymX=0x" << QString::number(keySymX, 16)
 
676
                    << " i=" << i << " mask=0x" << QString::number(mask, 16)
 
677
                    << " keymap[i]=0x" << QString::number(keymap[i], 16) << endl;
 
678
 
 
679
        // If ALL keys passed need to be depressed,
 
680
        if (bAll) {
 
681
            if ((keymap[i] & mask) == 0)
 
682
                return false;
 
683
        } else {
 
684
            // If we are looking for ANY key press, and this key is depressed,
 
685
            if (keymap[i] & mask)
 
686
                return true;
 
687
        }
 
688
    }
 
689
 
 
690
    // If we were looking for ANY key press, then none was found, return false,
 
691
    // If we were looking for ALL key presses, then all were found, return true.
 
692
    return bAll;
 
693
}
 
694
 
 
695
static bool areModKeysDepressed(const QKeySequence& seq)
 
696
{
 
697
    uint rgKeySyms[10];
 
698
    int nKeySyms = 0;
 
699
    if (seq.isEmpty())
 
700
        return false;
 
701
    int mod = seq[seq.count()-1] & Qt::KeyboardModifierMask;
 
702
 
 
703
    if (mod & Qt::SHIFT) {
 
704
        rgKeySyms[nKeySyms++] = XK_Shift_L;
 
705
        rgKeySyms[nKeySyms++] = XK_Shift_R;
 
706
    }
 
707
    if (mod & Qt::CTRL) {
 
708
        rgKeySyms[nKeySyms++] = XK_Control_L;
 
709
        rgKeySyms[nKeySyms++] = XK_Control_R;
 
710
    }
 
711
    if (mod & Qt::ALT) {
 
712
        rgKeySyms[nKeySyms++] = XK_Alt_L;
 
713
        rgKeySyms[nKeySyms++] = XK_Alt_R;
 
714
    }
 
715
    if (mod & Qt::META) {
 
716
        // It would take some code to determine whether the Win key
 
717
        // is associated with Super or Meta, so check for both.
 
718
        // See bug #140023 for details.
 
719
        rgKeySyms[nKeySyms++] = XK_Super_L;
 
720
        rgKeySyms[nKeySyms++] = XK_Super_R;
 
721
        rgKeySyms[nKeySyms++] = XK_Meta_L;
 
722
        rgKeySyms[nKeySyms++] = XK_Meta_R;
 
723
    }
 
724
 
 
725
    return areKeySymXsDepressed(false, rgKeySyms, nKeySyms);
 
726
}
 
727
 
 
728
static bool areModKeysDepressed(const KShortcut& cut)
 
729
{
 
730
    if (areModKeysDepressed(cut.primary()) || areModKeysDepressed(cut.alternate()))
 
731
        return true;
 
732
 
 
733
    return false;
 
734
}
 
735
 
 
736
void Workspace::navigatingThroughWindows(bool forward, const KShortcut& shortcut, TabBoxMode mode)
 
737
{
 
738
    if (tab_grab || control_grab)
 
739
        return;
 
740
    if (!options->focusPolicyIsReasonable()) {
 
741
        //ungrabXKeyboard(); // need that because of accelerator raw mode
 
742
        // CDE style raise / lower
 
743
        CDEWalkThroughWindows(forward);
 
744
    } else {
 
745
        if (areModKeysDepressed(shortcut)) {
 
746
            if (startKDEWalkThroughWindows(mode))
 
747
                KDEWalkThroughWindows(forward);
 
748
        } else
 
749
            // if the shortcut has no modifiers, don't show the tabbox,
 
750
            // don't grab, but simply go to the next window
 
751
            KDEOneStepThroughWindows(forward, mode);
 
752
    }
 
753
}
 
754
 
 
755
void Workspace::slotWalkThroughWindows()
 
756
{
 
757
    navigatingThroughWindows(true, cutWalkThroughWindows, TabBoxWindowsMode);
 
758
}
 
759
 
 
760
void Workspace::slotWalkBackThroughWindows()
 
761
{
 
762
    navigatingThroughWindows(false, cutWalkThroughWindowsReverse, TabBoxWindowsMode);
 
763
}
 
764
 
 
765
void Workspace::slotWalkThroughWindowsAlternative()
 
766
{
 
767
    navigatingThroughWindows(true, cutWalkThroughWindowsAlternative, TabBoxWindowsAlternativeMode);
 
768
}
 
769
 
 
770
void Workspace::slotWalkBackThroughWindowsAlternative()
 
771
{
 
772
    navigatingThroughWindows(false, cutWalkThroughWindowsAlternativeReverse, TabBoxWindowsAlternativeMode);
 
773
}
 
774
 
 
775
void Workspace::slotWalkThroughDesktops()
 
776
{
 
777
    if (tab_grab || control_grab)
 
778
        return;
 
779
    if (areModKeysDepressed(cutWalkThroughDesktops)) {
 
780
        if (startWalkThroughDesktops())
 
781
            walkThroughDesktops(true);
 
782
    } else {
 
783
        oneStepThroughDesktops(true);
 
784
    }
 
785
}
 
786
 
 
787
void Workspace::slotWalkBackThroughDesktops()
 
788
{
 
789
    if (tab_grab || control_grab)
 
790
        return;
 
791
    if (areModKeysDepressed(cutWalkThroughDesktopsReverse)) {
 
792
        if (startWalkThroughDesktops())
 
793
            walkThroughDesktops(false);
 
794
    } else {
 
795
        oneStepThroughDesktops(false);
 
796
    }
 
797
}
 
798
 
 
799
void Workspace::slotWalkThroughDesktopList()
 
800
{
 
801
    if (tab_grab || control_grab)
 
802
        return;
 
803
    if (areModKeysDepressed(cutWalkThroughDesktopList)) {
 
804
        if (startWalkThroughDesktopList())
 
805
            walkThroughDesktops(true);
 
806
    } else {
 
807
        oneStepThroughDesktopList(true);
 
808
    }
 
809
}
 
810
 
 
811
void Workspace::slotWalkBackThroughDesktopList()
 
812
{
 
813
    if (tab_grab || control_grab)
 
814
        return;
 
815
    if (areModKeysDepressed(cutWalkThroughDesktopListReverse)) {
 
816
        if (startWalkThroughDesktopList())
 
817
            walkThroughDesktops(false);
 
818
    } else {
 
819
        oneStepThroughDesktopList(false);
 
820
    }
 
821
}
 
822
 
 
823
void Workspace::slotWalkThroughDesktopsKeyChanged(const QKeySequence& seq)
 
824
{
 
825
    cutWalkThroughDesktops = KShortcut(seq);
 
826
}
 
827
 
 
828
void Workspace::slotWalkBackThroughDesktopsKeyChanged(const QKeySequence& seq)
 
829
{
 
830
    cutWalkThroughDesktopsReverse = KShortcut(seq);
 
831
}
 
832
 
 
833
void Workspace::slotWalkThroughDesktopListKeyChanged(const QKeySequence& seq)
 
834
{
 
835
    cutWalkThroughDesktopList = KShortcut(seq);
 
836
}
 
837
 
 
838
void Workspace::slotWalkBackThroughDesktopListKeyChanged(const QKeySequence& seq)
 
839
{
 
840
    cutWalkThroughDesktopListReverse = KShortcut(seq);
 
841
}
 
842
 
 
843
void Workspace::slotWalkThroughWindowsKeyChanged(const QKeySequence& seq)
 
844
{
 
845
    cutWalkThroughWindows = KShortcut(seq);
 
846
}
 
847
 
 
848
void Workspace::slotWalkBackThroughWindowsKeyChanged(const QKeySequence& seq)
 
849
{
 
850
    cutWalkThroughWindowsReverse = KShortcut(seq);
 
851
}
 
852
 
 
853
void Workspace::slotMoveToTabLeftKeyChanged(const QKeySequence& seq)
 
854
{
 
855
    cutWalkThroughGroupWindows = KShortcut(seq);
 
856
}
 
857
void Workspace::slotMoveToTabRightKeyChanged(const QKeySequence& seq)
 
858
{
 
859
    cutWalkThroughGroupWindowsReverse = KShortcut(seq);
 
860
}
 
861
 
 
862
void Workspace::slotWalkThroughWindowsAlternativeKeyChanged(const QKeySequence& seq)
 
863
{
 
864
    cutWalkThroughWindowsAlternative = KShortcut(seq);
 
865
}
 
866
 
 
867
void Workspace::slotWalkBackThroughWindowsAlternativeKeyChanged(const QKeySequence& seq)
 
868
{
 
869
    cutWalkThroughWindowsAlternativeReverse = KShortcut(seq);
 
870
}
 
871
 
 
872
void Workspace::modalActionsSwitch(bool enabled)
 
873
{
 
874
    QList<KActionCollection*> collections;
 
875
    collections.append(keys);
 
876
    collections.append(disable_shortcuts_keys);
 
877
    collections.append(client_keys);
 
878
    foreach (KActionCollection * collection, collections)
 
879
    foreach (QAction * action, collection->actions())
 
880
    action->setEnabled(enabled);
 
881
}
 
882
 
 
883
bool Workspace::startKDEWalkThroughWindows(TabBoxMode mode)
 
884
{
 
885
    if (!establishTabBoxGrab())
 
886
        return false;
 
887
    tab_grab = true;
 
888
    modalActionsSwitch(false);
 
889
    tab_box->setMode(mode);
 
890
    tab_box->reset();
 
891
    return true;
 
892
}
 
893
 
 
894
bool Workspace::startWalkThroughDesktops(TabBoxMode mode)
 
895
{
 
896
    if (!establishTabBoxGrab())
 
897
        return false;
 
898
    control_grab = true;
 
899
    modalActionsSwitch(false);
 
900
    tab_box->setMode(mode);
 
901
    tab_box->reset();
 
902
    return true;
 
903
}
 
904
 
 
905
bool Workspace::startWalkThroughDesktops()
 
906
{
 
907
    return startWalkThroughDesktops(TabBoxDesktopMode);
 
908
}
 
909
 
 
910
bool Workspace::startWalkThroughDesktopList()
 
911
{
 
912
    return startWalkThroughDesktops(TabBoxDesktopListMode);
 
913
}
 
914
 
 
915
void Workspace::KDEWalkThroughWindows(bool forward)
 
916
{
 
917
    tab_box->nextPrev(forward);
 
918
    tab_box->delayedShow();
 
919
}
 
920
 
 
921
void Workspace::walkThroughDesktops(bool forward)
 
922
{
 
923
    tab_box->nextPrev(forward);
 
924
    tab_box->delayedShow();
 
925
}
 
926
 
 
927
void Workspace::CDEWalkThroughWindows(bool forward)
 
928
{
 
929
    Client* c = NULL;
 
930
// this function find the first suitable client for unreasonable focus
 
931
// policies - the topmost one, with some exceptions (can't be keepabove/below,
 
932
// otherwise it gets stuck on them)
 
933
    Q_ASSERT(block_stacking_updates == 0);
 
934
    for (int i = stacking_order.size() - 1;
 
935
            i >= 0 ;
 
936
            --i) {
 
937
        Client* it = stacking_order.at(i);
 
938
        if (it->isOnCurrentActivity() && it->isOnCurrentDesktop() && !it->isSpecialWindow()
 
939
                && it->isShown(false) && it->wantsTabFocus()
 
940
                && !it->keepAbove() && !it->keepBelow()) {
 
941
            c = it;
 
942
            break;
 
943
        }
 
944
    }
 
945
    Client* nc = c;
 
946
    bool options_traverse_all;
 
947
    {
 
948
        KConfigGroup group(KGlobal::config(), "TabBox");
 
949
        options_traverse_all = group.readEntry("TraverseAll", false);
 
950
    }
 
951
 
 
952
    Client* firstClient = 0;
 
953
    do {
 
954
        nc = forward ? nextClientStatic(nc) : previousClientStatic(nc);
 
955
        if (!firstClient) {
 
956
            // When we see our first client for the second time,
 
957
            // it's time to stop.
 
958
            firstClient = nc;
 
959
        } else if (nc == firstClient) {
 
960
            // No candidates found.
 
961
            nc = 0;
 
962
            break;
 
963
        }
 
964
    } while (nc && nc != c &&
 
965
            ((!options_traverse_all && !nc->isOnDesktop(currentDesktop())) ||
 
966
             nc->isMinimized() || !nc->wantsTabFocus() || nc->keepAbove() || nc->keepBelow() || !nc->isOnCurrentActivity()));
 
967
    if (nc) {
 
968
        if (c && c != nc)
 
969
            lowerClient(c);
 
970
        if (options->focusPolicyIsReasonable()) {
 
971
            activateClient(nc);
 
972
            if (nc->isShade() && options->shadeHover)
 
973
                nc->setShade(ShadeActivated);
 
974
        } else {
 
975
            if (!nc->isOnDesktop(currentDesktop()))
 
976
                setCurrentDesktop(nc->desktop());
 
977
            raiseClient(nc);
 
978
        }
 
979
    }
 
980
}
 
981
 
 
982
void Workspace::KDEOneStepThroughWindows(bool forward, TabBoxMode mode)
 
983
{
 
984
    tab_box->setMode(mode);
 
985
    tab_box->reset();
 
986
    tab_box->nextPrev(forward);
 
987
    if (Client* c = tab_box->currentClient()) {
 
988
        activateClient(c);
 
989
        if (c->isShade() && options->shadeHover)
 
990
            c->setShade(ShadeActivated);
 
991
    }
 
992
}
 
993
 
 
994
void Workspace::oneStepThroughDesktops(bool forward, TabBoxMode mode)
 
995
{
 
996
    tab_box->setMode(mode);
 
997
    tab_box->reset();
 
998
    tab_box->nextPrev(forward);
 
999
    if (tab_box->currentDesktop() != -1)
 
1000
        setCurrentDesktop(tab_box->currentDesktop());
 
1001
}
 
1002
 
 
1003
void Workspace::oneStepThroughDesktops(bool forward)
 
1004
{
 
1005
    oneStepThroughDesktops(forward, TabBoxDesktopMode);
 
1006
}
 
1007
 
 
1008
void Workspace::oneStepThroughDesktopList(bool forward)
 
1009
{
 
1010
    oneStepThroughDesktops(forward, TabBoxDesktopListMode);
 
1011
}
 
1012
 
 
1013
/*!
 
1014
  Handles holding alt-tab / control-tab
 
1015
 */
 
1016
void Workspace::tabBoxKeyPress(int keyQt)
 
1017
{
 
1018
    bool forward = false;
 
1019
    bool backward = false;
 
1020
 
 
1021
    if (tab_grab) {
 
1022
        KShortcut forwardShortcut;
 
1023
        KShortcut backwardShortcut;
 
1024
        if (tab_box->mode() == TabBoxWindowsMode) {
 
1025
            forwardShortcut = cutWalkThroughWindows;
 
1026
            backwardShortcut = cutWalkThroughWindowsReverse;
 
1027
        } else {
 
1028
            forwardShortcut = cutWalkThroughWindowsAlternative;
 
1029
            backwardShortcut = cutWalkThroughWindowsAlternativeReverse;
 
1030
        }
 
1031
        forward = forwardShortcut.contains(keyQt);
 
1032
        backward = backwardShortcut.contains(keyQt);
 
1033
        if (forward || backward) {
 
1034
            kDebug(125) << "== " << forwardShortcut.toString()
 
1035
                        << " or " << backwardShortcut.toString() << endl;
 
1036
            KDEWalkThroughWindows(forward);
 
1037
        }
 
1038
    } else if (control_grab) {
 
1039
        forward = cutWalkThroughDesktops.contains(keyQt) ||
 
1040
                  cutWalkThroughDesktopList.contains(keyQt);
 
1041
        backward = cutWalkThroughDesktopsReverse.contains(keyQt) ||
 
1042
                   cutWalkThroughDesktopListReverse.contains(keyQt);
 
1043
        if (forward || backward)
 
1044
            walkThroughDesktops(forward);
 
1045
    }
 
1046
 
 
1047
    if (control_grab || tab_grab) {
 
1048
        if (((keyQt & ~Qt::KeyboardModifierMask) == Qt::Key_Escape)
 
1049
                && !(forward || backward)) {
 
1050
            // if Escape is part of the shortcut, don't cancel
 
1051
            closeTabBox(true);
 
1052
        } else if (!(forward || backward)) {
 
1053
            QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, keyQt & ~Qt::KeyboardModifierMask, Qt::NoModifier);
 
1054
            tab_box->grabbedKeyEvent(event);
 
1055
        }
 
1056
    }
 
1057
}
 
1058
 
 
1059
void Workspace::refTabBox()
 
1060
{
 
1061
    if (tab_box)
 
1062
        tab_box->refDisplay();
 
1063
}
 
1064
 
 
1065
void Workspace::unrefTabBox()
 
1066
{
 
1067
    if (tab_box)
 
1068
        tab_box->unrefDisplay();
 
1069
}
 
1070
 
 
1071
void Workspace::closeTabBox(bool abort)
 
1072
{
 
1073
    removeTabBoxGrab();
 
1074
    tab_box->hide(abort);
 
1075
    modalActionsSwitch(true);
 
1076
    tab_grab = false;
 
1077
    control_grab = false;
 
1078
}
 
1079
 
 
1080
/*!
 
1081
  Handles alt-tab / control-tab releasing
 
1082
 */
 
1083
void Workspace::tabBoxKeyRelease(const XKeyEvent& ev)
 
1084
{
 
1085
    unsigned int mk = ev.state &
 
1086
                      (KKeyServer::modXShift() |
 
1087
                       KKeyServer::modXCtrl() |
 
1088
                       KKeyServer::modXAlt() |
 
1089
                       KKeyServer::modXMeta());
 
1090
    // ev.state is state before the key release, so just checking mk being 0 isn't enough
 
1091
    // using XQueryPointer() also doesn't seem to work well, so the check that all
 
1092
    // modifiers are released: only one modifier is active and the currently released
 
1093
    // key is this modifier - if yes, release the grab
 
1094
    int mod_index = -1;
 
1095
    for (int i = ShiftMapIndex;
 
1096
            i <= Mod5MapIndex;
 
1097
            ++i)
 
1098
        if ((mk & (1 << i)) != 0) {
 
1099
            if (mod_index >= 0)
 
1100
                return;
 
1101
            mod_index = i;
 
1102
        }
 
1103
    bool release = false;
 
1104
    if (mod_index == -1)
 
1105
        release = true;
 
1106
    else {
 
1107
        XModifierKeymap* xmk = XGetModifierMapping(display());
 
1108
        for (int i = 0; i < xmk->max_keypermod; i++)
 
1109
            if (xmk->modifiermap[xmk->max_keypermod * mod_index + i]
 
1110
                    == ev.keycode)
 
1111
                release = true;
 
1112
        XFreeModifiermap(xmk);
 
1113
    }
 
1114
    if (!release)
 
1115
        return;
 
1116
    if (tab_grab) {
 
1117
        bool old_control_grab = control_grab;
 
1118
        Client* c = tab_box->currentClient();
 
1119
        closeTabBox();
 
1120
        control_grab = old_control_grab;
 
1121
        if (c) {
 
1122
            activateClient(c);
 
1123
            if (c->isShade() && options->shadeHover)
 
1124
                c->setShade(ShadeActivated);
 
1125
            if (c->isDesktop())
 
1126
                setShowingDesktop(!showingDesktop());
 
1127
        }
 
1128
    }
 
1129
    if (control_grab) {
 
1130
        bool old_tab_grab = tab_grab;
 
1131
        int desktop = tab_box->currentDesktop();
 
1132
        closeTabBox();
 
1133
        tab_grab = old_tab_grab;
 
1134
        if (desktop != -1) {
 
1135
            setCurrentDesktop(desktop);
 
1136
        }
 
1137
    }
 
1138
}
 
1139
 
 
1140
 
 
1141
int Workspace::nextDesktopFocusChain(int iDesktop) const
 
1142
{
 
1143
    int i = desktop_focus_chain.indexOf(iDesktop);
 
1144
    if (i >= 0 && i + 1 < (int)desktop_focus_chain.size())
 
1145
        return desktop_focus_chain[i+1];
 
1146
    else if (desktop_focus_chain.size() > 0)
 
1147
        return desktop_focus_chain[ 0 ];
 
1148
    else
 
1149
        return 1;
 
1150
}
 
1151
 
 
1152
int Workspace::previousDesktopFocusChain(int iDesktop) const
 
1153
{
 
1154
    int i = desktop_focus_chain.indexOf(iDesktop);
 
1155
    if (i - 1 >= 0)
 
1156
        return desktop_focus_chain[i-1];
 
1157
    else if (desktop_focus_chain.size() > 0)
 
1158
        return desktop_focus_chain[desktop_focus_chain.size()-1];
 
1159
    else
 
1160
        return numberOfDesktops();
 
1161
}
 
1162
 
 
1163
int Workspace::nextDesktopStatic(int iDesktop) const
 
1164
{
 
1165
    int i = ++iDesktop;
 
1166
    if (i > numberOfDesktops())
 
1167
        i = 1;
 
1168
    return i;
 
1169
}
 
1170
 
 
1171
int Workspace::previousDesktopStatic(int iDesktop) const
 
1172
{
 
1173
    int i = --iDesktop;
 
1174
    if (i < 1)
 
1175
        i = numberOfDesktops();
 
1176
    return i;
 
1177
}
 
1178
 
 
1179
/*!
 
1180
  auxiliary functions to travers all clients according to the focus
 
1181
  order. Useful for kwms Alt-tab feature.
 
1182
*/
 
1183
Client* Workspace::nextClientFocusChain(Client* c) const
 
1184
{
 
1185
    if (global_focus_chain.isEmpty())
 
1186
        return 0;
 
1187
    int pos = global_focus_chain.indexOf(c);
 
1188
    if (pos == -1)
 
1189
        return global_focus_chain.last();
 
1190
    if (pos == 0)
 
1191
        return global_focus_chain.last();
 
1192
    pos--;
 
1193
    return global_focus_chain[ pos ];
 
1194
}
 
1195
 
 
1196
/*!
 
1197
  auxiliary functions to travers all clients according to the focus
 
1198
  order. Useful for kwms Alt-tab feature.
 
1199
*/
 
1200
Client* Workspace::previousClientFocusChain(Client* c) const
 
1201
{
 
1202
    if (global_focus_chain.isEmpty())
 
1203
        return 0;
 
1204
    int pos = global_focus_chain.indexOf(c);
 
1205
    if (pos == -1)
 
1206
        return global_focus_chain.first();
 
1207
    pos++;
 
1208
    if (pos == global_focus_chain.count())
 
1209
        return global_focus_chain.first();
 
1210
    return global_focus_chain[ pos ];
 
1211
}
 
1212
 
 
1213
/*!
 
1214
  auxiliary functions to travers all clients according to the static
 
1215
  order. Useful for the CDE-style Alt-tab feature.
 
1216
*/
 
1217
Client* Workspace::nextClientStatic(Client* c) const
 
1218
{
 
1219
    if (!c || clients.isEmpty())
 
1220
        return 0;
 
1221
    int pos = clients.indexOf(c);
 
1222
    if (pos == -1)
 
1223
        return clients.first();
 
1224
    ++pos;
 
1225
    if (pos == clients.count())
 
1226
        return clients.first();
 
1227
    return clients[ pos ];
 
1228
}
 
1229
/*!
 
1230
  auxiliary functions to travers all clients according to the static
 
1231
  order. Useful for the CDE-style Alt-tab feature.
 
1232
*/
 
1233
Client* Workspace::previousClientStatic(Client* c) const
 
1234
{
 
1235
    if (!c || clients.isEmpty())
 
1236
        return 0;
 
1237
    int pos = clients.indexOf(c);
 
1238
    if (pos == -1)
 
1239
        return clients.last();
 
1240
    if (pos == 0)
 
1241
        return clients.last();
 
1242
    --pos;
 
1243
    return clients[ pos ];
 
1244
}
 
1245
 
 
1246
Client* Workspace::currentTabBoxClient() const
 
1247
{
 
1248
    if (!tab_box)
 
1249
        return 0;
 
1250
    return tab_box->currentClient();
 
1251
}
 
1252
 
 
1253
ClientList Workspace::currentTabBoxClientList() const
 
1254
{
 
1255
    if (!tab_box)
 
1256
        return ClientList();
 
1257
    return tab_box->currentClientList();
 
1258
}
 
1259
 
 
1260
int Workspace::currentTabBoxDesktop() const
 
1261
{
 
1262
    if (!tab_box)
 
1263
        return -1;
 
1264
    return tab_box->currentDesktop();
 
1265
}
 
1266
 
 
1267
QList< int > Workspace::currentTabBoxDesktopList() const
 
1268
{
 
1269
    if (!tab_box)
 
1270
        return QList< int >();
 
1271
    return tab_box->currentDesktopList();
 
1272
}
 
1273
 
 
1274
void Workspace::setTabBoxClient(Client* c)
 
1275
{
 
1276
    if (tab_box)
 
1277
        tab_box->setCurrentClient(c);
 
1278
}
 
1279
 
 
1280
void Workspace::setTabBoxDesktop(int iDesktop)
 
1281
{
 
1282
    if (tab_box)
 
1283
        tab_box->setCurrentDesktop(iDesktop);
 
1284
}
 
1285
 
 
1286
bool Workspace::establishTabBoxGrab()
 
1287
{
 
1288
    if (!grabXKeyboard())
 
1289
        return false;
 
1290
    // Don't try to establish a global mouse grab using XGrabPointer, as that would prevent
 
1291
    // using Alt+Tab while DND (#44972). However force passive grabs on all windows
 
1292
    // in order to catch MouseRelease events and close the tabbox (#67416).
 
1293
    // All clients already have passive grabs in their wrapper windows, so check only
 
1294
    // the active client, which may not have it.
 
1295
    assert(!forced_global_mouse_grab);
 
1296
    forced_global_mouse_grab = true;
 
1297
    if (active_client != NULL)
 
1298
        active_client->updateMouseGrab();
 
1299
    return true;
 
1300
}
 
1301
 
 
1302
void Workspace::removeTabBoxGrab()
 
1303
{
 
1304
    ungrabXKeyboard();
 
1305
    assert(forced_global_mouse_grab);
 
1306
    forced_global_mouse_grab = false;
 
1307
    if (active_client != NULL)
 
1308
        active_client->updateMouseGrab();
 
1309
}
 
1310
 
 
1311
} // namespace
 
1312
 
 
1313
#include "tabbox.moc"