~vanvugt/compiz-plugins-main/fix-915236

« back to all changes in this revision

Viewing changes to wall/src/wall.cpp

  • Committer: Sam Spilsbury
  • Date: 2011-08-12 06:41:38 UTC
  • Revision ID: sam.spilsbury@canonical.com-20110812064138-sg45sswip9zgk0og
Sync in changes from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 *
 
3
 * Compiz wall plugin
 
4
 *
 
5
 * wall.cpp
 
6
 *
 
7
 * Copyright (c) 2006 Robert Carr <racarr@beryl-project.org>
 
8
 *
 
9
 * Authors:
 
10
 * Robert Carr <racarr@beryl-project.org>
 
11
 * Dennis Kasprzyk <onestone@opencompositing.org>
 
12
 *
 
13
 * This program is free software; you can redistribute it and/or
 
14
 * modify it under the terms of the GNU General Public License
 
15
 * as published by the Free Software Foundation; either version 2
 
16
 * of the License, or (at your option) any later version.
 
17
 *
 
18
 * This program is distributed in the hope that it will be useful,
 
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
 * GNU General Public License for more details.
 
22
 *
 
23
 **/
 
24
 
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#include <math.h>
 
29
#include <sys/time.h>
 
30
#include <GL/glu.h>
 
31
#include <dlfcn.h>
 
32
 
 
33
#include <core/atoms.h>
 
34
 
 
35
#include "wall.h"
 
36
 
 
37
#define PI 3.14159265359f
 
38
#define VIEWPORT_SWITCHER_SIZE 100
 
39
#define ARROW_SIZE 33
 
40
 
 
41
#define getColorRGBA(name) \
 
42
    r = optionGet##name##Red() / 65535.0f;\
 
43
    g = optionGet##name##Green() / 65535.0f; \
 
44
    b = optionGet##name##Blue() / 65535.0f; \
 
45
    a = optionGet##name##Alpha() / 65535.0f
 
46
 
 
47
#define sigmoid(x) (1.0f / (1.0f + exp (-5.5f * 2 * ((x) - 0.5))))
 
48
#define sigmoidProgress(x) ((sigmoid (x) - sigmoid (0)) / \
 
49
                            (sigmoid (1) - sigmoid (0)))
 
50
 
 
51
COMPIZ_PLUGIN_20090315 (wall, WallPluginVTable);
 
52
 
 
53
void
 
54
WallScreen::clearCairoLayer (cairo_t *cr)
 
55
{
 
56
    cairo_save (cr);
 
57
    cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
 
58
    cairo_paint (cr);
 
59
    cairo_restore (cr);
 
60
}
 
61
 
 
62
void
 
63
WallScreen::drawSwitcherBackground ()
 
64
{
 
65
    cairo_t         *cr;
 
66
    cairo_pattern_t *pattern;
 
67
    float           outline = 2.0f;
 
68
    int             width, height, radius;
 
69
    float           r, g, b, a;
 
70
    unsigned int    i, j;
 
71
 
 
72
    destroyCairoContext (switcherContext);
 
73
    setupCairoContext (switcherContext);
 
74
 
 
75
    cr = switcherContext.cr;
 
76
    clearCairoLayer (cr);
 
77
 
 
78
    width = switcherContext.width - outline;
 
79
    height = switcherContext.height - outline;
 
80
 
 
81
    cairo_save (cr);
 
82
    cairo_translate (cr, outline / 2.0f, outline / 2.0f);
 
83
 
 
84
    /* set the pattern for the switcher's background */
 
85
    pattern = cairo_pattern_create_linear (0, 0, width, height);
 
86
    getColorRGBA (BackgroundGradientBaseColor);
 
87
    cairo_pattern_add_color_stop_rgba (pattern, 0.00f, r, g, b, a);
 
88
    getColorRGBA (BackgroundGradientHighlightColor);
 
89
    cairo_pattern_add_color_stop_rgba (pattern, 0.65f, r, g, b, a);
 
90
    getColorRGBA (BackgroundGradientShadowColor);
 
91
    cairo_pattern_add_color_stop_rgba (pattern, 0.85f, r, g, b, a);
 
92
    cairo_set_source (cr, pattern);
 
93
 
 
94
    /* draw the border's shape */
 
95
    radius = optionGetEdgeRadius ();
 
96
    if (radius)
 
97
    {
 
98
        cairo_arc (cr, radius, radius, radius, PI, 1.5f * PI);
 
99
        cairo_arc (cr, radius + width - 2 * radius,
 
100
                   radius, radius, 1.5f * PI, 2.0 * PI);
 
101
        cairo_arc (cr, width - radius, height - radius, radius, 0,  PI / 2.0f);
 
102
        cairo_arc (cr, radius, height - radius, radius,  PI / 2.0f, PI);
 
103
    }
 
104
    else
 
105
    {
 
106
        cairo_rectangle (cr, 0, 0, width, height);
 
107
    }
 
108
 
 
109
    cairo_close_path (cr);
 
110
 
 
111
    /* apply pattern to background... */
 
112
    cairo_fill_preserve (cr);
 
113
 
 
114
    /* ... and draw an outline */
 
115
    cairo_set_line_width (cr, outline);
 
116
    getColorRGBA (OutlineColor);
 
117
    cairo_set_source_rgba (cr, r, g, b, a);
 
118
    cairo_stroke (cr);
 
119
 
 
120
    cairo_pattern_destroy (pattern);
 
121
    cairo_restore (cr);
 
122
 
 
123
    cairo_save (cr);
 
124
    for (i = 0; i < (unsigned int) screen->vpSize ().height (); i++)
 
125
    {
 
126
        cairo_translate (cr, 0.0, viewportBorder);
 
127
        cairo_save (cr);
 
128
        for (j = 0; j < (unsigned int) screen->vpSize ().width (); j++)
 
129
        {
 
130
            cairo_translate (cr, viewportBorder, 0.0);
 
131
 
 
132
            /* this cuts a hole into our background */
 
133
            cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
134
            cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
 
135
            cairo_rectangle (cr, 0, 0, viewportWidth, viewportHeight);
 
136
 
 
137
            cairo_fill_preserve (cr);
 
138
            cairo_set_operator (cr, CAIRO_OPERATOR_XOR);
 
139
            cairo_fill (cr);
 
140
 
 
141
            cairo_translate (cr, viewportWidth, 0.0);
 
142
        }
 
143
        cairo_restore(cr);
 
144
 
 
145
        cairo_translate (cr, 0.0, viewportHeight);
 
146
    }
 
147
    cairo_restore (cr);
 
148
}
 
149
 
 
150
void
 
151
WallScreen::drawThumb ()
 
152
{
 
153
    cairo_t         *cr;
 
154
    cairo_pattern_t *pattern;
 
155
    float           r, g, b, a;
 
156
    float           outline = 2.0f;
 
157
    int             width, height;
 
158
 
 
159
    destroyCairoContext (thumbContext);
 
160
    setupCairoContext (thumbContext);
 
161
 
 
162
    cr = thumbContext.cr;
 
163
    clearCairoLayer (cr);
 
164
 
 
165
    width  = thumbContext.width - outline;
 
166
    height = thumbContext.height - outline;
 
167
 
 
168
    cairo_translate (cr, outline / 2.0f, outline / 2.0f);
 
169
 
 
170
    pattern = cairo_pattern_create_linear (0, 0, width, height);
 
171
    getColorRGBA (ThumbGradientBaseColor);
 
172
    cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a);
 
173
    getColorRGBA (ThumbGradientHighlightColor);
 
174
    cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a);
 
175
 
 
176
    /* apply the pattern for thumb background */
 
177
    cairo_set_source (cr, pattern);
 
178
    cairo_rectangle (cr, 0, 0, width, height);
 
179
    cairo_fill_preserve (cr);
 
180
 
 
181
    cairo_set_line_width (cr, outline);
 
182
    getColorRGBA (OutlineColor);
 
183
    cairo_set_source_rgba (cr, r, g, b, a);
 
184
    cairo_stroke (cr);
 
185
 
 
186
    cairo_pattern_destroy (pattern);
 
187
 
 
188
    cairo_restore (cr);
 
189
}
 
190
 
 
191
void
 
192
WallScreen::drawHighlight ()
 
193
{
 
194
    cairo_t         *cr;
 
195
    cairo_pattern_t *pattern;
 
196
    int             width, height;
 
197
    float           r, g, b, a;
 
198
    float           outline = 2.0f;
 
199
 
 
200
    destroyCairoContext (highlightContext);
 
201
    setupCairoContext (highlightContext);
 
202
 
 
203
    cr = highlightContext.cr;
 
204
    clearCairoLayer (cr);
 
205
 
 
206
    width  = highlightContext.width - outline;
 
207
    height = highlightContext.height - outline;
 
208
 
 
209
    cairo_translate (cr, outline / 2.0f, outline / 2.0f);
 
210
 
 
211
    pattern = cairo_pattern_create_linear (0, 0, width, height);
 
212
    getColorRGBA (ThumbHighlightGradientBaseColor);
 
213
    cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a);
 
214
    getColorRGBA (ThumbHighlightGradientShadowColor);
 
215
    cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a);
 
216
 
 
217
    /* apply the pattern for thumb background */
 
218
    cairo_set_source (cr, pattern);
 
219
    cairo_rectangle (cr, 0, 0, width, height);
 
220
    cairo_fill_preserve (cr);
 
221
 
 
222
    cairo_set_line_width (cr, outline);
 
223
    getColorRGBA (OutlineColor);
 
224
    cairo_set_source_rgba (cr, r, g, b, a);
 
225
    cairo_stroke (cr);
 
226
 
 
227
    cairo_pattern_destroy (pattern);
 
228
 
 
229
    cairo_restore (cr);
 
230
}
 
231
 
 
232
void
 
233
WallScreen::drawArrow ()
 
234
{
 
235
    cairo_t *cr;
 
236
    float   outline = 2.0f;
 
237
    float   r, g, b, a;
 
238
 
 
239
    destroyCairoContext (arrowContext);
 
240
    setupCairoContext (arrowContext);
 
241
 
 
242
    cr = arrowContext.cr;
 
243
    clearCairoLayer (cr);
 
244
 
 
245
    cairo_translate (cr, outline / 2.0f, outline / 2.0f);
 
246
 
 
247
    /* apply the pattern for thumb background */
 
248
    cairo_set_line_width (cr, outline);
 
249
 
 
250
    /* draw top part of the arrow */
 
251
    getColorRGBA (ArrowBaseColor);
 
252
    cairo_set_source_rgba (cr, r, g, b, a);
 
253
    cairo_move_to (cr, 15, 0);
 
254
    cairo_line_to (cr, 30, 30);
 
255
    cairo_line_to (cr, 15, 24.5);
 
256
    cairo_line_to (cr, 15, 0);
 
257
    cairo_fill (cr);
 
258
 
 
259
    /* draw bottom part of the arrow */
 
260
    getColorRGBA (ArrowShadowColor);
 
261
    cairo_set_source_rgba (cr, r, g, b, a);
 
262
    cairo_move_to (cr, 15, 0);
 
263
    cairo_line_to (cr, 0, 30);
 
264
    cairo_line_to (cr, 15, 24.5);
 
265
    cairo_line_to (cr, 15, 0);
 
266
    cairo_fill (cr);
 
267
 
 
268
    /* draw the arrow outline */
 
269
    getColorRGBA (OutlineColor);
 
270
    cairo_set_source_rgba (cr, r, g, b, a);
 
271
    cairo_move_to (cr, 15, 0);
 
272
    cairo_line_to (cr, 30, 30);
 
273
    cairo_line_to (cr, 15, 24.5);
 
274
    cairo_line_to (cr, 0, 30);
 
275
    cairo_line_to (cr, 15, 0);
 
276
    cairo_stroke (cr);
 
277
 
 
278
    cairo_restore (cr);
 
279
}
 
280
 
 
281
void
 
282
WallScreen::setupCairoContext (WallCairoContext &context)
 
283
{
 
284
    XRenderPictFormat *format;
 
285
    Screen            *xScreen;
 
286
    int               width, height;
 
287
 
 
288
    xScreen = ScreenOfDisplay (screen->dpy (), screen->screenNum ());
 
289
 
 
290
    width = context.width;
 
291
    height = context.height;
 
292
 
 
293
    format = XRenderFindStandardFormat (screen->dpy (), PictStandardARGB32);
 
294
 
 
295
    context.pixmap = XCreatePixmap (screen->dpy (), screen->root (),
 
296
                                    width, height, 32);
 
297
 
 
298
    context.texture = GLTexture::bindPixmapToTexture (context.pixmap,
 
299
                                                      width, height, 32);
 
300
    if (context.texture.empty ())
 
301
    {
 
302
        screen->logMessage ("wall", CompLogLevelError,
 
303
                            "Couldn't create cairo context for switcher");
 
304
    }
 
305
 
 
306
    context.surface =
 
307
        cairo_xlib_surface_create_with_xrender_format (screen->dpy (),
 
308
                                                       context.pixmap,
 
309
                                                       xScreen, format,
 
310
                                                       width, height);
 
311
 
 
312
    context.cr = cairo_create (context.surface);
 
313
    clearCairoLayer (context.cr);
 
314
}
 
315
 
 
316
void
 
317
WallScreen::destroyCairoContext (WallCairoContext &context)
 
318
{
 
319
    if (context.cr)
 
320
        cairo_destroy (context.cr);
 
321
 
 
322
    if (context.surface)
 
323
        cairo_surface_destroy (context.surface);
 
324
 
 
325
    context.texture.clear ();
 
326
 
 
327
    if (context.pixmap)
 
328
        XFreePixmap (screen->dpy (), context.pixmap);
 
329
}
 
330
 
 
331
bool
 
332
WallScreen::checkDestination (unsigned int destX,
 
333
                              unsigned int destY)
 
334
{
 
335
    CompPoint point;
 
336
    CompSize  size;
 
337
 
 
338
    point = screen->vp ();
 
339
    size = screen->vpSize ();
 
340
 
 
341
    if (point.x () - destX < 0)
 
342
        return false;
 
343
 
 
344
    if (point.x () - destX >= (unsigned int) size.width ())
 
345
        return false;
 
346
 
 
347
    if (point.y () - destY >= (unsigned int) size.height ())
 
348
        return false;
 
349
 
 
350
    if (point.y () - destY < 0)
 
351
        return false;
 
352
 
 
353
    return true;
 
354
}
 
355
 
 
356
void
 
357
WallScreen::releaseMoveWindow ()
 
358
{
 
359
    CompWindow *window;
 
360
 
 
361
    window = screen->findWindow (moveWindow);
 
362
    if (window)
 
363
        window->syncPosition ();
 
364
 
 
365
    moveWindow = 0;
 
366
}
 
367
 
 
368
void
 
369
WallScreen::computeTranslation (float &x,
 
370
                                float &y)
 
371
{
 
372
    float elapsed, duration;
 
373
 
 
374
    duration = optionGetSlideDuration () * 1000.0;
 
375
    if (duration != 0.0)
 
376
        elapsed = 1.0 - (timer / duration);
 
377
    else
 
378
        elapsed = 1.0;
 
379
 
 
380
    if (elapsed < 0.0)
 
381
        elapsed = 0.0;
 
382
    if (elapsed > 1.0)
 
383
        elapsed = 1.0;
 
384
 
 
385
    /* Use temporary variables to you can pass in &ps->cur_x */
 
386
    x = (gotoX - curPosX) * elapsed + curPosX;
 
387
    y = (gotoY - curPosY) * elapsed + curPosY;
 
388
}
 
389
 
 
390
/* movement remainder that gets ignored for direction calculation */
 
391
#define IGNORE_REMAINDER 0.05
 
392
 
 
393
void
 
394
WallScreen::determineMovementAngle ()
 
395
{
 
396
    int   angle;
 
397
    float dx, dy;
 
398
 
 
399
    dx = gotoX - curPosX;
 
400
    dy = gotoY - curPosY;
 
401
 
 
402
    if (dy > IGNORE_REMAINDER)
 
403
        angle = (dx > IGNORE_REMAINDER) ? 135 :
 
404
                (dx < -IGNORE_REMAINDER) ? 225 : 180;
 
405
    else if (dy < -IGNORE_REMAINDER)
 
406
        angle = (dx > IGNORE_REMAINDER) ? 45 :
 
407
                (dx < -IGNORE_REMAINDER) ? 315 : 0;
 
408
    else
 
409
        angle = (dx > IGNORE_REMAINDER) ? 90 :
 
410
                (dx < -IGNORE_REMAINDER) ? 270 : -1;
 
411
 
 
412
    direction = angle;
 
413
}
 
414
 
 
415
bool
 
416
WallScreen::moveViewport (int    x,
 
417
                          int    y,
 
418
                          Window moveWin)
 
419
{
 
420
    CompOption::Vector o(0);
 
421
 
 
422
    if (!x && !y)
 
423
        return false;
 
424
 
 
425
    if (screen->otherGrabExist ("move", "switcher", "group-drag", "wall", 0))
 
426
        return false;
 
427
 
 
428
    if (!checkDestination (x, y))
 
429
        return false;
 
430
 
 
431
    if (moveWindow != moveWin)
 
432
    {
 
433
        CompWindow *w;
 
434
 
 
435
        releaseMoveWindow ();
 
436
        w = screen->findWindow (moveWin);
 
437
        if (w)
 
438
        {
 
439
            if (!(w->type () & (CompWindowTypeDesktopMask |
 
440
                                CompWindowTypeDockMask)))
 
441
            {
 
442
                if (!(w->state () & CompWindowStateStickyMask))
 
443
                {
 
444
                    moveWindow = w->id ();
 
445
                    moveWindowX = w->x ();
 
446
                    moveWindowY = w->y ();
 
447
                    w->raise ();
 
448
                }
 
449
            }
 
450
        }
 
451
    }
 
452
 
 
453
    if (!moving)
 
454
    {
 
455
        curPosX = screen->vp ().x ();
 
456
        curPosY = screen->vp ().y ();
 
457
    }
 
458
    gotoX = screen->vp ().x () - x;
 
459
    gotoY = screen->vp ().y () - y;
 
460
 
 
461
    determineMovementAngle ();
 
462
 
 
463
    screen->handleCompizEvent ("wall", "start_viewport_switch", o);
 
464
 
 
465
    if (!grabIndex)
 
466
        grabIndex = screen->pushGrab (screen->invisibleCursor (), "wall");
 
467
 
 
468
    screen->moveViewport (x, y, true);
 
469
 
 
470
    moving          = true;
 
471
    focusDefault    = true;
 
472
    boxOutputDevice = screen->outputDeviceForPoint (pointerX, pointerY);
 
473
 
 
474
    if (optionGetShowSwitcher ())
 
475
        boxTimeout = optionGetPreviewTimeout () * 1000;
 
476
    else
 
477
        boxTimeout = 0;
 
478
 
 
479
    timer = optionGetSlideDuration () * 1000;
 
480
 
 
481
    cScreen->damageScreen ();
 
482
 
 
483
    return true;
 
484
}
 
485
 
 
486
void
 
487
WallScreen::handleEvent (XEvent *event)
 
488
{
 
489
    switch (event->type) {
 
490
    case ClientMessage:
 
491
        if (event->xclient.message_type == Atoms::desktopViewport)
 
492
        {
 
493
            int dx, dy;
 
494
 
 
495
            if (screen->otherGrabExist ("switcher", "wall", 0))
 
496
                break;
 
497
 
 
498
            dx  = event->xclient.data.l[0] / screen->width();
 
499
            dx -= screen->vp ().x ();
 
500
            dy  = event->xclient.data.l[1] / screen->height();
 
501
            dy -= screen->vp ().y ();
 
502
 
 
503
            if (!dx && !dy)
 
504
                break;
 
505
 
 
506
            moveViewport (-dx, -dy, None);
 
507
        }
 
508
        if (event->xclient.message_type == Atoms::xdndEnter)
 
509
        {
 
510
            toggleEdges (true);
 
511
            edgeDrag = true;
 
512
        }
 
513
        else if (event->xclient.message_type == Atoms::xdndLeave)
 
514
            edgeDrag = false;
 
515
 
 
516
        break;
 
517
 
 
518
        case FocusIn:
 
519
        case FocusOut:
 
520
            if (event->xfocus.mode == NotifyGrab)
 
521
                poller.start ();
 
522
            else if (event->xfocus.mode == NotifyUngrab)
 
523
                poller.stop ();
 
524
        break;
 
525
 
 
526
        case ConfigureNotify:
 
527
 
 
528
             if (event->xconfigure.window == screen->root ())
 
529
                updateScreenEdgeRegions ();
 
530
 
 
531
        break;
 
532
    }
 
533
 
 
534
    screen->handleEvent (event);
 
535
}
 
536
 
 
537
/*
 
538
 * Borrowed this from PrivateScreen::updateScreenEdges
 
539
 *
 
540
 */
 
541
 
 
542
#define SCREEN_EDGE_NUM         8
 
543
 
 
544
void
 
545
WallScreen::updateScreenEdgeRegions ()
 
546
{
 
547
    edgeRegion = CompRegion (0, 0, screen->width (), screen->height ());
 
548
    noEdgeRegion = CompRegion (0, 0, screen->width (), screen->height ());
 
549
 
 
550
    struct screenEdgeGeometry {
 
551
        int xw, x0;
 
552
        int yh, y0;
 
553
        int ww, w0;
 
554
        int hh, h0;
 
555
    } geometry[SCREEN_EDGE_NUM] = {
 
556
        { 0,  0,   0,  2,   0,  2,   1, -4 }, /* left */
 
557
        { 1, -2,   0,  2,   0,  2,   1, -4 }, /* right */
 
558
        { 0,  2,   0,  0,   1, -4,   0,  2 }, /* top */
 
559
        { 0,  2,   1, -2,   1, -4,   0,  2 }, /* bottom */
 
560
        { 0,  0,   0,  0,   0,  2,   0,  2 }, /* top-left */
 
561
        { 1, -2,   0,  0,   0,  2,   0,  2 }, /* top-right */
 
562
        { 0,  0,   1, -2,   0,  2,   0,  2 }, /* bottom-left */
 
563
        { 1, -2,   1, -2,   0,  2,   0,  2 }  /* bottom-right */
 
564
    };
 
565
 
 
566
    for (unsigned int i = 0; i < SCREEN_EDGE_NUM; i++)
 
567
    {
 
568
        CompRegion edge (geometry[i].xw * screen->width () +
 
569
                         geometry[i].x0,
 
570
                         geometry[i].yh * screen->height () +
 
571
                         geometry[i].y0,
 
572
                         geometry[i].ww * screen->width () +
 
573
                         geometry[i].w0,
 
574
                         geometry[i].hh * screen->height () +
 
575
                         geometry[i].h0);
 
576
 
 
577
        noEdgeRegion -= edgeRegion;
 
578
    }
 
579
 
 
580
    edgeRegion -= noEdgeRegion;
 
581
}
 
582
 
 
583
#undef SCREEN_EDGE_NUM
 
584
 
 
585
void
 
586
WallScreen::positionUpdate (const CompPoint &pos)
 
587
{
 
588
    if (edgeDrag)
 
589
        return;
 
590
 
 
591
    if (edgeRegion.contains (pos))
 
592
        toggleEdges (false);
 
593
    else if (noEdgeRegion.contains (pos))
 
594
    {
 
595
        if (!screen->grabbed ())
 
596
            poller.stop ();
 
597
        toggleEdges (true);
 
598
    }
 
599
}
 
600
 
 
601
void
 
602
WallWindow::activate ()
 
603
{
 
604
    WALL_SCREEN (screen);
 
605
 
 
606
    if (window->placed () && !screen->otherGrabExist ("wall", "switcher", 0))
 
607
    {
 
608
        int       dx, dy;
 
609
        CompPoint viewport;
 
610
 
 
611
        viewport = window->defaultViewport ();
 
612
        dx       = viewport.x ();
 
613
        dy       = viewport.y ();
 
614
 
 
615
        dx -= screen->vp ().x ();
 
616
        dy -= screen->vp ().y ();
 
617
 
 
618
        if (dx || dy)
 
619
        {
 
620
            ws->moveViewport (-dx, -dy, None);
 
621
            ws->focusDefault = false;
 
622
        }
 
623
    }
 
624
 
 
625
    window->activate ();
 
626
}
 
627
 
 
628
void
 
629
WallWindow::grabNotify (int          x,
 
630
                        int          y,
 
631
                        unsigned int width,
 
632
                        unsigned int height)
 
633
{
 
634
    WallScreen::get (screen)->toggleEdges (true);
 
635
    WallScreen::get (screen)->edgeDrag = true;
 
636
 
 
637
    window->grabNotify (x, y, width, height);
 
638
}
 
639
 
 
640
void
 
641
WallWindow::ungrabNotify ()
 
642
{
 
643
    WallScreen::get (screen)->edgeDrag = false;
 
644
 
 
645
    window->ungrabNotify ();
 
646
}
 
647
 
 
648
void
 
649
WallScreen::checkAmount (int          dx,
 
650
                         int          dy,
 
651
                         int          &amountX,
 
652
                         int          &amountY)
 
653
{
 
654
    CompPoint point;
 
655
    CompSize  size;
 
656
 
 
657
    point = screen->vp ();
 
658
    size = screen->vpSize ();
 
659
 
 
660
    amountX = -dx;
 
661
    amountY = -dy;
 
662
 
 
663
    if (optionGetAllowWraparound ())
 
664
    {
 
665
        if ((point.x () + dx) < 0)
 
666
            amountX = -(size.width () + dx);
 
667
        else if ((point.x () + dx) >= size.width ())
 
668
            amountX = size.width () - dx;
 
669
 
 
670
        if ((point.y () + dy) < 0)
 
671
            amountY = -(size.height () + dy);
 
672
        else if ((point.y () + dy) >= size.height ())
 
673
            amountY = size.height () - dy;
 
674
    }
 
675
}
 
676
 
 
677
bool
 
678
WallScreen::initiate (CompAction         *action,
 
679
                      CompAction::State  state,
 
680
                      CompOption::Vector &options,
 
681
                      Direction          dir,
 
682
                      bool               withWin)
 
683
{
 
684
    int          dx = 0, dy = 0, amountX, amountY;
 
685
    unsigned int vpX, vpY;
 
686
    CompSize     size;
 
687
    Window       win = None;
 
688
 
 
689
    vpX  = screen->vp ().x ();
 
690
    vpY  = screen->vp ().y ();
 
691
    size = screen->vpSize ();
 
692
 
 
693
    switch (dir) {
 
694
        case Up:
 
695
            dy = -1;
 
696
            checkAmount (dx, dy, amountX, amountY);
 
697
            break;
 
698
        case Down:
 
699
            dy = 1;
 
700
            checkAmount (dx, dy, amountX, amountY);
 
701
            break;
 
702
        case Left:
 
703
            dx = -1;
 
704
            checkAmount (dx, dy, amountX, amountY);
 
705
            break;
 
706
        case Right:
 
707
            dx = 1;
 
708
            checkAmount (dx, dy, amountX, amountY);
 
709
            break;
 
710
        case Next:
 
711
            if ((vpX == (unsigned int) size.width () - 1) &&
 
712
                (vpY == (unsigned int) size.height () - 1))
 
713
            {
 
714
                amountX = -(size.width () - 1);
 
715
                amountY = -(size.height () - 1);
 
716
            }
 
717
            else if (vpX == (unsigned int) size.width () - 1)
 
718
            {
 
719
                amountX = -(size.width () - 1);
 
720
                amountY = 1;
 
721
            }
 
722
            else
 
723
            {
 
724
                amountX = 1;
 
725
                amountY = 0;
 
726
            }
 
727
 
 
728
            break;
 
729
        case Prev:
 
730
            if (vpX == 0 && vpY == 0)
 
731
            {
 
732
                amountX = size.width () - 1;
 
733
                amountY = size.height () - 1;
 
734
            }
 
735
            else if (vpX == 0)
 
736
            {
 
737
                amountX = size.width () - 1;
 
738
                amountY = -1;
 
739
            }
 
740
            else
 
741
            {
 
742
                amountX = -1;
 
743
                amountY = 0;
 
744
            }
 
745
            break;
 
746
    }
 
747
 
 
748
    if (withWin)
 
749
        win = CompOption::getIntOptionNamed (options, "window", 0);
 
750
 
 
751
    if (!moveViewport (amountX, amountY, win))
 
752
        return true;
 
753
 
 
754
    if (state & CompAction::StateInitKey)
 
755
        action->setState (action->state () | CompAction::StateTermKey);
 
756
 
 
757
    if (state & CompAction::StateInitButton)
 
758
        action->setState (action->state () | CompAction::StateTermButton);
 
759
 
 
760
    showPreview = optionGetShowSwitcher ();
 
761
 
 
762
    return true;
 
763
}
 
764
 
 
765
bool
 
766
WallScreen::terminate (CompAction         *action,
 
767
                       CompAction::State   state,
 
768
                       CompOption::Vector &options)
 
769
{
 
770
    if (showPreview)
 
771
    {
 
772
        showPreview = false;
 
773
        cScreen->damageScreen ();
 
774
    }
 
775
 
 
776
    if (action)
 
777
        action->setState (action->state () & ~(CompAction::StateTermKey |
 
778
                                               CompAction::StateTermButton));
 
779
 
 
780
    return false;
 
781
}
 
782
 
 
783
bool
 
784
WallScreen::initiateFlip (Direction         direction,
 
785
                          CompAction::State state)
 
786
{
 
787
    int dx, dy;
 
788
    int amountX, amountY;
 
789
 
 
790
    if (screen->otherGrabExist ("wall", "move", "group-drag", 0))
 
791
        return false;
 
792
 
 
793
    if (state & CompAction::StateInitEdgeDnd)
 
794
    {
 
795
        if (!optionGetEdgeflipDnd ())
 
796
            return false;
 
797
 
 
798
        if (screen->otherGrabExist ("wall", 0))
 
799
            return false;
 
800
    }
 
801
    else if (screen->grabExist ("move"))
 
802
    {
 
803
        if (!optionGetEdgeflipMove ())
 
804
            return false;
 
805
    }
 
806
    else if (screen->grabExist ("group-drag"))
 
807
    {
 
808
        if (!optionGetEdgeflipDnd ())
 
809
            return false;
 
810
    }
 
811
    else if (!optionGetEdgeflipPointer ())
 
812
    {
 
813
        toggleEdges (false);
 
814
        poller.start ();
 
815
        return false;
 
816
    }
 
817
 
 
818
    switch (direction) {
 
819
    case Left:
 
820
        dx = -1; dy = 0;
 
821
        break;
 
822
    case Right:
 
823
        dx = 1; dy = 0;
 
824
        break;
 
825
    case Up:
 
826
        dx = 0; dy = -1;
 
827
        break;
 
828
    case Down:
 
829
        dx = 0; dy = 1;
 
830
        break;
 
831
    default:
 
832
        dx = 0; dy = 0;
 
833
        break;
 
834
    }
 
835
 
 
836
    checkAmount (dx, dy, amountX, amountY);
 
837
    if (moveViewport (amountX, amountY, None))
 
838
    {
 
839
        int offsetX, offsetY;
 
840
        int warpX, warpY;
 
841
 
 
842
        if (dx < 0)
 
843
        {
 
844
            offsetX = screen->width () - 10;
 
845
            warpX = pointerX + screen->width ();
 
846
        }
 
847
        else if (dx > 0)
 
848
        {
 
849
            offsetX = 1- screen->width ();
 
850
            warpX = pointerX - screen->width ();
 
851
        }
 
852
        else
 
853
        {
 
854
            offsetX = 0;
 
855
            warpX = lastPointerX;
 
856
        }
 
857
 
 
858
        if (dy < 0)
 
859
        {
 
860
            offsetY = screen->height () - 10;
 
861
            warpY = pointerY + screen->height ();
 
862
        }
 
863
        else if (dy > 0)
 
864
        {
 
865
            offsetY = 1- screen->height ();
 
866
            warpY = pointerY - screen->height ();
 
867
        }
 
868
        else
 
869
        {
 
870
            offsetY = 0;
 
871
            warpY = lastPointerY;
 
872
        }
 
873
 
 
874
        screen->warpPointer (offsetX, offsetY);
 
875
        lastPointerX = warpX;
 
876
        lastPointerY = warpY;
 
877
    }
 
878
 
 
879
    return true;
 
880
}
 
881
 
 
882
inline void
 
883
wallDrawQuad (GLTexture::Matrix *matrix,
 
884
              BOX               *box)
 
885
{
 
886
    glTexCoord2f (COMP_TEX_COORD_X (*matrix, box->x1),
 
887
                  COMP_TEX_COORD_Y (*matrix, box->y2));
 
888
    glVertex2i (box->x1, box->y2);
 
889
    glTexCoord2f (COMP_TEX_COORD_X (*matrix, box->x2),
 
890
                  COMP_TEX_COORD_Y (*matrix, box->y2));
 
891
    glVertex2i (box->x2, box->y2);
 
892
    glTexCoord2f (COMP_TEX_COORD_X (*matrix, box->x2),
 
893
                  COMP_TEX_COORD_Y (*matrix, box->y1));
 
894
    glVertex2i (box->x2, box->y1);
 
895
    glTexCoord2f (COMP_TEX_COORD_X (*matrix, box->x1),
 
896
                  COMP_TEX_COORD_Y (*matrix, box->y1));
 
897
    glVertex2i (box->x1, box->y1);
 
898
}
 
899
 
 
900
void
 
901
WallScreen::drawCairoTextureOnScreen ()
 
902
{
 
903
    float             centerX, centerY;
 
904
    float             width, height;
 
905
    float             topLeftX, topLeftY;
 
906
    float             border;
 
907
    unsigned int      i, j;
 
908
    GLTexture::Matrix matrix;
 
909
    BOX               box;
 
910
 
 
911
    CompOutput::vector &outputDevs = screen->outputDevs ();
 
912
    CompOutput         output = outputDevs[boxOutputDevice];
 
913
 
 
914
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 
915
    glEnable (GL_BLEND);
 
916
 
 
917
    centerX = output.x1 () + (output.width () / 2.0f);
 
918
    centerY = output.y1 () + (output.height () / 2.0f);
 
919
 
 
920
    border = (float) viewportBorder;
 
921
    width  = (float) switcherContext.width;
 
922
    height = (float) switcherContext.height;
 
923
 
 
924
    topLeftX = centerX - floor (width / 2.0f);
 
925
    topLeftY = centerY - floor (height / 2.0f);
 
926
 
 
927
    firstViewportX = topLeftX + border;
 
928
    firstViewportY = topLeftY + border;
 
929
 
 
930
    if (!moving)
 
931
    {
 
932
        double left, timeout;
 
933
 
 
934
        timeout = optionGetPreviewTimeout () * 1000.0f;
 
935
        left    = (timeout > 0) ? (float) boxTimeout / timeout : 1.0f;
 
936
 
 
937
        if (left < 0)
 
938
            left = 0.0f;
 
939
        else if (left > 0.5)
 
940
            left = 1.0f;
 
941
        else
 
942
            left = 2 * left;
 
943
 
 
944
        glScreen->setTexEnvMode (GL_MODULATE);
 
945
 
 
946
        glColor4f (left, left, left, left);
 
947
        glTranslatef (0.0f, 0.0f, -(1 - left));
 
948
 
 
949
        mSzCamera = -(1 - left);
 
950
    }
 
951
    else
 
952
    {
 
953
        mSzCamera = 0.0f;
 
954
    }
 
955
 
 
956
    /* draw background */
 
957
 
 
958
    matrix = switcherContext.texture[0]->matrix ();
 
959
    matrix.x0 -= topLeftX * matrix.xx;
 
960
    matrix.y0 -= topLeftY * matrix.yy;
 
961
 
 
962
    box.x1 = topLeftX;
 
963
    box.x2 = box.x1 + width;
 
964
    box.y1 = topLeftY;
 
965
    box.y2 = box.y1 + height;
 
966
 
 
967
    switcherContext.texture[0]->enable (GLTexture::Fast);
 
968
    glBegin (GL_QUADS);
 
969
    wallDrawQuad (&matrix, &box);
 
970
    glEnd ();
 
971
    switcherContext.texture[0]->disable ();
 
972
 
 
973
    /* draw thumb */
 
974
    width = (float) thumbContext.width;
 
975
    height = (float) thumbContext.height;
 
976
 
 
977
    thumbContext.texture[0]->enable (GLTexture::Fast);
 
978
    glBegin (GL_QUADS);
 
979
    for (i = 0; i < (unsigned int) screen->vpSize ().width (); i++)
 
980
    {
 
981
        for (j = 0; j < (unsigned int) screen->vpSize ().height (); j++)
 
982
        {
 
983
            if (i == gotoX && j == gotoY && moving)
 
984
                continue;
 
985
 
 
986
            box.x1 = i * (width + border);
 
987
            box.x1 += topLeftX + border;
 
988
            box.x2 = box.x1 + width;
 
989
            box.y1 = j * (height + border);
 
990
            box.y1 += topLeftY + border;
 
991
            box.y2 = box.y1 + height;
 
992
 
 
993
            matrix = thumbContext.texture[0]->matrix ();
 
994
            matrix.x0 -= box.x1 * matrix.xx;
 
995
            matrix.y0 -= box.y1 * matrix.yy;
 
996
 
 
997
            wallDrawQuad (&matrix, &box);
 
998
        }
 
999
    }
 
1000
    glEnd ();
 
1001
    thumbContext.texture[0]->disable ();
 
1002
 
 
1003
    if (moving || showPreview)
 
1004
    {
 
1005
        /* draw highlight */
 
1006
 
 
1007
        box.x1 = screen->vp ().x () * (width + border) + topLeftX + border;
 
1008
        box.x2 = box.x1 + width;
 
1009
        box.y1 = screen->vp ().y () * (height + border) + topLeftY + border;
 
1010
        box.y2 = box.y1 + height;
 
1011
 
 
1012
        matrix = highlightContext.texture[0]->matrix ();
 
1013
        matrix.x0 -= box.x1 * matrix.xx;
 
1014
        matrix.y0 -= box.y1 * matrix.yy;
 
1015
 
 
1016
        highlightContext.texture[0]->enable (GLTexture::Fast);
 
1017
        glBegin (GL_QUADS);
 
1018
        wallDrawQuad (&matrix, &box);
 
1019
        glEnd ();
 
1020
        highlightContext.texture[0]->disable ();
 
1021
 
 
1022
        /* draw arrow */
 
1023
        if (direction >= 0)
 
1024
        {
 
1025
            arrowContext.texture[0]->enable (GLTexture::Fast);
 
1026
            int aW = arrowContext.width;
 
1027
            int aH = arrowContext.height;
 
1028
 
 
1029
            /* if we have a viewport preview we just paint the
 
1030
               arrow outside the switcher */
 
1031
            if (optionGetMiniscreen ())
 
1032
            {
 
1033
                width  = (float) switcherContext.width;
 
1034
                height = (float) switcherContext.height;
 
1035
 
 
1036
                switch (direction)
 
1037
                {
 
1038
                    /* top left */
 
1039
                    case 315:
 
1040
                        box.x1 = topLeftX - aW - border;
 
1041
                        box.y1 = topLeftY - aH - border;
 
1042
                        break;
 
1043
                    /* up */
 
1044
                    case 0:
 
1045
                        box.x1 = topLeftX + width / 2.0f - aW / 2.0f;
 
1046
                        box.y1 = topLeftY - aH - border;
 
1047
                        break;
 
1048
                    /* top right */
 
1049
                    case 45:
 
1050
                        box.x1 = topLeftX + width + border;
 
1051
                        box.y1 = topLeftY - aH - border;
 
1052
                        break;
 
1053
                    /* right */
 
1054
                    case 90:
 
1055
                        box.x1 = topLeftX + width + border;
 
1056
                        box.y1 = topLeftY + height / 2.0f - aH / 2.0f;
 
1057
                        break;
 
1058
                    /* bottom right */
 
1059
                    case 135:
 
1060
                        box.x1 = topLeftX + width + border;
 
1061
                        box.y1 = topLeftY + height + border;
 
1062
                        break;
 
1063
                    /* down */
 
1064
                    case 180:
 
1065
                        box.x1 = topLeftX + width / 2.0f - aW / 2.0f;
 
1066
                        box.y1 = topLeftY + height + border;
 
1067
                        break;
 
1068
                    /* bottom left */
 
1069
                    case 225:
 
1070
                        box.x1 = topLeftX - aW - border;
 
1071
                        box.y1 = topLeftY + height + border;
 
1072
                        break;
 
1073
                    /* left */
 
1074
                    case 270:
 
1075
                        box.x1 = topLeftX - aW - border;
 
1076
                        box.y1 = topLeftY + height / 2.0f - aH / 2.0f;
 
1077
                        break;
 
1078
                    default:
 
1079
                        break;
 
1080
                }
 
1081
            }
 
1082
            else
 
1083
            {
 
1084
                /* arrow is visible (no preview is painted over it) */
 
1085
                box.x1  = screen->vp().x() * (width + border) +
 
1086
                          topLeftX + border;
 
1087
                box.x1 += width / 2 - aW / 2;
 
1088
                box.y1  = screen->vp().y() * (height + border) +
 
1089
                          topLeftY + border;
 
1090
                box.y1 += height / 2 - aH / 2;
 
1091
            }
 
1092
 
 
1093
            box.x2 = box.x1 + aW;
 
1094
            box.y2 = box.y1 + aH;
 
1095
 
 
1096
            glTranslatef (box.x1 + aW / 2, box.y1 + aH / 2, 0.0f);
 
1097
            glRotatef (direction, 0.0f, 0.0f, 1.0f);
 
1098
            glTranslatef (-box.x1 - aW / 2, -box.y1 - aH / 2, 0.0f);
 
1099
 
 
1100
            matrix = arrowContext.texture[0]->matrix ();
 
1101
            matrix.x0 -= box.x1 * matrix.xx;
 
1102
            matrix.y0 -= box.y1 * matrix.yy;
 
1103
 
 
1104
            glBegin (GL_QUADS);
 
1105
            wallDrawQuad (&matrix, &box);
 
1106
            glEnd ();
 
1107
 
 
1108
            arrowContext.texture[0]->disable ();
 
1109
        }
 
1110
    }
 
1111
 
 
1112
    glDisable (GL_BLEND);
 
1113
    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 
1114
    glScreen->setTexEnvMode (GL_REPLACE);
 
1115
    glColor4usv (defaultColor);
 
1116
}
 
1117
 
 
1118
void
 
1119
WallScreen::paint (CompOutput::ptrList& outputs,
 
1120
                   unsigned int         mask)
 
1121
{
 
1122
    if (moving && outputs.size () > 1 && optionGetMmmode() == MmmodeSwitchAll)
 
1123
    {
 
1124
        outputs.clear ();
 
1125
        outputs.push_back (&screen->fullscreenOutput ());
 
1126
    }
 
1127
 
 
1128
    cScreen->paint (outputs, mask);
 
1129
}
 
1130
 
 
1131
bool
 
1132
WallScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
 
1133
                           const GLMatrix            &matrix,
 
1134
                           const CompRegion          &region,
 
1135
                           CompOutput                *output,
 
1136
                           unsigned int              mask)
 
1137
{
 
1138
    bool status;
 
1139
 
 
1140
    transform = NoTransformation;
 
1141
 
 
1142
    if (moving)
 
1143
        mask |= PAINT_SCREEN_TRANSFORMED_MASK |
 
1144
                PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
 
1145
 
 
1146
    status = glScreen->glPaintOutput (attrib, matrix, region, output, mask);
 
1147
 
 
1148
    if (optionGetShowSwitcher () &&
 
1149
        (moving || showPreview || boxTimeout) &&
 
1150
        (output->id () == boxOutputDevice ||
 
1151
         output == &screen->fullscreenOutput ()))
 
1152
    {
 
1153
        GLMatrix sMatrix (matrix);
 
1154
 
 
1155
        sMatrix.toScreenSpace (output, -DEFAULT_Z_CAMERA);
 
1156
 
 
1157
        glPushMatrix ();
 
1158
        glLoadMatrixf (sMatrix.getMatrix ());
 
1159
 
 
1160
        drawCairoTextureOnScreen ();
 
1161
 
 
1162
        glPopMatrix ();
 
1163
 
 
1164
        if (optionGetMiniscreen ())
 
1165
        {
 
1166
            unsigned int i, j;
 
1167
            float        mw, mh;
 
1168
 
 
1169
            mw = viewportWidth;
 
1170
            mh = viewportHeight;
 
1171
 
 
1172
            transform = MiniScreen;
 
1173
            mSAttribs.xScale = mw / screen->width ();
 
1174
            mSAttribs.yScale = mh / screen->height ();
 
1175
            mSAttribs.opacity = OPAQUE * (1.0 + mSzCamera);
 
1176
            mSAttribs.saturation = COLOR;
 
1177
 
 
1178
            for (j = 0; j < (unsigned int) screen->vpSize ().height (); j++)
 
1179
            {
 
1180
                for (i = 0; i < (unsigned int) screen->vpSize ().width (); i++)
 
1181
                {
 
1182
                    float        mx, my;
 
1183
                    unsigned int msMask;
 
1184
                    CompPoint    vp (i, j);
 
1185
 
 
1186
                    mx = firstViewportX +
 
1187
                         (i * (viewportWidth + viewportBorder));
 
1188
                    my = firstViewportY +
 
1189
                         (j * (viewportHeight + viewportBorder));
 
1190
 
 
1191
                    mSAttribs.xTranslate = mx / output->width ();
 
1192
                    mSAttribs.yTranslate = -my / output->height ();
 
1193
 
 
1194
                    mSAttribs.brightness = 0.4f * BRIGHT;
 
1195
 
 
1196
                    if (vp == screen->vp () &&
 
1197
                        (moving || boxTimeout || showPreview))
 
1198
                    {
 
1199
                        mSAttribs.brightness = BRIGHT;
 
1200
                    }
 
1201
 
 
1202
                    cScreen->setWindowPaintOffset ((screen->vp ().x () - i) *
 
1203
                                                   screen->width (),
 
1204
                                                   (screen->vp ().y () - j) *
 
1205
                                                   screen->height ());
 
1206
 
 
1207
                    msMask = mask | PAINT_SCREEN_TRANSFORMED_MASK;
 
1208
 
 
1209
                    glScreen->glPaintTransformedOutput (attrib, matrix,
 
1210
                                                        region, output, msMask);
 
1211
 
 
1212
                }
 
1213
            }
 
1214
            transform = NoTransformation;
 
1215
            cScreen->setWindowPaintOffset (0, 0);
 
1216
        }
 
1217
    }
 
1218
 
 
1219
    return status;
 
1220
}
 
1221
 
 
1222
void
 
1223
WallScreen::preparePaint (int msSinceLastPaint)
 
1224
{
 
1225
    if (!moving && !showPreview && boxTimeout)
 
1226
        boxTimeout -= msSinceLastPaint;
 
1227
 
 
1228
    if (timer)
 
1229
        timer -= msSinceLastPaint;
 
1230
 
 
1231
    if (moving)
 
1232
    {
 
1233
        computeTranslation (curPosX, curPosY);
 
1234
 
 
1235
        if (moveWindow)
 
1236
        {
 
1237
            CompWindow *window;
 
1238
 
 
1239
            window = screen->findWindow (moveWindow);
 
1240
            if (window)
 
1241
            {
 
1242
                float dx, dy;
 
1243
 
 
1244
                dx = (gotoX - curPosX) * screen->width ();
 
1245
                dy = (gotoY - curPosY) * screen->height ();
 
1246
 
 
1247
                window->moveToViewportPosition (moveWindowX - dx,
 
1248
                                                moveWindowY - dy,
 
1249
                                                true);
 
1250
            }
 
1251
        }
 
1252
    }
 
1253
 
 
1254
    if (moving && curPosX == gotoX && curPosY == gotoY)
 
1255
    {
 
1256
        CompOption::Vector o (0);
 
1257
        moving = false;
 
1258
        timer  = 0;
 
1259
 
 
1260
        if (moveWindow)
 
1261
            releaseMoveWindow ();
 
1262
        else if (focusDefault)
 
1263
        {
 
1264
            /* only focus default window if switcher is not active */
 
1265
            if (!screen->grabExist ("switcher"))
 
1266
                screen->focusDefaultWindow ();
 
1267
        }
 
1268
 
 
1269
        screen->handleCompizEvent ("wall", "end_viewport_switch", o);
 
1270
    }
 
1271
 
 
1272
    cScreen->preparePaint (msSinceLastPaint);
 
1273
}
 
1274
 
 
1275
void
 
1276
WallScreen::glPaintTransformedOutput (const GLScreenPaintAttrib &attrib,
 
1277
                                      const GLMatrix            &matrix,
 
1278
                                      const CompRegion          &region,
 
1279
                                      CompOutput                *output,
 
1280
                                      unsigned int              mask)
 
1281
{
 
1282
    bool clear = (mask & PAINT_SCREEN_CLEAR_MASK);
 
1283
 
 
1284
    if (transform == MiniScreen)
 
1285
    {
 
1286
        GLMatrix sMatrix (matrix);
 
1287
 
 
1288
        mask &= ~PAINT_SCREEN_CLEAR_MASK;
 
1289
 
 
1290
        /* move each screen to the correct output position */
 
1291
        sMatrix.translate (-(float) output->x1 () / (float) output->width (),
 
1292
                           (float) output->y1 () / (float) output->height (),
 
1293
                           0.0f);
 
1294
        sMatrix.translate (0.0f, 0.0f, -DEFAULT_Z_CAMERA);
 
1295
 
 
1296
        sMatrix.translate (mSAttribs.xTranslate,
 
1297
                           mSAttribs.yTranslate,
 
1298
                           mSzCamera);
 
1299
 
 
1300
        /* move origin to top left */
 
1301
        sMatrix.translate (-0.5f, 0.5f, 0.0f);
 
1302
        sMatrix.scale (mSAttribs.xScale, mSAttribs.yScale, 1.0);
 
1303
 
 
1304
        /* revert prepareXCoords region shift.
 
1305
           Now all screens display the same */
 
1306
        sMatrix.translate (0.5f, 0.5f, DEFAULT_Z_CAMERA);
 
1307
        sMatrix.translate ((float) output->x1 () / (float) output->width (),
 
1308
                           -(float) output->y2 () / (float) output->height (),
 
1309
                           0.0f);
 
1310
 
 
1311
        glScreen->glPaintTransformedOutput (attrib, sMatrix,
 
1312
                                            screen->region (), output, mask);
 
1313
        return;
 
1314
    }
 
1315
 
 
1316
    if (!moving)
 
1317
        glScreen->glPaintTransformedOutput (attrib, matrix,
 
1318
                                            region, output, mask);
 
1319
 
 
1320
    mask &= ~PAINT_SCREEN_CLEAR_MASK;
 
1321
 
 
1322
    if (moving)
 
1323
    {
 
1324
        ScreenTransformation oldTransform = transform;
 
1325
        GLMatrix             sMatrix (matrix);
 
1326
        float                xTranslate, yTranslate;
 
1327
        float                px, py;
 
1328
        bool                 movingX, movingY;
 
1329
        CompPoint            point (screen->vp ());
 
1330
        CompRegion           outputRegion (*output);
 
1331
 
 
1332
        if (clear)
 
1333
            glScreen->clearTargetOutput (GL_COLOR_BUFFER_BIT);
 
1334
 
 
1335
        transform  = Sliding;
 
1336
        currOutput = output;
 
1337
 
 
1338
        px = curPosX;
 
1339
        py = curPosY;
 
1340
 
 
1341
        movingX = ((int) floor (px)) != ((int) ceil (px));
 
1342
        movingY = ((int) floor (py)) != ((int) ceil (py));
 
1343
 
 
1344
        if (movingY)
 
1345
        {
 
1346
            yTranslate = fmod (py, 1) - 1;
 
1347
 
 
1348
            sMatrix.translate (0.0f, yTranslate, 0.0f);
 
1349
 
 
1350
            if (movingX)
 
1351
            {
 
1352
                xTranslate = 1 - fmod (px, 1);
 
1353
 
 
1354
                cScreen->setWindowPaintOffset ((point.x () - ceil (px)) *
 
1355
                                               screen->width (),
 
1356
                                               (point.y () - ceil (py)) *
 
1357
                                               screen->height ());
 
1358
 
 
1359
                sMatrix.translate (xTranslate, 0.0f, 0.0f);
 
1360
 
 
1361
                glScreen->glPaintTransformedOutput (attrib, sMatrix,
 
1362
                                                    outputRegion, output, mask);
 
1363
 
 
1364
                sMatrix.translate (-xTranslate, 0.0f, 0.0f);
 
1365
            }
 
1366
            xTranslate = -fmod (px, 1);
 
1367
 
 
1368
            cScreen->setWindowPaintOffset ((point.x () - floor (px)) *
 
1369
                                           screen->width (),
 
1370
                                           (point.y () - ceil (py)) *
 
1371
                                           screen->height ());
 
1372
 
 
1373
            sMatrix.translate (xTranslate, 0.0f, 0.0f);
 
1374
 
 
1375
            glScreen->glPaintTransformedOutput (attrib, sMatrix,
 
1376
                                                outputRegion, output, mask);
 
1377
            sMatrix.translate (-xTranslate, -yTranslate, 0.0f);
 
1378
        }
 
1379
 
 
1380
        yTranslate = fmod (py, 1);
 
1381
 
 
1382
        sMatrix.translate (0.0f, yTranslate, 0.0f);
 
1383
 
 
1384
        if (movingX)
 
1385
        {
 
1386
            xTranslate = 1 - fmod (px, 1);
 
1387
 
 
1388
            cScreen->setWindowPaintOffset ((point.x () - ceil (px)) *
 
1389
                                           screen->width (),
 
1390
                                           (point.y () - floor (py)) *
 
1391
                                           screen->height ());
 
1392
 
 
1393
            sMatrix.translate (xTranslate, 0.0f, 0.0f);
 
1394
 
 
1395
            glScreen->glPaintTransformedOutput (attrib, sMatrix,
 
1396
                                                outputRegion, output, mask);
 
1397
 
 
1398
            sMatrix.translate (-xTranslate, 0.0f, 0.0f);
 
1399
        }
 
1400
 
 
1401
        xTranslate = -fmod (px, 1);
 
1402
 
 
1403
        cScreen->setWindowPaintOffset ((point.x () - floor (px)) *
 
1404
                                       screen->width (),
 
1405
                                       (point.y () - floor (py)) *
 
1406
                                       screen->height ());
 
1407
 
 
1408
        sMatrix.translate (xTranslate, 0.0f, 0.0f);
 
1409
        glScreen->glPaintTransformedOutput (attrib, sMatrix, outputRegion,
 
1410
                                            output, mask);
 
1411
 
 
1412
        cScreen->setWindowPaintOffset (0, 0);
 
1413
        transform = oldTransform;
 
1414
    }
 
1415
}
 
1416
 
 
1417
bool
 
1418
WallWindow::glPaint (const GLWindowPaintAttrib &attrib,
 
1419
                     const GLMatrix            &matrix,
 
1420
                     const CompRegion          &region,
 
1421
                     unsigned int              mask)
 
1422
{
 
1423
    bool status;
 
1424
 
 
1425
    WALL_SCREEN (screen);
 
1426
 
 
1427
    if (ws->transform == MiniScreen)
 
1428
    {
 
1429
        GLWindowPaintAttrib pA (attrib);
 
1430
 
 
1431
        pA.opacity    = attrib.opacity *
 
1432
                        ((float) ws->mSAttribs.opacity / OPAQUE);
 
1433
        pA.brightness = attrib.brightness *
 
1434
                        ((float) ws->mSAttribs.brightness / BRIGHT);
 
1435
        pA.saturation = attrib.saturation *
 
1436
                        ((float) ws->mSAttribs.saturation / COLOR);
 
1437
 
 
1438
        if (!pA.opacity || !pA.brightness)
 
1439
            mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
 
1440
 
 
1441
        status = glWindow->glPaint (pA, matrix, region, mask);
 
1442
    }
 
1443
    else if (ws->transform == Sliding && !isSliding)
 
1444
    {
 
1445
        GLMatrix wMatrix;
 
1446
 
 
1447
        wMatrix.toScreenSpace (ws->currOutput, -DEFAULT_Z_CAMERA);
 
1448
        mask |= PAINT_WINDOW_TRANSFORMED_MASK;
 
1449
 
 
1450
        status = glWindow->glPaint (attrib, wMatrix, region, mask);
 
1451
    }
 
1452
    else
 
1453
    {
 
1454
        status = glWindow->glPaint (attrib, matrix, region, mask);
 
1455
    }
 
1456
 
 
1457
    return status;
 
1458
}
 
1459
 
 
1460
void
 
1461
WallScreen::donePaint ()
 
1462
{
 
1463
    if (moving || showPreview || boxTimeout)
 
1464
    {
 
1465
        boxTimeout = MAX (0, boxTimeout);
 
1466
        cScreen->damageScreen ();
 
1467
    }
 
1468
 
 
1469
    if (!moving && !showPreview && grabIndex)
 
1470
    {
 
1471
        screen->removeGrab (grabIndex, NULL);
 
1472
        grabIndex = 0;
 
1473
    }
 
1474
 
 
1475
    cScreen->donePaint ();
 
1476
}
 
1477
 
 
1478
void
 
1479
WallScreen::createCairoContexts (bool initial)
 
1480
{
 
1481
    int width, height;
 
1482
 
 
1483
    viewportWidth = VIEWPORT_SWITCHER_SIZE *
 
1484
                    (float) optionGetPreviewScale () / 100.0f;
 
1485
    viewportHeight = viewportWidth * (float) screen->height () /
 
1486
                     (float) screen->width ();
 
1487
    viewportBorder = optionGetBorderWidth ();
 
1488
 
 
1489
    width  = screen->vpSize ().width () * (viewportWidth + viewportBorder) +
 
1490
             viewportBorder;
 
1491
    height = screen->vpSize ().height () * (viewportHeight + viewportBorder) +
 
1492
             viewportBorder;
 
1493
 
 
1494
    destroyCairoContext (switcherContext);
 
1495
    switcherContext.width = width;
 
1496
    switcherContext.height = height;
 
1497
    setupCairoContext (switcherContext);
 
1498
    drawSwitcherBackground ();
 
1499
 
 
1500
    destroyCairoContext (thumbContext);
 
1501
    thumbContext.width = viewportWidth;
 
1502
    thumbContext.height = viewportHeight;
 
1503
    setupCairoContext (thumbContext);
 
1504
    drawThumb ();
 
1505
 
 
1506
    destroyCairoContext (highlightContext);
 
1507
    highlightContext.width = viewportWidth;
 
1508
    highlightContext.height = viewportHeight;
 
1509
    setupCairoContext (highlightContext);
 
1510
    drawHighlight ();
 
1511
 
 
1512
    if (initial)
 
1513
    {
 
1514
        arrowContext.width = ARROW_SIZE;
 
1515
        arrowContext.height = ARROW_SIZE;
 
1516
        setupCairoContext (arrowContext);
 
1517
        drawArrow ();
 
1518
    }
 
1519
}
 
1520
 
 
1521
void
 
1522
WallScreen::toggleEdges (bool enabled)
 
1523
{
 
1524
    WALL_SCREEN (screen);
 
1525
 
 
1526
    if (!enabled)
 
1527
    {
 
1528
        screen->removeAction (&ws->optionGetFlipLeftEdge ());
 
1529
        screen->removeAction (&ws->optionGetFlipUpEdge ());
 
1530
        screen->removeAction (&ws->optionGetFlipRightEdge ());
 
1531
        screen->removeAction (&ws->optionGetFlipDownEdge ());
 
1532
    }
 
1533
    else
 
1534
    {
 
1535
        screen->addAction (&ws->optionGetFlipLeftEdge ());
 
1536
        screen->addAction (&ws->optionGetFlipUpEdge ());
 
1537
        screen->addAction (&ws->optionGetFlipRightEdge ());
 
1538
        screen->addAction (&ws->optionGetFlipDownEdge ());
 
1539
    }
 
1540
}
 
1541
 
 
1542
void
 
1543
WallScreen::optionChanged (CompOption           *opt,
 
1544
                           WallOptions::Options num)
 
1545
{
 
1546
    switch(num) {
 
1547
    case WallOptions::OutlineColor:
 
1548
        drawSwitcherBackground ();
 
1549
        drawHighlight ();
 
1550
        drawThumb ();
 
1551
        break;
 
1552
 
 
1553
    case WallOptions::EdgeRadius:
 
1554
    case WallOptions::BackgroundGradientBaseColor:
 
1555
    case WallOptions::BackgroundGradientHighlightColor:
 
1556
    case WallOptions::BackgroundGradientShadowColor:
 
1557
        drawSwitcherBackground ();
 
1558
        break;
 
1559
 
 
1560
    case WallOptions::BorderWidth:
 
1561
    case WallOptions::PreviewScale:
 
1562
        createCairoContexts (false);
 
1563
        break;
 
1564
 
 
1565
    case WallOptions::ThumbGradientBaseColor:
 
1566
    case WallOptions::ThumbGradientHighlightColor:
 
1567
        drawThumb ();
 
1568
        break;
 
1569
 
 
1570
    case WallOptions::ThumbHighlightGradientBaseColor:
 
1571
    case WallOptions::ThumbHighlightGradientShadowColor:
 
1572
        drawHighlight ();
 
1573
        break;
 
1574
 
 
1575
    case WallOptions::ArrowBaseColor:
 
1576
    case WallOptions::ArrowShadowColor:
 
1577
        drawArrow ();
 
1578
        break;
 
1579
 
 
1580
    case WallOptions::NoSlideMatch:
 
1581
        foreach (CompWindow *w, screen->windows ())
 
1582
        {
 
1583
            WALL_WINDOW (w);
 
1584
            ww->isSliding = !optionGetNoSlideMatch ().evaluate (w);
 
1585
        }
 
1586
        break;
 
1587
 
 
1588
    default:
 
1589
        break;
 
1590
    }
 
1591
}
 
1592
 
 
1593
bool
 
1594
WallScreen::setOptionForPlugin (const char        *plugin,
 
1595
                                const char        *name,
 
1596
                                CompOption::Value &value)
 
1597
{
 
1598
    bool status = screen->setOptionForPlugin (plugin, name, value);
 
1599
 
 
1600
    if (strcmp (plugin, "core") == 0)
 
1601
    {
 
1602
        if (strcmp (name, "hsize") == 0 || strcmp (name, "vsize") == 0)
 
1603
        {
 
1604
            createCairoContexts (false);
 
1605
        }
 
1606
    }
 
1607
 
 
1608
    return status;
 
1609
}
 
1610
 
 
1611
void
 
1612
WallScreen::matchExpHandlerChanged ()
 
1613
{
 
1614
    screen->matchExpHandlerChanged ();
 
1615
 
 
1616
    foreach (CompWindow *w, screen->windows ())
 
1617
    {
 
1618
        WALL_WINDOW (w);
 
1619
        ww->isSliding = !optionGetNoSlideMatch ().evaluate (w);
 
1620
    }
 
1621
}
 
1622
 
 
1623
void
 
1624
WallScreen::matchPropertyChanged (CompWindow *window)
 
1625
{
 
1626
    WALL_WINDOW (window);
 
1627
 
 
1628
    screen->matchPropertyChanged (window);
 
1629
 
 
1630
    ww->isSliding = !optionGetNoSlideMatch ().evaluate (window);
 
1631
}
 
1632
 
 
1633
WallScreen::WallScreen (CompScreen *screen) :
 
1634
    PluginClassHandler <WallScreen, CompScreen> (screen),
 
1635
    WallOptions (),
 
1636
    cScreen (CompositeScreen::get (screen)),
 
1637
    glScreen (GLScreen::get (screen)),
 
1638
    moving (false),
 
1639
    showPreview (false),
 
1640
    direction (-1),
 
1641
    boxTimeout (0),
 
1642
    grabIndex (0),
 
1643
    timer (0),
 
1644
    moveWindow (None),
 
1645
    focusDefault (true),
 
1646
    transform (NoTransformation)
 
1647
{
 
1648
    ScreenInterface::setHandler (screen);
 
1649
    CompositeScreenInterface::setHandler (cScreen);
 
1650
    GLScreenInterface::setHandler (glScreen);
 
1651
 
 
1652
    // HACK: we have to keep libcairo loaded even if wall gets unloaded
 
1653
    // to prevent crashes in XCloseDisplay
 
1654
    dlopen ("libcairo.so.2", RTLD_LAZY);
 
1655
 
 
1656
    memset (&switcherContext, 0, sizeof (WallCairoContext));
 
1657
    memset (&thumbContext, 0, sizeof (WallCairoContext));
 
1658
    memset (&highlightContext, 0, sizeof (WallCairoContext));
 
1659
    memset (&arrowContext, 0, sizeof (WallCairoContext));
 
1660
    createCairoContexts (true);
 
1661
 
 
1662
#define setAction(action, dir, win) \
 
1663
    optionSet##action##Initiate (boost::bind (&WallScreen::initiate, this,   \
 
1664
                                              _1, _2, _3, dir, win));        \
 
1665
    optionSet##action##Terminate (boost::bind (&WallScreen::terminate, this, \
 
1666
                                               _1, _2, _3))
 
1667
 
 
1668
#define setFlipAction(action, dir) \
 
1669
    optionSet##action##Initiate (boost::bind (&WallScreen::initiateFlip, \
 
1670
                                              this, dir, _2))
 
1671
 
 
1672
    setAction (LeftKey, Left, false);
 
1673
    setAction (RightKey, Right, false);
 
1674
    setAction (UpKey, Up, false);
 
1675
    setAction (DownKey, Down, false);
 
1676
    setAction (NextKey, Next, false);
 
1677
    setAction (PrevKey, Prev, false);
 
1678
    setAction (LeftButton, Left, false);
 
1679
    setAction (RightButton, Right, false);
 
1680
    setAction (UpButton, Up, false);
 
1681
    setAction (DownButton, Down, false);
 
1682
    setAction (NextButton, Next, false);
 
1683
    setAction (PrevButton, Prev, false);
 
1684
    setAction (LeftWindowKey, Left, true);
 
1685
    setAction (RightWindowKey, Right, true);
 
1686
    setAction (UpWindowKey, Up, true);
 
1687
    setAction (DownWindowKey, Down, true);
 
1688
 
 
1689
    setFlipAction (FlipLeftEdge, Left);
 
1690
    setFlipAction (FlipRightEdge, Right);
 
1691
    setFlipAction (FlipUpEdge, Up);
 
1692
    setFlipAction (FlipDownEdge, Down);
 
1693
 
 
1694
#define setNotify(func) \
 
1695
    optionSet##func##Notify (boost::bind (&WallScreen::optionChanged, \
 
1696
                                          this, _1, _2))
 
1697
 
 
1698
    setNotify (EdgeRadius);
 
1699
    setNotify (BorderWidth);
 
1700
    setNotify (PreviewScale);
 
1701
    setNotify (OutlineColor);
 
1702
    setNotify (BackgroundGradientBaseColor);
 
1703
    setNotify (BackgroundGradientHighlightColor);
 
1704
    setNotify (BackgroundGradientShadowColor);
 
1705
    setNotify (ThumbGradientBaseColor);
 
1706
    setNotify (ThumbGradientHighlightColor);
 
1707
    setNotify (ThumbHighlightGradientBaseColor);
 
1708
    setNotify (ThumbHighlightGradientShadowColor);
 
1709
    setNotify (ArrowBaseColor);
 
1710
    setNotify (ArrowShadowColor);
 
1711
    setNotify (NoSlideMatch);
 
1712
    setNotify (EdgeflipPointer);
 
1713
 
 
1714
    updateScreenEdgeRegions ();
 
1715
 
 
1716
    poller.setCallback (boost::bind (&WallScreen::positionUpdate, this,
 
1717
                                     _1));
 
1718
}
 
1719
 
 
1720
WallScreen::~WallScreen ()
 
1721
{
 
1722
    destroyCairoContext (switcherContext);
 
1723
    destroyCairoContext (thumbContext);
 
1724
    destroyCairoContext (highlightContext);
 
1725
    destroyCairoContext (arrowContext);
 
1726
}
 
1727
 
 
1728
WallWindow::WallWindow (CompWindow *window) :
 
1729
    PluginClassHandler <WallWindow, CompWindow> (window),
 
1730
    window (window),
 
1731
    glWindow (GLWindow::get (window))
 
1732
{
 
1733
    WALL_SCREEN (screen);
 
1734
 
 
1735
    isSliding = !ws->optionGetNoSlideMatch ().evaluate (window);
 
1736
 
 
1737
    GLWindowInterface::setHandler (glWindow);
 
1738
    WindowInterface::setHandler (window);
 
1739
}
 
1740
 
 
1741
bool
 
1742
WallPluginVTable::init ()
 
1743
{
 
1744
    if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
 
1745
        return false;
 
1746
    if (!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI))
 
1747
        return false;
 
1748
    if (!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
 
1749
        return false;
 
1750
    if (!CompPlugin::checkPluginABI ("mousepoll", COMPIZ_MOUSEPOLL_ABI))
 
1751
        return false;
 
1752
 
 
1753
    return true;
 
1754
}
 
1755