~mc-return/compiz/compiz.merge-src-screen.cpp-improvements

« back to all changes in this revision

Viewing changes to plugins/switcher/src/switcher.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 05:09:18 UTC
  • Revision ID: git-v1:163f6b6f3c3b7764987cbdf8e03cc355edeaa499
New generalized build system.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2005 Novell, Inc.
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software
 
5
 * and its documentation for any purpose is hereby granted without
 
6
 * fee, provided that the above copyright notice appear in all copies
 
7
 * and that both that copyright notice and this permission notice
 
8
 * appear in supporting documentation, and that the name of
 
9
 * Novell, Inc. not be used in advertising or publicity pertaining to
 
10
 * distribution of the software without specific, written prior permission.
 
11
 * Novell, Inc. makes no representations about the suitability of this
 
12
 * software for any purpose. It is provided "as is" without express or
 
13
 * implied warranty.
 
14
 *
 
15
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 
17
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
18
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 
19
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 
21
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
22
 *
 
23
 * Author: David Reveman <davidr@novell.com>
 
24
 */
 
25
 
 
26
#include "switcher.h"
 
27
 
 
28
COMPIZ_PLUGIN_20081216 (switcher, SwitchPluginVTable)
 
29
 
 
30
static float _boxVertices[] =
 
31
{
 
32
    -(WIDTH >> 1), 0,
 
33
    -(WIDTH >> 1), BOX_WIDTH,
 
34
     (WIDTH >> 1), BOX_WIDTH,
 
35
     (WIDTH >> 1), 0,
 
36
 
 
37
    -(WIDTH >> 1),             BOX_WIDTH,
 
38
    -(WIDTH >> 1),             HEIGHT - BOX_WIDTH,
 
39
    -(WIDTH >> 1) + BOX_WIDTH, HEIGHT - BOX_WIDTH,
 
40
    -(WIDTH >> 1) + BOX_WIDTH, 0,
 
41
 
 
42
     (WIDTH >> 1) - BOX_WIDTH, BOX_WIDTH,
 
43
     (WIDTH >> 1) - BOX_WIDTH, HEIGHT - BOX_WIDTH,
 
44
     (WIDTH >> 1),             HEIGHT - BOX_WIDTH,
 
45
     (WIDTH >> 1),             0,
 
46
 
 
47
    -(WIDTH >> 1), HEIGHT - BOX_WIDTH,
 
48
    -(WIDTH >> 1), HEIGHT,
 
49
     (WIDTH >> 1), HEIGHT,
 
50
     (WIDTH >> 1), HEIGHT - BOX_WIDTH
 
51
};
 
52
 
 
53
 
 
54
void
 
55
SwitchScreen::setSelectedWindowHint ()
 
56
{
 
57
    XChangeProperty (screen->dpy (), popupWindow, selectWinAtom,
 
58
                     XA_WINDOW, 32, PropModeReplace,
 
59
                     (unsigned char *) &selectedWindow, 1);
 
60
}
 
61
 
 
62
bool
 
63
SwitchWindow::isSwitchWin ()
 
64
{
 
65
    if (!window->isViewable ())
 
66
    {
 
67
        if (sScreen->opt[SWITCH_OPTION_MINIMIZED].value ().b ())
 
68
        {
 
69
            if (!window->minimized () && !window->inShowDesktopMode () &&
 
70
                !window->shaded ())
 
71
                return false;
 
72
        }
 
73
        else
 
74
        {
 
75
            return false;
 
76
        }
 
77
    }
 
78
 
 
79
    if (!window->isFocussable ())
 
80
        return false;
 
81
 
 
82
    if (window->overrideRedirect ())
 
83
        return false;
 
84
 
 
85
    if (sScreen->selection == Panels)
 
86
    {
 
87
        if (!(window->type () &
 
88
              (CompWindowTypeDockMask | CompWindowTypeDesktopMask)))
 
89
            return false;
 
90
    }
 
91
    else
 
92
    {
 
93
        CompMatch *match;
 
94
 
 
95
        if (window->wmType () &
 
96
            (CompWindowTypeDockMask | CompWindowTypeDesktopMask))
 
97
            return false;
 
98
 
 
99
        if (window->state () & CompWindowStateSkipTaskbarMask)
 
100
            return false;
 
101
 
 
102
        match = &sScreen->opt[SWITCH_OPTION_WINDOW_MATCH].value ().match ();
 
103
        if (!match->evaluate (window))
 
104
            return false;
 
105
 
 
106
    }
 
107
 
 
108
    if (sScreen->selection == CurrentViewport)
 
109
    {
 
110
        if (!window->mapNum () || !window->isViewable ())
 
111
        {
 
112
            CompWindow::Geometry &sg = window->serverGeometry ();
 
113
            if (sg.x () + sg.width ()  <= 0    ||
 
114
                sg.y () + sg.height () <= 0    ||
 
115
                sg.x () >= screen->width () ||
 
116
                sg.y () >= screen->height ())
 
117
                return false;
 
118
        }
 
119
        else
 
120
        {
 
121
            if (!window->focus ())
 
122
                return false;
 
123
        }
 
124
    }
 
125
 
 
126
    return true;
 
127
}
 
128
 
 
129
void
 
130
SwitchScreen::activateEvent (bool activating)
 
131
{
 
132
    CompOption::Vector o (0);
 
133
 
 
134
    o.push_back (CompOption ("root", CompOption::TypeInt));
 
135
    o.push_back (CompOption ("active", CompOption::TypeBool));
 
136
 
 
137
    o[0].value ().set ((int) screen->root ());
 
138
    o[1].value ().set (activating);
 
139
 
 
140
    screen->handleCompizEvent ("switcher", "activate", o);
 
141
}
 
142
 
 
143
 
 
144
static bool
 
145
compareWindows (CompWindow *w1,
 
146
                CompWindow *w2)
 
147
{
 
148
 
 
149
    if (w1->mapNum () && !w2->mapNum ())
 
150
        return true;
 
151
 
 
152
    if (w2->mapNum () && !w1->mapNum ())
 
153
        return false;
 
154
 
 
155
    return w2->activeNum () < w1->activeNum ();
 
156
}
 
157
 
 
158
 
 
159
void
 
160
SwitchScreen::updateWindowList (int count)
 
161
{
 
162
    int x, y;
 
163
 
 
164
    if (count > 1)
 
165
    {
 
166
        count -= (count + 1) & 1;
 
167
        if (count < 3)
 
168
            count = 3;
 
169
    }
 
170
 
 
171
    pos  = ((count >> 1) - windows.size ()) * WIDTH;
 
172
    move = 0;
 
173
 
 
174
    selectedWindow = windows.front ()->id ();
 
175
 
 
176
    x = screen->currentOutputDev ().x1 () +
 
177
        screen->currentOutputDev ().width () / 2;
 
178
    y = screen->currentOutputDev ().y1 () +
 
179
        screen->currentOutputDev ().height () / 2;
 
180
 
 
181
    if (popupWindow)
 
182
    {
 
183
        CompWindow *w = screen->findWindow (popupWindow);
 
184
 
 
185
        if (w)
 
186
            w->resize (x - WINDOW_WIDTH (count) / 2,
 
187
                       y - WINDOW_HEIGHT / 2,
 
188
                       WINDOW_WIDTH (count),
 
189
                       WINDOW_HEIGHT);
 
190
        else
 
191
            XMoveResizeWindow (screen->dpy (), popupWindow,
 
192
                               x - WINDOW_WIDTH (count) / 2,
 
193
                               y - WINDOW_HEIGHT / 2,
 
194
                               WINDOW_WIDTH (count),
 
195
                               WINDOW_HEIGHT);
 
196
    }
 
197
}
 
198
 
 
199
void
 
200
SwitchScreen::createWindowList (int count)
 
201
{
 
202
 
 
203
    windows.clear ();
 
204
 
 
205
    foreach (CompWindow *w, screen->windows ())
 
206
    {
 
207
        if (SwitchWindow::get (w)->isSwitchWin ())
 
208
        {
 
209
            SWITCH_WINDOW (w);
 
210
            windows.push_back (w);
 
211
 
 
212
            sw->cWindow->damageRectSetEnabled (sw, true);
 
213
        }
 
214
    }
 
215
 
 
216
    windows.sort (compareWindows);
 
217
 
 
218
    if (windows.size () == 2)
 
219
    {
 
220
        windows.push_back (windows.front ());
 
221
        windows.push_back ((*++windows.begin ()));
 
222
    }
 
223
 
 
224
    updateWindowList (count);
 
225
}
 
226
 
 
227
void
 
228
SwitchScreen::switchToWindow (bool toNext)
 
229
{
 
230
    CompWindow               *w = NULL;
 
231
    CompWindowList::iterator it;
 
232
 
 
233
    if (!grabIndex)
 
234
        return;
 
235
 
 
236
    for (it = windows.begin (); it != windows.end (); it++)
 
237
    {
 
238
        if ((*it)->id () == selectedWindow)
 
239
            break;
 
240
    }
 
241
 
 
242
    if (it == windows.end ())
 
243
        return;
 
244
 
 
245
    if (toNext)
 
246
    {
 
247
        it++;
 
248
        if (it == windows.end ())
 
249
            w = windows.front ();
 
250
        else
 
251
            w = *it;
 
252
    }
 
253
    else
 
254
    {
 
255
        if (it == windows.begin ())
 
256
            w = windows.back ();
 
257
        else
 
258
            w = *--it;
 
259
    }
 
260
 
 
261
    if (w)
 
262
    {
 
263
        Window old = selectedWindow;
 
264
 
 
265
        if (selection == AllViewports &&
 
266
            opt[SWITCH_OPTION_AUTO_ROTATE].value ().b ())
 
267
        {
 
268
            XEvent xev;
 
269
            CompPoint pnt = w->defaultViewport ();
 
270
 
 
271
            xev.xclient.type = ClientMessage;
 
272
            xev.xclient.display = screen->dpy ();
 
273
            xev.xclient.format = 32;
 
274
 
 
275
            xev.xclient.message_type = Atoms::desktopViewport;
 
276
            xev.xclient.window = screen->root ();
 
277
 
 
278
            xev.xclient.data.l[0] = pnt.x () * screen->width ();
 
279
            xev.xclient.data.l[1] = pnt.y () * screen->height ();
 
280
            xev.xclient.data.l[2] = 0;
 
281
            xev.xclient.data.l[3] = 0;
 
282
            xev.xclient.data.l[4] = 0;
 
283
 
 
284
            XSendEvent (screen->dpy (), screen->root (), FALSE,
 
285
                        SubstructureRedirectMask | SubstructureNotifyMask,
 
286
                        &xev);
 
287
        }
 
288
 
 
289
        lastActiveNum  = w->activeNum ();
 
290
        selectedWindow = w->id ();
 
291
 
 
292
        if (!zoomedWindow)
 
293
            zoomedWindow = selectedWindow;
 
294
 
 
295
        if (old != w->id ())
 
296
        {
 
297
            if (toNext)
 
298
                move -= WIDTH;
 
299
            else
 
300
                move += WIDTH;
 
301
 
 
302
            moreAdjust = true;
 
303
        }
 
304
 
 
305
        if (popupWindow)
 
306
        {
 
307
            CompWindow *popup;
 
308
 
 
309
            popup = screen->findWindow (popupWindow);
 
310
            if (popup)
 
311
                CompositeWindow::get (popup)->addDamage ();
 
312
 
 
313
            setSelectedWindowHint ();
 
314
        }
 
315
 
 
316
        CompositeWindow::get (w)->addDamage ();
 
317
 
 
318
        if (old)
 
319
        {
 
320
            w = screen->findWindow (old);
 
321
            if (w)
 
322
                CompositeWindow::get (w)->addDamage ();
 
323
        }
 
324
    }
 
325
}
 
326
 
 
327
int
 
328
SwitchScreen::countWindows ()
 
329
{
 
330
    int count = 0;
 
331
 
 
332
    foreach (CompWindow *w, screen->windows ())
 
333
        if (SwitchWindow::get (w)->isSwitchWin ())
 
334
        {
 
335
            count++;
 
336
            if (count == 5)
 
337
                break;
 
338
        }
 
339
 
 
340
    if (count == 5 && screen->width () <= WINDOW_WIDTH (5))
 
341
        count = 3;
 
342
 
 
343
    return count;
 
344
}
 
345
 
 
346
static Visual *
 
347
findArgbVisual (Display *dpy, int scr)
 
348
{
 
349
    XVisualInfo         *xvi;
 
350
    XVisualInfo         temp;
 
351
    int                 nvi;
 
352
    int                 i;
 
353
    XRenderPictFormat   *format;
 
354
    Visual              *visual;
 
355
 
 
356
    temp.screen  = scr;
 
357
    temp.depth   = 32;
 
358
    temp.c_class = TrueColor;
 
359
 
 
360
    xvi = XGetVisualInfo (dpy,
 
361
                          VisualScreenMask |
 
362
                          VisualDepthMask  |
 
363
                          VisualClassMask,
 
364
                          &temp,
 
365
                          &nvi);
 
366
    if (!xvi)
 
367
        return 0;
 
368
 
 
369
    visual = 0;
 
370
    for (i = 0; i < nvi; i++)
 
371
    {
 
372
        format = XRenderFindVisualFormat (dpy, xvi[i].visual);
 
373
        if (format->type == PictTypeDirect && format->direct.alphaMask)
 
374
        {
 
375
            visual = xvi[i].visual;
 
376
            break;
 
377
        }
 
378
    }
 
379
 
 
380
    XFree (xvi);
 
381
 
 
382
    return visual;
 
383
}
 
384
 
 
385
 
 
386
void
 
387
SwitchScreen::initiate (SwitchWindowSelection selection,
 
388
                        bool                  showPopup)
 
389
{
 
390
    int count;
 
391
 
 
392
    if (screen->otherGrabExist ("switcher", "scale", "cube", 0))
 
393
        return;
 
394
 
 
395
    this->selection      = selection;
 
396
    selectedWindow = None;
 
397
 
 
398
    count = countWindows ();
 
399
    if (count < 1)
 
400
        return;
 
401
 
 
402
    if (!popupWindow && showPopup)
 
403
    {
 
404
        Display              *dpy = screen->dpy ();
 
405
        XSizeHints           xsh;
 
406
        XWMHints             xwmh;
 
407
        Atom                 state[4];
 
408
        int                  nState = 0;
 
409
        XSetWindowAttributes attr;
 
410
        Visual               *visual;
 
411
 
 
412
        visual = findArgbVisual (dpy, screen->screenNum ());
 
413
        if (!visual)
 
414
            return;
 
415
 
 
416
        if (count > 1)
 
417
        {
 
418
            count -= (count + 1) & 1;
 
419
            if (count < 3)
 
420
                count = 3;
 
421
        }
 
422
 
 
423
        xsh.flags       = PSize | PPosition | PWinGravity;
 
424
        xsh.width       = WINDOW_WIDTH (count);
 
425
        xsh.height      = WINDOW_HEIGHT;
 
426
        xsh.win_gravity = StaticGravity;
 
427
 
 
428
        xwmh.flags = InputHint;
 
429
        xwmh.input = 0;
 
430
 
 
431
        attr.background_pixel = 0;
 
432
        attr.border_pixel     = 0;
 
433
        attr.colormap         = XCreateColormap (dpy, screen->root (), visual,
 
434
                                                 AllocNone);
 
435
 
 
436
        popupWindow =
 
437
            XCreateWindow (dpy, screen->root (),
 
438
                           screen->width () / 2 - xsh.width / 2,
 
439
                           screen->height () / 2 - xsh.height / 2,
 
440
                           xsh.width, xsh.height, 0,
 
441
                           32, InputOutput, visual,
 
442
                           CWBackPixel | CWBorderPixel | CWColormap, &attr);
 
443
 
 
444
        XSetWMProperties (dpy, popupWindow, NULL, NULL,
 
445
                          programArgv, programArgc,
 
446
                          &xsh, &xwmh, NULL);
 
447
 
 
448
        state[nState++] = Atoms::winStateAbove;
 
449
        state[nState++] = Atoms::winStateSticky;
 
450
        state[nState++] = Atoms::winStateSkipTaskbar;
 
451
        state[nState++] = Atoms::winStateSkipPager;
 
452
 
 
453
        XChangeProperty (dpy, popupWindow,
 
454
                         Atoms::winState,
 
455
                         XA_ATOM, 32, PropModeReplace,
 
456
                         (unsigned char *) state, nState);
 
457
 
 
458
        XChangeProperty (dpy, popupWindow,
 
459
                         Atoms::winType,
 
460
                         XA_ATOM, 32, PropModeReplace,
 
461
                         (unsigned char *) &Atoms::winTypeUtil, 1);
 
462
 
 
463
        screen->setWindowProp (popupWindow, Atoms::winDesktop, 0xffffffff);
 
464
 
 
465
        setSelectedWindowHint ();
 
466
    }
 
467
 
 
468
    if (!grabIndex)
 
469
        grabIndex = screen->pushGrab (screen->invisibleCursor (), "switcher");
 
470
 
 
471
    if (grabIndex)
 
472
    {
 
473
        if (!switching)
 
474
        {
 
475
            lastActiveNum = screen->activeNum ();
 
476
 
 
477
            createWindowList (count);
 
478
 
 
479
            sTranslate = zoom;
 
480
 
 
481
            if (popupWindow && showPopup)
 
482
            {
 
483
                CompWindow *w;
 
484
 
 
485
                
 
486
                w = screen->findWindow (popupWindow);
 
487
                if (w && (w->state () & CompWindowStateHiddenMask))
 
488
                {
 
489
                    w->unminimize ();
 
490
                }
 
491
                else
 
492
                {
 
493
                    XMapWindow (screen->dpy (), popupWindow);
 
494
                }
 
495
                setSelectedWindowHint ();
 
496
            }
 
497
 
 
498
            activateEvent (true);
 
499
        }
 
500
 
 
501
        cScreen->damageScreen ();
 
502
 
 
503
        switching  = true;
 
504
        moreAdjust = true;
 
505
 
 
506
        screen->handleEventSetEnabled (this, true);
 
507
        cScreen->preparePaintSetEnabled (this, true);
 
508
        cScreen->donePaintSetEnabled (this, true);
 
509
        gScreen->glPaintOutputSetEnabled (this, true);
 
510
 
 
511
        foreach (CompWindow *w, screen->windows ())
 
512
        {
 
513
            SWITCH_WINDOW (w);
 
514
 
 
515
            sw->gWindow->glPaintSetEnabled (sw, true);
 
516
        }
 
517
    }
 
518
}
 
519
 
 
520
 
 
521
static bool
 
522
switchTerminate (CompAction         *action,
 
523
                 CompAction::State  state,
 
524
                 CompOption::Vector &options)
 
525
{
 
526
    CompScreen *s;
 
527
    Window     xid;
 
528
 
 
529
    xid = CompOption::getIntOptionNamed (options, "root");
 
530
 
 
531
    if (action)
 
532
        action->setState (action->state () & ~(CompAction::StateTermKey |
 
533
                                               CompAction::StateTermButton));
 
534
 
 
535
    if (xid && xid != screen->root ())
 
536
        return false;
 
537
 
 
538
    SWITCH_SCREEN (screen);
 
539
 
 
540
 
 
541
    if (ss->grabIndex)
 
542
    {
 
543
        CompWindow *w;
 
544
 
 
545
        if (ss->popupWindow)
 
546
        {
 
547
            w = screen->findWindow (ss->popupWindow);
 
548
            if (w && w->managed () && w->mapNum ())
 
549
            {
 
550
                w->minimize ();
 
551
            }
 
552
            else
 
553
            {
 
554
                XUnmapWindow (screen->dpy (), ss->popupWindow);
 
555
            }
 
556
        }
 
557
 
 
558
        ss->switching = false;
 
559
 
 
560
        if (state & CompAction::StateCancel)
 
561
        {
 
562
            ss->selectedWindow = None;
 
563
            ss->zoomedWindow   = None;
 
564
        }
 
565
 
 
566
        if (state && ss->selectedWindow)
 
567
        {
 
568
            w = screen->findWindow (ss->selectedWindow);
 
569
            if (w)
 
570
                screen->sendWindowActivationRequest (w->id ());
 
571
        }
 
572
 
 
573
        screen->removeGrab (ss->grabIndex, 0);
 
574
        ss->grabIndex = NULL;
 
575
 
 
576
        if (!ss->popupWindow)
 
577
            screen->handleEventSetEnabled (ss, false);
 
578
 
 
579
        if (!ss->zooming)
 
580
        {
 
581
            ss->selectedWindow = None;
 
582
            ss->zoomedWindow   = None;
 
583
 
 
584
            ss->activateEvent (false);
 
585
        }
 
586
        else
 
587
        {
 
588
            ss->moreAdjust = true;
 
589
        }
 
590
 
 
591
        ss->selectedWindow = None;
 
592
        ss->setSelectedWindowHint ();
 
593
 
 
594
        ss->lastActiveNum = 0;
 
595
 
 
596
        ss->cScreen->damageScreen ();
 
597
    }
 
598
 
 
599
 
 
600
    return false;
 
601
}
 
602
 
 
603
static bool
 
604
switchInitiateCommon (CompAction            *action,
 
605
                      CompAction::State     state,
 
606
                      CompOption::Vector    &options,
 
607
                      SwitchWindowSelection selection,
 
608
                      bool                  showPopup,
 
609
                      bool                  nextWindow)
 
610
{
 
611
    CompScreen *s;
 
612
    Window     xid;
 
613
 
 
614
    xid = CompOption::getIntOptionNamed (options, "root");
 
615
 
 
616
    if (xid != screen->root ())
 
617
        return false;
 
618
 
 
619
    SWITCH_SCREEN (screen);
 
620
 
 
621
    if (!ss->switching)
 
622
    {
 
623
        ss->initiate (selection, showPopup);
 
624
 
 
625
        if (state & CompAction::StateInitKey)
 
626
            action->setState (action->state () | CompAction::StateTermKey);
 
627
 
 
628
        if (state & CompAction::StateInitEdge)
 
629
            action->setState (action->state () | CompAction::StateTermEdge);
 
630
        else if (state & CompAction::StateInitButton)
 
631
            action->setState (action->state () | CompAction::StateTermButton);
 
632
    }
 
633
 
 
634
    ss->switchToWindow (nextWindow);
 
635
 
 
636
    return false;
 
637
}
 
638
 
 
639
#define SWITCHBIND(a,b,c) boost::bind (switchInitiateCommon, _1, _2, _3, a, b, c)
 
640
 
 
641
static const CompMetadata::OptionInfo switchOptionInfo[] = {
 
642
    { "next_button", "button", 0,
 
643
      SWITCHBIND (CurrentViewport, true, true), switchTerminate },
 
644
    { "next_key", "key", 0,
 
645
      SWITCHBIND (CurrentViewport, true, true), switchTerminate },
 
646
    { "prev_button", "button", 0,
 
647
      SWITCHBIND (CurrentViewport, true, false), switchTerminate },
 
648
    { "prev_key", "key", 0,
 
649
      SWITCHBIND (CurrentViewport, true, false), switchTerminate },
 
650
    { "next_all_button", "button", 0,
 
651
      SWITCHBIND (AllViewports, true, true), switchTerminate },
 
652
    { "next_all_key", "key", 0,
 
653
      SWITCHBIND (AllViewports, true, true), switchTerminate },
 
654
    { "prev_all_button", "button", 0,
 
655
      SWITCHBIND (AllViewports, true, false), switchTerminate },
 
656
    { "prev_all_key", "key", 0,
 
657
      SWITCHBIND (AllViewports, true, false), switchTerminate },
 
658
    { "next_no_popup_button", "button", 0,
 
659
      SWITCHBIND (CurrentViewport, false, true), switchTerminate },
 
660
    { "next_no_popup_key", "key", 0,
 
661
      SWITCHBIND (CurrentViewport, false, true), switchTerminate },
 
662
    { "prev_no_popup_button", "button", 0,
 
663
      SWITCHBIND (CurrentViewport, false, false), switchTerminate },
 
664
    { "prev_no_popup_key", "key", 0,
 
665
      SWITCHBIND (CurrentViewport, false, false), switchTerminate },
 
666
    { "next_panel_button", "button", 0,
 
667
      SWITCHBIND (Panels, false, true), switchTerminate },
 
668
    { "next_panel_key", "key", 0,
 
669
      SWITCHBIND (Panels, false, true), switchTerminate },
 
670
    { "prev_panel_button", "button", 0,
 
671
      SWITCHBIND (Panels, false, false), switchTerminate },
 
672
    { "prev_panel_key", "key", 0,
 
673
      SWITCHBIND (Panels, false, false), switchTerminate },
 
674
    { "speed", "float", "<min>0.1</min>", 0, 0 },
 
675
    { "timestep", "float", "<min>0.1</min>", 0, 0 },
 
676
    { "window_match", "match", 0, 0, 0 },
 
677
    { "mipmap", "bool", 0, 0, 0 },
 
678
    { "saturation", "int", "<min>0</min><max>100</max>", 0, 0 },
 
679
    { "brightness", "int", "<min>0</min><max>100</max>", 0, 0 },
 
680
    { "opacity", "int", "<min>0</min><max>100</max>", 0, 0 },
 
681
    { "bring_to_front", "bool", 0, 0, 0 },
 
682
    { "zoom", "float", "<min>0</min>", 0, 0 },
 
683
    { "icon", "bool", 0, 0, 0 },
 
684
    { "minimized", "bool", 0, 0, 0 },
 
685
    { "auto_rotate", "bool", 0, 0, 0 }
 
686
};
 
687
 
 
688
#undef SWITCHBIND
 
689
 
 
690
void
 
691
SwitchScreen::windowRemove (Window id)
 
692
{
 
693
    CompWindow *w;
 
694
 
 
695
    w = screen->findWindow (id);
 
696
    if (w)
 
697
    {
 
698
        bool   inList = false;
 
699
        int    count, j, i = 0;
 
700
        Window selected, old;
 
701
 
 
702
        SWITCH_WINDOW (w);
 
703
 
 
704
        if (!sw->isSwitchWin ())
 
705
            return;
 
706
 
 
707
        sw->cWindow->damageRectSetEnabled (sw, false);
 
708
        sw->gWindow->glPaintSetEnabled (sw, false);
 
709
 
 
710
        old = selected = selectedWindow;
 
711
 
 
712
        CompWindowList::iterator it = windows.begin ();
 
713
        while (it != windows.end ())
 
714
        {
 
715
            if (*it == w)
 
716
            {
 
717
                inList = true;
 
718
 
 
719
                if (w->id () == selected)
 
720
                {
 
721
                    it++;
 
722
                    if (it == windows.end ())
 
723
                        selected = windows.front ()->id ();
 
724
                    else 
 
725
                        selected = (*it)->id ();
 
726
                    it--;
 
727
                }
 
728
 
 
729
                CompWindowList::iterator del = it;
 
730
                it++;
 
731
                windows.erase (del);
 
732
            }
 
733
            else
 
734
                it++;
 
735
        }
 
736
 
 
737
        if (!inList)
 
738
            return;
 
739
 
 
740
        count = windows.size ();
 
741
 
 
742
        if (windows.size () == 2)
 
743
        {
 
744
            if (windows.front () == windows.back ())
 
745
            {
 
746
                windows.pop_back ();
 
747
                count = 1;
 
748
            }
 
749
            else
 
750
            {
 
751
                windows.push_back (windows.front ());
 
752
                windows.push_back ((*++windows.begin ()));
 
753
            }
 
754
        }
 
755
 
 
756
        if (windows.size () == 0)
 
757
        {
 
758
            CompOption::Vector o (0);
 
759
 
 
760
            o.push_back (CompOption ("root", CompOption::TypeInt));
 
761
 
 
762
            o[0].value ().set ((int) screen->root ());
 
763
 
 
764
            switchTerminate (NULL, 0, o);
 
765
            return;
 
766
        }
 
767
 
 
768
        if (!grabIndex)
 
769
            return;
 
770
 
 
771
        updateWindowList (count);
 
772
 
 
773
        foreach (CompWindow *w, windows)
 
774
        {
 
775
            selectedWindow = w->id ();
 
776
 
 
777
            if (selectedWindow == selected)
 
778
                break;
 
779
 
 
780
            pos -= WIDTH;
 
781
            if (pos < -windows.size () * WIDTH)
 
782
                pos += windows.size () * WIDTH;
 
783
        }
 
784
 
 
785
        if (popupWindow)
 
786
        {
 
787
            CompWindow *popup;
 
788
 
 
789
            popup = screen->findWindow (popupWindow);
 
790
            if (popup)
 
791
                CompositeWindow::get (popup)->addDamage ();
 
792
 
 
793
            setSelectedWindowHint ();
 
794
        }
 
795
 
 
796
        if (old != selectedWindow)
 
797
        {
 
798
            CompositeWindow::get (w)->addDamage ();
 
799
 
 
800
            w = screen->findWindow (old);
 
801
            if (w)
 
802
                CompositeWindow::get (w)->addDamage ();
 
803
 
 
804
            moreAdjust = true;
 
805
        }
 
806
    }
 
807
}
 
808
 
 
809
void
 
810
SwitchScreen::updateForegroundColor ()
 
811
{
 
812
    Atom          actual;
 
813
    int           result, format;
 
814
    unsigned long n, left;
 
815
    unsigned char *propData;
 
816
 
 
817
    if (!popupWindow)
 
818
        return;
 
819
 
 
820
 
 
821
    result = XGetWindowProperty (screen->dpy (), popupWindow,
 
822
                                 selectFgColorAtom, 0L, 4L, FALSE,
 
823
                                 XA_INTEGER, &actual, &format,
 
824
                                 &n, &left, &propData);
 
825
 
 
826
    if (result == Success && n && propData)
 
827
    {
 
828
        if (n == 3 || n == 4)
 
829
        {
 
830
            long *data = (long *) propData;
 
831
 
 
832
            fgColor[0] = MIN (0xffff, data[0]);
 
833
            fgColor[1] = MIN (0xffff, data[1]);
 
834
            fgColor[2] = MIN (0xffff, data[2]);
 
835
 
 
836
            if (n == 4)
 
837
                fgColor[3] = MIN (0xffff, data[3]);
 
838
        }
 
839
 
 
840
        XFree (propData);
 
841
    }
 
842
    else
 
843
    {
 
844
        fgColor[0] = 0;
 
845
        fgColor[1] = 0;
 
846
        fgColor[2] = 0;
 
847
        fgColor[3] = 0xffff;
 
848
    }
 
849
}
 
850
 
 
851
 
 
852
 
 
853
void
 
854
SwitchScreen::handleEvent (XEvent *event)
 
855
{
 
856
    CompWindow *w;
 
857
 
 
858
    screen->handleEvent (event);
 
859
 
 
860
    switch (event->type) {
 
861
        case UnmapNotify:
 
862
            windowRemove (event->xunmap.window);
 
863
            break;
 
864
        case DestroyNotify:
 
865
            windowRemove (event->xdestroywindow.window);
 
866
            break;
 
867
        case PropertyNotify:
 
868
            if (event->xproperty.atom == selectFgColorAtom)
 
869
            {
 
870
                if (event->xproperty.window == popupWindow)
 
871
                    updateForegroundColor ();
 
872
            }
 
873
 
 
874
        default:
 
875
            break;
 
876
    }
 
877
}
 
878
 
 
879
bool
 
880
SwitchScreen::adjustVelocity ()
 
881
{
 
882
    float dx, adjust, amount;
 
883
 
 
884
    dx = move;
 
885
 
 
886
    adjust = dx * 0.15f;
 
887
    amount = fabs (dx) * 1.5f;
 
888
    if (amount < 0.2f)
 
889
        amount = 0.2f;
 
890
    else if (amount > 2.0f)
 
891
        amount = 2.0f;
 
892
 
 
893
    mVelocity = (amount * mVelocity + adjust) / (amount + 1.0f);
 
894
 
 
895
    if (zooming)
 
896
    {
 
897
        float dt, ds;
 
898
 
 
899
        if (switching)
 
900
            dt = zoom - translate;
 
901
        else
 
902
            dt = 0.0f - translate;
 
903
 
 
904
        adjust = dt * 0.15f;
 
905
        amount = fabs (dt) * 1.5f;
 
906
        if (amount < 0.2f)
 
907
            amount = 0.2f;
 
908
        else if (amount > 2.0f)
 
909
            amount = 2.0f;
 
910
 
 
911
        tVelocity = (amount * tVelocity + adjust) / (amount + 1.0f);
 
912
 
 
913
        if (selectedWindow == zoomedWindow)
 
914
            ds = zoom - sTranslate;
 
915
        else
 
916
            ds = 0.0f - sTranslate;
 
917
 
 
918
        adjust = ds * 0.5f;
 
919
        amount = fabs (ds) * 5.0f;
 
920
        if (amount < 1.0f)
 
921
            amount = 1.0f;
 
922
        else if (amount > 6.0f)
 
923
            amount = 6.0f;
 
924
 
 
925
        sVelocity = (amount * sVelocity + adjust) / (amount + 1.0f);
 
926
 
 
927
        if (selectedWindow == zoomedWindow)
 
928
        {
 
929
            if (fabs (dx) < 0.1f   && fabs (mVelocity) < 0.2f   &&
 
930
                fabs (dt) < 0.001f && fabs (tVelocity) < 0.001f &&
 
931
                fabs (ds) < 0.001f && fabs (sVelocity) < 0.001f)
 
932
            {
 
933
                mVelocity = tVelocity = sVelocity = 0.0f;
 
934
                return false;
 
935
            }
 
936
        }
 
937
    }
 
938
    else
 
939
    {
 
940
        if (fabs (dx) < 0.1f  && fabs (mVelocity) < 0.2f)
 
941
        {
 
942
            mVelocity = 0.0f;
 
943
            return false;
 
944
        }
 
945
    }
 
946
 
 
947
    return true;
 
948
}
 
949
 
 
950
void
 
951
SwitchScreen::preparePaint (int msSinceLastPaint)
 
952
{
 
953
    if (moreAdjust)
 
954
    {
 
955
        int   steps, m;
 
956
        float amount, chunk;
 
957
 
 
958
        amount = msSinceLastPaint * 0.05f *
 
959
            opt[SWITCH_OPTION_SPEED].value ().f ();
 
960
        steps  = amount /
 
961
            (0.5f * opt[SWITCH_OPTION_TIMESTEP].value ().f ());
 
962
        if (!steps) steps = 1;
 
963
        chunk  = amount / (float) steps;
 
964
 
 
965
        while (steps--)
 
966
        {
 
967
            moreAdjust = adjustVelocity ();
 
968
            if (!moreAdjust)
 
969
            {
 
970
                pos += move;
 
971
                move = 0;
 
972
 
 
973
                if (zooming)
 
974
                {
 
975
                    if (switching)
 
976
                    {
 
977
                        translate  = zoom;
 
978
                        sTranslate = zoom;
 
979
                    }
 
980
                    else
 
981
                    {
 
982
                        translate  = 0.0f;
 
983
                        sTranslate = zoom;
 
984
 
 
985
                        selectedWindow = None;
 
986
                        zoomedWindow   = None;
 
987
 
 
988
                        if (grabIndex)
 
989
                        {
 
990
                            screen->removeGrab (grabIndex, 0);
 
991
                            grabIndex = 0;
 
992
                        }
 
993
 
 
994
                        activateEvent (false);
 
995
                    }
 
996
                }
 
997
                break;
 
998
            }
 
999
 
 
1000
            m = mVelocity * chunk;
 
1001
            if (!m)
 
1002
            {
 
1003
                if (mVelocity)
 
1004
                    m = (move > 0) ? 1 : -1;
 
1005
            }
 
1006
 
 
1007
            move -= m;
 
1008
            pos  += m;
 
1009
            if (pos < -windows.size () * WIDTH)
 
1010
                pos += windows.size () * WIDTH;
 
1011
            else if (pos > 0)
 
1012
                pos -= windows.size () * WIDTH;
 
1013
 
 
1014
            translate  += tVelocity * chunk;
 
1015
            sTranslate += sVelocity * chunk;
 
1016
 
 
1017
            if (selectedWindow != zoomedWindow)
 
1018
            {
 
1019
                if (sTranslate < 0.01f)
 
1020
                    zoomedWindow = selectedWindow;
 
1021
            }
 
1022
        }
 
1023
    }
 
1024
 
 
1025
    cScreen->preparePaint (msSinceLastPaint);
 
1026
}
 
1027
 
 
1028
bool
 
1029
SwitchScreen::glPaintOutput (const GLScreenPaintAttrib &sAttrib,
 
1030
                             const GLMatrix            &transform,
 
1031
                             const CompRegion          &region,
 
1032
                             CompOutput                *output,
 
1033
                             unsigned int              mask)
 
1034
{
 
1035
    bool status;
 
1036
 
 
1037
    zoomMask = ZOOMED_WINDOW_MASK | NORMAL_WINDOW_MASK;
 
1038
 
 
1039
    if (grabIndex || (zooming && translate > 0.001f))
 
1040
    {
 
1041
        GLMatrix   sTransform (transform);
 
1042
        CompWindow *zoomed;
 
1043
        CompWindow *switcher;
 
1044
        Window     zoomedAbove = None;
 
1045
 
 
1046
        if (zooming)
 
1047
        {
 
1048
            mask &= ~PAINT_SCREEN_REGION_MASK;
 
1049
            mask |= PAINT_SCREEN_TRANSFORMED_MASK | PAINT_SCREEN_CLEAR_MASK;
 
1050
 
 
1051
            sTransform.translate (0.0f, 0.0f, -translate);
 
1052
 
 
1053
            zoomMask = NORMAL_WINDOW_MASK;
 
1054
        }
 
1055
 
 
1056
        if (opt[SWITCH_OPTION_BRINGTOFRONT].value ().b ())
 
1057
        {
 
1058
            zoomed = screen->findWindow (zoomedWindow);
 
1059
            if (zoomed)
 
1060
            {
 
1061
                CompWindow *w;
 
1062
 
 
1063
                for (w = zoomed->prev; w && w->id () <= 1; w = w->prev);
 
1064
                zoomedAbove = (w) ? w->id () : None;
 
1065
 
 
1066
                screen->unhookWindow (zoomed);
 
1067
                screen->insertWindow (zoomed,
 
1068
                                      screen->windows ().back ()->id ());
 
1069
            }
 
1070
        }
 
1071
        else
 
1072
        {
 
1073
            zoomed = NULL;
 
1074
        }
 
1075
 
 
1076
        ignoreSwitcher = true;
 
1077
 
 
1078
        status = gScreen->glPaintOutput (sAttrib, sTransform, region, output,
 
1079
                                         mask);
 
1080
 
 
1081
        if (zooming)
 
1082
        {
 
1083
            float zTranslate;
 
1084
 
 
1085
            mask &= ~PAINT_SCREEN_CLEAR_MASK;
 
1086
            mask |= PAINT_SCREEN_NO_BACKGROUND_MASK;
 
1087
 
 
1088
            zoomMask = ZOOMED_WINDOW_MASK;
 
1089
 
 
1090
            zTranslate = MIN (sTranslate, translate);
 
1091
            sTransform.translate (0.0f, 0.0f, zTranslate);
 
1092
 
 
1093
            status = gScreen->glPaintOutput (sAttrib, sTransform, region,
 
1094
                                             output, mask);
 
1095
        }
 
1096
 
 
1097
        if (zoomed)
 
1098
        {
 
1099
            screen->unhookWindow (zoomed);
 
1100
            screen->insertWindow (zoomed, zoomedAbove);
 
1101
        }
 
1102
 
 
1103
        ignoreSwitcher = false;
 
1104
 
 
1105
        switcher = screen->findWindow (popupWindow);
 
1106
 
 
1107
        if (switcher)
 
1108
        {
 
1109
            SWITCH_WINDOW (switcher);
 
1110
 
 
1111
            sTransform = transform;
 
1112
 
 
1113
            sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
 
1114
 
 
1115
            glPushMatrix ();
 
1116
            glLoadMatrixf (sTransform.getMatrix ());
 
1117
 
 
1118
            if (!switcher->destroyed () &&
 
1119
                switcher->isViewable () &&
 
1120
                sw->cWindow->damaged ())
 
1121
            {
 
1122
                sw->gWindow->glPaint (sw->gWindow->paintAttrib (),
 
1123
                                      sTransform, infiniteRegion, 0);
 
1124
            }
 
1125
 
 
1126
            glPopMatrix ();
 
1127
        }
 
1128
    }
 
1129
    else
 
1130
    {
 
1131
        status = gScreen->glPaintOutput (sAttrib, transform, region, output,
 
1132
                                         mask);
 
1133
    }
 
1134
 
 
1135
    return status;
 
1136
}
 
1137
 
 
1138
void
 
1139
SwitchScreen::donePaint ()
 
1140
{
 
1141
    if ((grabIndex || zooming) && moreAdjust)
 
1142
    {
 
1143
        if (zooming)
 
1144
        {
 
1145
            cScreen->damageScreen ();
 
1146
        }
 
1147
        else
 
1148
        {
 
1149
            CompWindow *w;
 
1150
 
 
1151
            w = screen->findWindow (popupWindow);
 
1152
            if (w)
 
1153
                CompositeWindow::get (w)->addDamage ();
 
1154
        }
 
1155
    }
 
1156
    else if (!grabIndex && !(zooming && translate > 0.001f) && !moreAdjust)
 
1157
    {
 
1158
        cScreen->preparePaintSetEnabled (this, false);
 
1159
        cScreen->donePaintSetEnabled (this, false);
 
1160
        gScreen->glPaintOutputSetEnabled (this, false);
 
1161
 
 
1162
        foreach (CompWindow *w, screen->windows ())
 
1163
        {
 
1164
            SWITCH_WINDOW (w);
 
1165
            sw->cWindow->damageRectSetEnabled (sw, false);
 
1166
            sw->gWindow->glPaintSetEnabled (sw, false);
 
1167
        }
 
1168
    }
 
1169
 
 
1170
    cScreen->donePaint ();
 
1171
}
 
1172
 
 
1173
 
 
1174
void
 
1175
SwitchWindow::paintThumb (const GLWindowPaintAttrib &attrib,
 
1176
                          const GLMatrix            &transform,
 
1177
                          unsigned int              mask,
 
1178
                          int                       x,
 
1179
                          int                       y,
 
1180
                          int                       x1,
 
1181
                          int                       x2)
 
1182
{
 
1183
    GLWindowPaintAttrib  sAttrib (attrib);
 
1184
    int                  wx, wy;
 
1185
    float                width, height;
 
1186
    GLTexture            *icon = NULL;
 
1187
    CompWindow::Geometry &g = window->geometry ();
 
1188
 
 
1189
    mask |= PAINT_WINDOW_TRANSFORMED_MASK;
 
1190
 
 
1191
    if (window->mapNum ())
 
1192
    {
 
1193
        if (gWindow->textures ().empty ())
 
1194
            gWindow->bind ();
 
1195
    }
 
1196
 
 
1197
    if (!gWindow->textures ().empty ())
 
1198
    {
 
1199
        GLMatrix wTransform (transform);
 
1200
        int      ww, wh;
 
1201
        int      addWindowGeometryIndex =
 
1202
            gWindow->glAddGeometryGetCurrentIndex ();
 
1203
 
 
1204
        width  = WIDTH  - (SPACE << 1);
 
1205
        height = HEIGHT - (SPACE << 1);
 
1206
 
 
1207
        ww = g.width () + window->input ().left +
 
1208
             window->input ().right;
 
1209
        wh = g.height () + window->input ().top +
 
1210
             window->input ().bottom;
 
1211
 
 
1212
        if (ww > width)
 
1213
            sAttrib.xScale = width / ww;
 
1214
        else
 
1215
            sAttrib.xScale = 1.0f;
 
1216
 
 
1217
        if (wh > height)
 
1218
            sAttrib.yScale = height / wh;
 
1219
        else
 
1220
            sAttrib.yScale = 1.0f;
 
1221
 
 
1222
        if (sAttrib.xScale < sAttrib.yScale)
 
1223
            sAttrib.yScale = sAttrib.xScale;
 
1224
        else
 
1225
            sAttrib.xScale = sAttrib.yScale;
 
1226
 
 
1227
        width  = ww * sAttrib.xScale;
 
1228
        height = wh * sAttrib.yScale;
 
1229
 
 
1230
        wx = x + SPACE + ((WIDTH  - (SPACE << 1)) - width)  / 2;
 
1231
        wy = y + SPACE + ((HEIGHT - (SPACE << 1)) - height) / 2;
 
1232
 
 
1233
        sAttrib.xTranslate = wx - g.x () +
 
1234
                             window->input ().left * sAttrib.xScale;
 
1235
        sAttrib.yTranslate = wy - g.y () +
 
1236
                             window->input ().top  * sAttrib.yScale;
 
1237
 
 
1238
        GLFragment::Attrib fragment (sAttrib);
 
1239
 
 
1240
        if (window->alpha () || fragment.getOpacity () != OPAQUE)
 
1241
            mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
 
1242
 
 
1243
        wTransform.translate (g.x (), g.y (), 0.0f);
 
1244
        wTransform.scale (sAttrib.xScale, sAttrib.yScale, 1.0f);
 
1245
        wTransform.translate (sAttrib.xTranslate / sAttrib.xScale - g.x (),
 
1246
                              sAttrib.yTranslate / sAttrib.yScale - g.y (),
 
1247
                              0.0f);
 
1248
 
 
1249
        glPushMatrix ();
 
1250
        glLoadMatrixf (wTransform.getMatrix ());
 
1251
 
 
1252
        /* XXX: replacing the addWindowGeometry function like this is
 
1253
           very ugly but necessary until the vertex stage has been made
 
1254
           fully pluggable. */
 
1255
        gWindow->glAddGeometrySetCurrentIndex (MAXSHORT);
 
1256
        gWindow->glDraw (wTransform, fragment, infiniteRegion, mask);
 
1257
        gWindow->glAddGeometrySetCurrentIndex (addWindowGeometryIndex);
 
1258
 
 
1259
        glPopMatrix ();
 
1260
 
 
1261
        if (sScreen->opt[SWITCH_OPTION_ICON].value ().b ())
 
1262
        {
 
1263
            icon = gWindow->getIcon (ICON_SIZE, ICON_SIZE);
 
1264
            if (icon)
 
1265
            {
 
1266
                sAttrib.xScale = sAttrib.yScale = 1.0f;
 
1267
 
 
1268
                wx = x + WIDTH  - icon->width ()  - SPACE;
 
1269
                wy = y + HEIGHT - icon->height () - SPACE;
 
1270
            }
 
1271
        }
 
1272
    }
 
1273
    else
 
1274
    {
 
1275
        width  = WIDTH  - (WIDTH  >> 2);
 
1276
        height = HEIGHT - (HEIGHT >> 2);
 
1277
 
 
1278
        icon = gWindow->getIcon (ICON_SIZE, ICON_SIZE);
 
1279
        if (!icon)
 
1280
            icon = gScreen->defaultIcon ();
 
1281
 
 
1282
        if (icon)
 
1283
        {
 
1284
            int iw, ih;
 
1285
 
 
1286
            iw = width  - SPACE;
 
1287
            ih = height - SPACE;
 
1288
 
 
1289
            if (icon->width () < (iw >> 1))
 
1290
                sAttrib.xScale = (iw / icon->width ());
 
1291
            else
 
1292
                sAttrib.xScale = 1.0f;
 
1293
 
 
1294
            if (icon->height () < (ih >> 1))
 
1295
                sAttrib.yScale = (ih / icon->height ());
 
1296
            else
 
1297
                sAttrib.yScale = 1.0f;
 
1298
 
 
1299
            if (sAttrib.xScale < sAttrib.yScale)
 
1300
                sAttrib.yScale = sAttrib.xScale;
 
1301
            else
 
1302
                sAttrib.xScale = sAttrib.yScale;
 
1303
 
 
1304
            width  = icon->width ()  * sAttrib.xScale;
 
1305
            height = icon->height () * sAttrib.yScale;
 
1306
 
 
1307
            wx = x + SPACE + ((WIDTH  - (SPACE << 1)) - width)  / 2;
 
1308
            wy = y + SPACE + ((HEIGHT - (SPACE << 1)) - height) / 2;
 
1309
        }
 
1310
    }
 
1311
 
 
1312
    if (icon)
 
1313
    {
 
1314
        CompRegion        iconReg (g.x (), g.y (), icon->width (),
 
1315
                                   icon->height ());
 
1316
        GLTexture::MatrixList matrix (1);
 
1317
        int               addWindowGeometryIndex =
 
1318
            gWindow->glAddGeometryGetCurrentIndex ();
 
1319
 
 
1320
        mask |= PAINT_WINDOW_BLEND_MASK;
 
1321
 
 
1322
        matrix[0] = icon->matrix ();
 
1323
        matrix[0].x0 -= (g.x () * matrix[0].xx);
 
1324
        matrix[0].y0 -= (g.y () * matrix[0].yy);
 
1325
 
 
1326
        sAttrib.xTranslate = wx - g.x ();
 
1327
        sAttrib.yTranslate = wy - g.y ();
 
1328
 
 
1329
        gWindow->geometry ().reset ();
 
1330
 
 
1331
        gWindow->glAddGeometrySetCurrentIndex (MAXSHORT);
 
1332
        gWindow->glAddGeometry (matrix, iconReg, infiniteRegion);
 
1333
        gWindow->glAddGeometrySetCurrentIndex (addWindowGeometryIndex);
 
1334
 
 
1335
        if (gWindow->geometry ().vCount)
 
1336
        {
 
1337
            GLFragment::Attrib fragment (sAttrib);
 
1338
            GLMatrix           wTransform (transform);
 
1339
 
 
1340
            wTransform.translate (g.x (), g.y (), 0.0f);
 
1341
            wTransform.scale (sAttrib.xScale, sAttrib.yScale, 1.0f);
 
1342
            wTransform.translate (sAttrib.xTranslate / sAttrib.xScale - g.x (),
 
1343
                                  sAttrib.yTranslate / sAttrib.yScale - g.y (),
 
1344
                                  0.0f);
 
1345
 
 
1346
            glPushMatrix ();
 
1347
            glLoadMatrixf (wTransform.getMatrix ());
 
1348
 
 
1349
            gWindow->glDrawTexture (icon, fragment, mask);
 
1350
 
 
1351
            glPopMatrix ();
 
1352
        }
 
1353
    }
 
1354
}
 
1355
 
 
1356
bool
 
1357
SwitchWindow::glPaint (const GLWindowPaintAttrib &attrib,
 
1358
                       const GLMatrix            &transform,
 
1359
                       const CompRegion          &region,
 
1360
                       unsigned int              mask)
 
1361
{
 
1362
    int        zoomType = NORMAL_WINDOW_MASK;
 
1363
    bool       status;
 
1364
 
 
1365
    if (window->id () == sScreen->popupWindow)
 
1366
    {
 
1367
        GLenum         filter;
 
1368
        int            x, y, x1, x2, cx, i;
 
1369
        unsigned short color[4];
 
1370
 
 
1371
        CompWindow::Geometry &g = window->geometry ();
 
1372
 
 
1373
        if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK ||
 
1374
            sScreen->ignoreSwitcher)
 
1375
            return false;
 
1376
 
 
1377
        status = gWindow->glPaint (attrib, transform, region, mask);
 
1378
 
 
1379
        if (!(mask & PAINT_WINDOW_TRANSFORMED_MASK) && region.isEmpty ())
 
1380
            return true;
 
1381
 
 
1382
        x1 = g.x () + SPACE;
 
1383
        x2 = g.x () + g.width () - SPACE;
 
1384
 
 
1385
        x = x1 + sScreen->pos;
 
1386
        y = g.y () + SPACE;
 
1387
 
 
1388
        filter = gScreen->textureFilter ();
 
1389
 
 
1390
        if (sScreen->opt[SWITCH_OPTION_MIPMAP].value ().b ())
 
1391
            gScreen->setTextureFilter (GL_LINEAR_MIPMAP_LINEAR);
 
1392
 
 
1393
        glPushAttrib (GL_SCISSOR_BIT);
 
1394
 
 
1395
        glEnable (GL_SCISSOR_TEST);
 
1396
        glScissor (x1, 0, x2 - x1, screen->height ());
 
1397
 
 
1398
        foreach (CompWindow *w, sScreen->windows)
 
1399
        {
 
1400
            if (x + WIDTH > x1)
 
1401
                SwitchWindow::get (w)->paintThumb (
 
1402
                    gWindow->lastPaintAttrib (), transform,
 
1403
                    mask, x, y, x1, x2);
 
1404
            x += WIDTH;
 
1405
        }
 
1406
 
 
1407
        foreach (CompWindow *w, sScreen->windows)
 
1408
        {
 
1409
            if (x > x2)
 
1410
                break;
 
1411
 
 
1412
            SwitchWindow::get (w)->paintThumb (
 
1413
                gWindow->lastPaintAttrib (), transform,
 
1414
                mask, x, y, x1, x2);
 
1415
            x += WIDTH;
 
1416
        }
 
1417
 
 
1418
        glPopAttrib ();
 
1419
 
 
1420
        gScreen->setTextureFilter (filter);
 
1421
 
 
1422
        cx = g.x () + (g.width () >> 1);
 
1423
 
 
1424
        glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 
1425
        glEnable (GL_BLEND);
 
1426
        for (i = 0; i < 4; i++)
 
1427
            color[i] = (unsigned int)sScreen->fgColor[i] *
 
1428
                       gWindow->lastPaintAttrib ().opacity /
 
1429
                       0xffff;
 
1430
        glColor4usv (color);
 
1431
        glPushMatrix ();
 
1432
        glTranslatef (cx, y, 0.0f);
 
1433
        glVertexPointer (2, GL_FLOAT, 0, _boxVertices);
 
1434
        glDrawArrays (GL_QUADS, 0, 16);
 
1435
        glPopMatrix ();
 
1436
        glColor4usv (defaultColor);
 
1437
        glDisable (GL_BLEND);
 
1438
        glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 
1439
    }
 
1440
    else if (window->id () == sScreen->selectedWindow)
 
1441
    {
 
1442
        if (sScreen->opt[SWITCH_OPTION_BRINGTOFRONT].value ().b () &&
 
1443
            sScreen->selectedWindow == sScreen->zoomedWindow)
 
1444
            zoomType = ZOOMED_WINDOW_MASK;
 
1445
 
 
1446
        if (!(sScreen->zoomMask & zoomType))
 
1447
            return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
 
1448
                false : true;
 
1449
 
 
1450
        status = gWindow->glPaint (attrib, transform, region, mask);
 
1451
    }
 
1452
    else if (sScreen->switching)
 
1453
    {
 
1454
        GLWindowPaintAttrib sAttrib (attrib);
 
1455
        GLuint              value;
 
1456
 
 
1457
        value = sScreen->opt[SWITCH_OPTION_SATURATION].value ().i ();
 
1458
        if (value != 100)
 
1459
            sAttrib.saturation = sAttrib.saturation * value / 100;
 
1460
 
 
1461
        value = sScreen->opt[SWITCH_OPTION_BRIGHTNESS].value ().i ();
 
1462
        if (value != 100)
 
1463
            sAttrib.brightness = sAttrib.brightness * value / 100;
 
1464
 
 
1465
        if (window->wmType () & ~(CompWindowTypeDockMask |
 
1466
                                  CompWindowTypeDesktopMask))
 
1467
        {
 
1468
            value = sScreen->opt[SWITCH_OPTION_OPACITY].value ().i ();
 
1469
            if (value != 100)
 
1470
                sAttrib.opacity = sAttrib.opacity * value / 100;
 
1471
        }
 
1472
 
 
1473
        if (sScreen->opt[SWITCH_OPTION_BRINGTOFRONT].value ().b () &&
 
1474
            window->id () == sScreen->zoomedWindow)
 
1475
            zoomType = ZOOMED_WINDOW_MASK;
 
1476
 
 
1477
        if (!(sScreen->zoomMask & zoomType))
 
1478
            return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
 
1479
                false : true;
 
1480
 
 
1481
        status = gWindow->glPaint (sAttrib, transform, region, mask);
 
1482
    }
 
1483
    else
 
1484
    {
 
1485
        if (!(sScreen->zoomMask & zoomType))
 
1486
            return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
 
1487
                false : true;
 
1488
 
 
1489
        status = gWindow->glPaint (attrib, transform, region, mask);
 
1490
    }
 
1491
 
 
1492
    return status;
 
1493
}
 
1494
 
 
1495
bool
 
1496
SwitchWindow::damageRect (bool initial, const CompRect &rect)
 
1497
{
 
1498
    bool status;
 
1499
 
 
1500
    if (sScreen->grabIndex)
 
1501
    {
 
1502
        CompWindow *popup;
 
1503
        int        i;
 
1504
 
 
1505
        foreach (CompWindow *w, sScreen->windows)
 
1506
        {
 
1507
            if (window == w)
 
1508
            {
 
1509
                popup = screen->findWindow (sScreen->popupWindow);
 
1510
                if (popup)
 
1511
                    CompositeWindow::get (popup)->addDamage ();
 
1512
 
 
1513
                break;
 
1514
            }
 
1515
        }
 
1516
    }
 
1517
 
 
1518
    cWindow->damageRect (initial, rect);
 
1519
 
 
1520
    return status;
 
1521
}
 
1522
 
 
1523
CompOption::Vector &
 
1524
SwitchScreen::getOptions ()
 
1525
{
 
1526
    return opt;
 
1527
}
 
1528
 
 
1529
bool
 
1530
SwitchScreen::setOption (const char        *name,
 
1531
                       CompOption::Value &value)
 
1532
{
 
1533
    CompOption *o;
 
1534
    unsigned int index;
 
1535
 
 
1536
    o = CompOption::findOption (opt, name, &index);
 
1537
    if (!o)
 
1538
        return false;
 
1539
 
 
1540
     switch (index) {
 
1541
        case SWITCH_OPTION_ZOOM:
 
1542
            if (o->set (value))
 
1543
            {
 
1544
                if (o->value ().f () < 0.05f)
 
1545
                {
 
1546
                    zooming = false;
 
1547
                    zoom    = 0.0f;
 
1548
                }
 
1549
                else
 
1550
                {
 
1551
                    zooming = true;
 
1552
                    zoom    = o->value ().f () / 30.0f;
 
1553
                }
 
1554
 
 
1555
                return true;
 
1556
            }
 
1557
            break;
 
1558
     default:
 
1559
        return CompOption::setOption (*o, value);
 
1560
     }
 
1561
 
 
1562
    return false;
 
1563
}
 
1564
 
 
1565
SwitchScreen::SwitchScreen (CompScreen *screen) :
 
1566
    PrivateHandler<SwitchScreen,CompScreen> (screen),
 
1567
    cScreen (CompositeScreen::get (screen)),
 
1568
    gScreen (GLScreen::get (screen)),
 
1569
    opt(SWITCH_OPTION_NUM),
 
1570
    popupWindow (None),
 
1571
    selectedWindow (None),
 
1572
    zoomedWindow (None),
 
1573
    lastActiveNum (0),
 
1574
    grabIndex (NULL),
 
1575
    switching (false),
 
1576
    zoomMask (~0),
 
1577
    moreAdjust (false),
 
1578
    mVelocity (0.0),
 
1579
    tVelocity (0.0),
 
1580
    sVelocity (0.0),
 
1581
    windows (),
 
1582
    pos (0),
 
1583
    move (0),
 
1584
    translate (0.0),
 
1585
    sTranslate (0.0),
 
1586
    selection (CurrentViewport),
 
1587
    ignoreSwitcher (false)
 
1588
{
 
1589
    if (!switcherVTable->getMetadata ()->initOptions (switchOptionInfo,
 
1590
                                                      SWITCH_OPTION_NUM, opt))
 
1591
    {
 
1592
        setFailed ();
 
1593
        return;
 
1594
    }
 
1595
 
 
1596
    zoom = opt[SWITCH_OPTION_ZOOM].value ().f () / 30.0f;
 
1597
 
 
1598
    zooming = (opt[SWITCH_OPTION_ZOOM].value ().f () > 0.05f);
 
1599
 
 
1600
    fgColor[0] = 0;
 
1601
    fgColor[1] = 0;
 
1602
    fgColor[2] = 0;
 
1603
    fgColor[3] = 0xffff;
 
1604
 
 
1605
    selectWinAtom =
 
1606
        XInternAtom (screen->dpy (), DECOR_SWITCH_WINDOW_ATOM_NAME, 0);
 
1607
    selectFgColorAtom =
 
1608
        XInternAtom (screen->dpy (), DECOR_SWITCH_FOREGROUND_COLOR_ATOM_NAME, 0);
 
1609
 
 
1610
 
 
1611
    ScreenInterface::setHandler (screen, false);
 
1612
    CompositeScreenInterface::setHandler (cScreen, false);
 
1613
    GLScreenInterface::setHandler (gScreen, false);
 
1614
}
 
1615
 
 
1616
SwitchScreen::~SwitchScreen ()
 
1617
{
 
1618
    if (popupWindow)
 
1619
        XDestroyWindow (screen->dpy (), popupWindow);
 
1620
}
 
1621
 
 
1622
bool
 
1623
SwitchPluginVTable::init ()
 
1624
{
 
1625
    if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) |
 
1626
        !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) |
 
1627
        !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
 
1628
         return false;
 
1629
 
 
1630
    getMetadata ()->addFromOptionInfo (switchOptionInfo, SWITCH_OPTION_NUM);
 
1631
    getMetadata ()->addFromFile (name ());
 
1632
 
 
1633
    return true;
 
1634
}
 
1635