~alan-griffiths/compiz-core/Bug-931283

« back to all changes in this revision

Viewing changes to plugins/rotate.c

  • Committer: David Reveman
  • Date: 2006-02-09 06:03:09 UTC
  • Revision ID: git-v1:9959c2b13ded64a5e66359a8097250dc9d87fc1c
Initial revision

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 <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
#include <math.h>
 
30
#include <sys/time.h>
 
31
 
 
32
#include <X11/Xatom.h>
 
33
#include <X11/Xproto.h>
 
34
 
 
35
#include <compiz.h>
 
36
 
 
37
#define ROTATE_POINTER_INVERT_Y_DEFAULT FALSE
 
38
 
 
39
#define ROTATE_POINTER_SENSITIVITY_DEFAULT   1.0f
 
40
#define ROTATE_POINTER_SENSITIVITY_MIN       0.01f
 
41
#define ROTATE_POINTER_SENSITIVITY_MAX       100.0f
 
42
#define ROTATE_POINTER_SENSITIVITY_PRECISION 0.01f
 
43
 
 
44
#define ROTATE_POINTER_SENSITIVITY_FACTOR 0.05f
 
45
 
 
46
#define ROTATE_ACCELERATION_DEFAULT   4.0f
 
47
#define ROTATE_ACCELERATION_MIN       1.0f
 
48
#define ROTATE_ACCELERATION_MAX       20.0f
 
49
#define ROTATE_ACCELERATION_PRECISION 0.1f
 
50
 
 
51
#define ROTATE_INITIATE_BUTTON_DEFAULT    Button1
 
52
#define ROTATE_INITIATE_MODIFIERS_DEFAULT       \
 
53
    (CompPressMask | ControlMask | CompAltMask)
 
54
 
 
55
#define ROTATE_TERMINATE_BUTTON_DEFAULT    Button1
 
56
#define ROTATE_TERMINATE_MODIFIERS_DEFAULT CompReleaseMask
 
57
 
 
58
#define ROTATE_LEFT_KEY_DEFAULT       "Left"
 
59
#define ROTATE_LEFT_MODIFIERS_DEFAULT           \
 
60
    (CompPressMask | ControlMask | CompAltMask)
 
61
 
 
62
#define ROTATE_RIGHT_KEY_DEFAULT       "Right"
 
63
#define ROTATE_RIGHT_MODIFIERS_DEFAULT          \
 
64
    (CompPressMask | ControlMask | CompAltMask)
 
65
 
 
66
#define ROTATE_LEFT_WINDOW_KEY_DEFAULT       "Left"
 
67
#define ROTATE_LEFT_WINDOW_MODIFIERS_DEFAULT                \
 
68
    (CompPressMask | ShiftMask | ControlMask | CompAltMask)
 
69
 
 
70
#define ROTATE_RIGHT_WINDOW_KEY_DEFAULT       "Right"
 
71
#define ROTATE_RIGHT_WINDOW_MODIFIERS_DEFAULT               \
 
72
    (CompPressMask | ShiftMask | ControlMask | CompAltMask)
 
73
 
 
74
#define ROTATE_SNAP_TOP_DEFAULT FALSE
 
75
 
 
76
#define ROTATE_SPEED_DEFAULT   1.5f
 
77
#define ROTATE_SPEED_MIN       0.1f
 
78
#define ROTATE_SPEED_MAX       50.0f
 
79
#define ROTATE_SPEED_PRECISION 0.1f
 
80
 
 
81
#define ROTATE_TIMESTEP_DEFAULT   1.2f
 
82
#define ROTATE_TIMESTEP_MIN       0.1f
 
83
#define ROTATE_TIMESTEP_MAX       50.0f
 
84
#define ROTATE_TIMESTEP_PRECISION 0.1f
 
85
 
 
86
static int displayPrivateIndex;
 
87
 
 
88
typedef struct _RotateDisplay {
 
89
    int             screenPrivateIndex;
 
90
    HandleEventProc handleEvent;
 
91
} RotateDisplay;
 
92
 
 
93
#define ROTATE_SCREEN_OPTION_POINTER_INVERT_Y    0
 
94
#define ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY 1
 
95
#define ROTATE_SCREEN_OPTION_ACCELERATION        2
 
96
#define ROTATE_SCREEN_OPTION_INITIATE            3
 
97
#define ROTATE_SCREEN_OPTION_TERMINATE           4
 
98
#define ROTATE_SCREEN_OPTION_LEFT                5
 
99
#define ROTATE_SCREEN_OPTION_RIGHT               6
 
100
#define ROTATE_SCREEN_OPTION_LEFT_WINDOW         7
 
101
#define ROTATE_SCREEN_OPTION_RIGHT_WINDOW        8
 
102
#define ROTATE_SCREEN_OPTION_SNAP_TOP            9
 
103
#define ROTATE_SCREEN_OPTION_SPEED               10
 
104
#define ROTATE_SCREEN_OPTION_TIMESTEP            11
 
105
#define ROTATE_SCREEN_OPTION_NUM                 12
 
106
 
 
107
typedef struct _RotateScreen {
 
108
    PreparePaintScreenProc       preparePaintScreen;
 
109
    DonePaintScreenProc          donePaintScreen;
 
110
    PaintScreenProc              paintScreen;
 
111
    SetScreenOptionForPluginProc setScreenOptionForPlugin;
 
112
 
 
113
    CompOption opt[ROTATE_SCREEN_OPTION_NUM];
 
114
 
 
115
    Bool  pointerInvertY;
 
116
    float pointerSensitivity;
 
117
    Bool  snapTop;
 
118
    float acceleration;
 
119
 
 
120
    float speed;
 
121
    float timestep;
 
122
 
 
123
    int grabIndex;
 
124
 
 
125
    GLfloat xrot, xVelocity;
 
126
    GLfloat yrot, yVelocity;
 
127
 
 
128
    GLfloat baseXrot;
 
129
 
 
130
    Bool    moving;
 
131
    GLfloat moveTo;
 
132
 
 
133
    int invert;
 
134
 
 
135
    Window moveWindow;
 
136
    int    moveWindowX;
 
137
 
 
138
    int    prevPointerX;
 
139
    int    prevPointerY;
 
140
    XPoint savedPointer;
 
141
    Bool   grabbed;
 
142
} RotateScreen;
 
143
 
 
144
#define GET_ROTATE_DISPLAY(d)                                  \
 
145
    ((RotateDisplay *) (d)->privates[displayPrivateIndex].ptr)
 
146
 
 
147
#define ROTATE_DISPLAY(d)                      \
 
148
    RotateDisplay *rd = GET_ROTATE_DISPLAY (d)
 
149
 
 
150
#define GET_ROTATE_SCREEN(s, rd)                                   \
 
151
    ((RotateScreen *) (s)->privates[(rd)->screenPrivateIndex].ptr)
 
152
 
 
153
#define ROTATE_SCREEN(s)                                                      \
 
154
    RotateScreen *rs = GET_ROTATE_SCREEN (s, GET_ROTATE_DISPLAY (s->display))
 
155
 
 
156
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
 
157
 
 
158
static CompOption *
 
159
rotateGetScreenOptions (CompScreen *screen,
 
160
                        int        *count)
 
161
{
 
162
    ROTATE_SCREEN (screen);
 
163
 
 
164
    *count = NUM_OPTIONS (rs);
 
165
    return rs->opt;
 
166
}
 
167
 
 
168
static Bool
 
169
rotateSetScreenOption (CompScreen      *screen,
 
170
                       char            *name,
 
171
                       CompOptionValue *value)
 
172
{
 
173
    CompOption *o;
 
174
    int        index;
 
175
 
 
176
    ROTATE_SCREEN (screen);
 
177
 
 
178
    o = compFindOption (rs->opt, NUM_OPTIONS (rs), name, &index);
 
179
    if (!o)
 
180
        return FALSE;
 
181
 
 
182
    switch (index) {
 
183
    case ROTATE_SCREEN_OPTION_POINTER_INVERT_Y:
 
184
        if (compSetBoolOption (o, value))
 
185
        {
 
186
            rs->pointerInvertY = o->value.b;
 
187
            return TRUE;
 
188
        }
 
189
        break;
 
190
    case ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY:
 
191
        if (compSetFloatOption (o, value))
 
192
        {
 
193
            rs->pointerSensitivity = o->value.f *
 
194
                ROTATE_POINTER_SENSITIVITY_FACTOR;
 
195
            return TRUE;
 
196
        }
 
197
        break;
 
198
    case ROTATE_SCREEN_OPTION_ACCELERATION:
 
199
        if (compSetFloatOption (o, value))
 
200
        {
 
201
            rs->acceleration = o->value.f;
 
202
            return TRUE;
 
203
        }
 
204
        break;
 
205
    case ROTATE_SCREEN_OPTION_INITIATE:
 
206
    case ROTATE_SCREEN_OPTION_LEFT:
 
207
    case ROTATE_SCREEN_OPTION_RIGHT:
 
208
    case ROTATE_SCREEN_OPTION_LEFT_WINDOW:
 
209
    case ROTATE_SCREEN_OPTION_RIGHT_WINDOW:
 
210
        if (addScreenBinding (screen, &value->bind))
 
211
        {
 
212
            removeScreenBinding (screen, &o->value.bind);
 
213
 
 
214
            if (compSetBindingOption (o, value))
 
215
                return TRUE;
 
216
        }
 
217
        break;
 
218
    case ROTATE_SCREEN_OPTION_TERMINATE:
 
219
        if (compSetBindingOption (o, value))
 
220
            return TRUE;
 
221
        break;
 
222
    case ROTATE_SCREEN_OPTION_SNAP_TOP:
 
223
        if (compSetBoolOption (o, value))
 
224
        {
 
225
            rs->snapTop = o->value.b;
 
226
            return TRUE;
 
227
        }
 
228
        break;
 
229
    case ROTATE_SCREEN_OPTION_SPEED:
 
230
        if (compSetFloatOption (o, value))
 
231
        {
 
232
            rs->speed = o->value.f;
 
233
            return TRUE;
 
234
        }
 
235
        break;
 
236
    case ROTATE_SCREEN_OPTION_TIMESTEP:
 
237
        if (compSetFloatOption (o, value))
 
238
        {
 
239
            rs->timestep = o->value.f;
 
240
            return TRUE;
 
241
        }
 
242
        break;
 
243
    default:
 
244
        break;
 
245
    }
 
246
 
 
247
    return FALSE;
 
248
}
 
249
 
 
250
static void
 
251
rotateScreenInitOptions (RotateScreen *rs,
 
252
                         Display      *display)
 
253
{
 
254
    CompOption *o;
 
255
 
 
256
    o = &rs->opt[ROTATE_SCREEN_OPTION_POINTER_INVERT_Y];
 
257
    o->name      = "invert_y";
 
258
    o->shortDesc = "Pointer Invert Y";
 
259
    o->longDesc  = "Invert Y axis for pointer movement";
 
260
    o->type      = CompOptionTypeBool;
 
261
    o->value.b   = ROTATE_POINTER_INVERT_Y_DEFAULT;
 
262
 
 
263
    o = &rs->opt[ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY];
 
264
    o->name             = "sensitivity";
 
265
    o->shortDesc        = "Pointer Sensitivity";
 
266
    o->longDesc         = "Sensitivity of pointer movement";
 
267
    o->type             = CompOptionTypeFloat;
 
268
    o->value.f          = ROTATE_POINTER_SENSITIVITY_DEFAULT;
 
269
    o->rest.f.min       = ROTATE_POINTER_SENSITIVITY_MIN;
 
270
    o->rest.f.max       = ROTATE_POINTER_SENSITIVITY_MAX;
 
271
    o->rest.f.precision = ROTATE_POINTER_SENSITIVITY_PRECISION;
 
272
 
 
273
    o = &rs->opt[ROTATE_SCREEN_OPTION_ACCELERATION];
 
274
    o->name             = "acceleration";
 
275
    o->shortDesc        = "Acceleration";
 
276
    o->longDesc         = "Rotation Acceleration";
 
277
    o->type             = CompOptionTypeFloat;
 
278
    o->value.f          = ROTATE_ACCELERATION_DEFAULT;
 
279
    o->rest.f.min       = ROTATE_ACCELERATION_MIN;
 
280
    o->rest.f.max       = ROTATE_ACCELERATION_MAX;
 
281
    o->rest.f.precision = ROTATE_ACCELERATION_PRECISION;
 
282
 
 
283
    o = &rs->opt[ROTATE_SCREEN_OPTION_INITIATE];
 
284
    o->name                          = "initiate";
 
285
    o->shortDesc                     = "Initiate";
 
286
    o->longDesc                      = "Start Rotation";
 
287
    o->type                          = CompOptionTypeBinding;
 
288
    o->value.bind.type               = CompBindingTypeButton;
 
289
    o->value.bind.u.button.modifiers = ROTATE_INITIATE_MODIFIERS_DEFAULT;
 
290
    o->value.bind.u.button.button    = ROTATE_INITIATE_BUTTON_DEFAULT;
 
291
 
 
292
    o = &rs->opt[ROTATE_SCREEN_OPTION_TERMINATE];
 
293
    o->name                          = "terminate";
 
294
    o->shortDesc                     = "Terminate";
 
295
    o->longDesc                      = "Stop Rotation";
 
296
    o->type                          = CompOptionTypeBinding;
 
297
    o->value.bind.type               = CompBindingTypeButton;
 
298
    o->value.bind.u.button.modifiers = ROTATE_TERMINATE_MODIFIERS_DEFAULT;
 
299
    o->value.bind.u.button.button    = ROTATE_TERMINATE_BUTTON_DEFAULT;
 
300
 
 
301
    o = &rs->opt[ROTATE_SCREEN_OPTION_LEFT];
 
302
    o->name                       = "rotate_left";
 
303
    o->shortDesc                  = "Rotate Left";
 
304
    o->longDesc                   = "Rotate left";
 
305
    o->type                       = CompOptionTypeBinding;
 
306
    o->value.bind.type            = CompBindingTypeKey;
 
307
    o->value.bind.u.key.modifiers = ROTATE_LEFT_MODIFIERS_DEFAULT;
 
308
    o->value.bind.u.key.keycode   =
 
309
        XKeysymToKeycode (display,
 
310
                          XStringToKeysym (ROTATE_LEFT_KEY_DEFAULT));
 
311
 
 
312
    o = &rs->opt[ROTATE_SCREEN_OPTION_RIGHT];
 
313
    o->name                       = "rotate_right";
 
314
    o->shortDesc                  = "Rotate Right";
 
315
    o->longDesc                   = "Rotate right";
 
316
    o->type                       = CompOptionTypeBinding;
 
317
    o->value.bind.type            = CompBindingTypeKey;
 
318
    o->value.bind.u.key.modifiers = ROTATE_RIGHT_MODIFIERS_DEFAULT;
 
319
    o->value.bind.u.key.keycode   =
 
320
        XKeysymToKeycode (display,
 
321
                          XStringToKeysym (ROTATE_RIGHT_KEY_DEFAULT));
 
322
 
 
323
    o = &rs->opt[ROTATE_SCREEN_OPTION_LEFT_WINDOW];
 
324
    o->name                       = "rotate_left_window";
 
325
    o->shortDesc                  = "Rotate Left with Window";
 
326
    o->longDesc                   = "Rotate left and bring active window "
 
327
        "along";
 
328
    o->type                       = CompOptionTypeBinding;
 
329
    o->value.bind.type            = CompBindingTypeKey;
 
330
    o->value.bind.u.key.modifiers = ROTATE_LEFT_WINDOW_MODIFIERS_DEFAULT;
 
331
    o->value.bind.u.key.keycode   =
 
332
                XKeysymToKeycode (display,
 
333
                          XStringToKeysym (ROTATE_LEFT_WINDOW_KEY_DEFAULT));
 
334
 
 
335
    o = &rs->opt[ROTATE_SCREEN_OPTION_RIGHT_WINDOW];
 
336
    o->name                       = "rotate_right_window";
 
337
    o->shortDesc                  = "Rotate Right with Window";
 
338
    o->longDesc                   = "Rotate right and bring active window "
 
339
        "along";
 
340
    o->type                       = CompOptionTypeBinding;
 
341
    o->value.bind.type            = CompBindingTypeKey;
 
342
    o->value.bind.u.key.modifiers = ROTATE_RIGHT_WINDOW_MODIFIERS_DEFAULT;
 
343
    o->value.bind.u.key.keycode   =
 
344
        XKeysymToKeycode (display,
 
345
                          XStringToKeysym (ROTATE_RIGHT_WINDOW_KEY_DEFAULT));
 
346
 
 
347
    o = &rs->opt[ROTATE_SCREEN_OPTION_SNAP_TOP];
 
348
    o->name      = "snap_top";
 
349
    o->shortDesc = "Snap To Top Face";
 
350
    o->longDesc  = "Snap Cube Rotation to Top Face";
 
351
    o->type      = CompOptionTypeBool;
 
352
    o->value.b   = ROTATE_SNAP_TOP_DEFAULT;
 
353
 
 
354
    o = &rs->opt[ROTATE_SCREEN_OPTION_SPEED];
 
355
    o->name             = "speed";
 
356
    o->shortDesc        = "Speed";
 
357
    o->longDesc         = "Rotation Speed";
 
358
    o->type             = CompOptionTypeFloat;
 
359
    o->value.f          = ROTATE_SPEED_DEFAULT;
 
360
    o->rest.f.min       = ROTATE_SPEED_MIN;
 
361
    o->rest.f.max       = ROTATE_SPEED_MAX;
 
362
    o->rest.f.precision = ROTATE_SPEED_PRECISION;
 
363
 
 
364
    o = &rs->opt[ROTATE_SCREEN_OPTION_TIMESTEP];
 
365
    o->name             = "timestep";
 
366
    o->shortDesc        = "Timestep";
 
367
    o->longDesc         = "Rotation Timestep";
 
368
    o->type             = CompOptionTypeFloat;
 
369
    o->value.f          = ROTATE_TIMESTEP_DEFAULT;
 
370
    o->rest.f.min       = ROTATE_TIMESTEP_MIN;
 
371
    o->rest.f.max       = ROTATE_TIMESTEP_MAX;
 
372
    o->rest.f.precision = ROTATE_TIMESTEP_PRECISION;
 
373
}
 
374
 
 
375
static int
 
376
adjustVelocity (RotateScreen *rs,
 
377
                int          size)
 
378
{
 
379
    float xrot, yrot, adjust, amount;
 
380
 
 
381
    if (rs->moving)
 
382
    {
 
383
        xrot = rs->moveTo + (rs->xrot + rs->baseXrot);
 
384
    }
 
385
    else
 
386
    {
 
387
        xrot = rs->xrot;
 
388
        if (rs->xrot < -180.0f / size)
 
389
            xrot = 360.0f / size + rs->xrot;
 
390
        else if (rs->xrot > 180.0f / size)
 
391
            xrot = rs->xrot - 360.0f / size;
 
392
    }
 
393
 
 
394
    adjust = -xrot * 0.05f * rs->acceleration;
 
395
    amount = fabs (xrot);
 
396
    if (amount < 10.0f)
 
397
        amount = 10.0f;
 
398
    else if (amount > 30.0f)
 
399
        amount = 30.0f;
 
400
 
 
401
    rs->xVelocity = (amount * rs->xVelocity + adjust) / (amount + 2.0f);
 
402
 
 
403
    if (rs->snapTop && rs->yrot > 50.0f)
 
404
        yrot = -(90.f - rs->yrot);
 
405
    else
 
406
        yrot = rs->yrot;
 
407
 
 
408
    adjust = -yrot * 0.05f * rs->acceleration;
 
409
    amount = fabs (rs->yrot);
 
410
    if (amount < 10.0f)
 
411
        amount = 10.0f;
 
412
    else if (amount > 30.0f)
 
413
        amount = 30.0f;
 
414
 
 
415
    rs->yVelocity = (amount * rs->yVelocity + adjust) / (amount + 2.0f);
 
416
 
 
417
    return (fabs (xrot) < 0.1f && fabs (rs->xVelocity) < 0.2f &&
 
418
            fabs (yrot) < 0.1f && fabs (rs->yVelocity) < 0.2f);
 
419
}
 
420
 
 
421
static void
 
422
rotatePreparePaintScreen (CompScreen *s,
 
423
                          int        msSinceLastPaint)
 
424
{
 
425
    ROTATE_SCREEN (s);
 
426
 
 
427
    if (rs->grabIndex)
 
428
    {
 
429
        int   steps;
 
430
        float amount, chunk;
 
431
 
 
432
        amount = msSinceLastPaint * 0.05f * rs->speed;
 
433
        steps  = amount / (0.5f * rs->timestep);
 
434
        if (!steps) steps = 1;
 
435
        chunk  = amount / (float) steps;
 
436
 
 
437
        while (steps--)
 
438
        {
 
439
            rs->xrot += rs->xVelocity * chunk;
 
440
            rs->yrot += rs->yVelocity * chunk;
 
441
 
 
442
            if (rs->xrot > 360.0f / s->size)
 
443
            {
 
444
                rs->baseXrot += 360.0f / s->size;
 
445
                rs->xrot -= 360.0f / s->size;
 
446
            }
 
447
            else if (rs->xrot < 0.0f)
 
448
            {
 
449
                rs->baseXrot -= 360.0f / s->size;
 
450
                rs->xrot += 360.0f / s->size;
 
451
            }
 
452
 
 
453
            if (rs->invert == -1)
 
454
            {
 
455
                if (rs->yrot > 45.0f)
 
456
                {
 
457
                    rs->yVelocity = 0.0f;
 
458
                    rs->yrot = 45.0f;
 
459
                }
 
460
                else if (rs->yrot < -45.0f)
 
461
                {
 
462
                    rs->yVelocity = 0.0f;
 
463
                    rs->yrot = -45.0f;
 
464
                }
 
465
            }
 
466
            else
 
467
            {
 
468
                if (rs->yrot > 100.0f)
 
469
                {
 
470
                    rs->yVelocity = 0.0f;
 
471
                    rs->yrot = 100.0f;
 
472
                }
 
473
                else if (rs->yrot < -100.0f)
 
474
                {
 
475
                    rs->yVelocity = 0.0f;
 
476
                    rs->yrot = -100.0f;
 
477
                }
 
478
            }
 
479
 
 
480
            if (rs->grabbed)
 
481
            {
 
482
                rs->xVelocity /= 1.25f;
 
483
                rs->yVelocity /= 1.25f;
 
484
 
 
485
                if (fabs (rs->xVelocity) < 0.01f)
 
486
                    rs->xVelocity = 0.0f;
 
487
                if (fabs (rs->yVelocity) < 0.01f)
 
488
                    rs->yVelocity = 0.0f;
 
489
            }
 
490
            else if (adjustVelocity (rs, s->size))
 
491
            {
 
492
                rs->xVelocity = 0.0f;
 
493
                rs->yVelocity = 0.0f;
 
494
 
 
495
                if (fabs (rs->yrot) < 0.1f)
 
496
                {
 
497
                    float xrot;
 
498
                    int   tx;
 
499
 
 
500
                    xrot = rs->baseXrot + rs->xrot;
 
501
                    if (xrot < 0.0f)
 
502
                        tx = (s->size * xrot / 360.0f) - 0.5f;
 
503
                    else
 
504
                        tx = (s->size * xrot / 360.0f) + 0.5f;
 
505
 
 
506
                    moveScreenViewport (s, tx, TRUE);
 
507
 
 
508
                    rs->xrot = 0.0f;
 
509
                    rs->yrot = 0.0f;
 
510
                    rs->baseXrot = rs->moveTo = 0.0f;
 
511
                    rs->moving = FALSE;
 
512
 
 
513
                    removeScreenGrab (s, rs->grabIndex, &rs->savedPointer);
 
514
                    rs->grabIndex = 0;
 
515
 
 
516
                    if (rs->moveWindow)
 
517
                    {
 
518
                        CompWindow *w;
 
519
 
 
520
                        w = findWindowAtScreen (s, rs->moveWindow);
 
521
                        if (w)
 
522
                        {
 
523
                            moveWindow (w, w->attrib.x - rs->moveWindowX, 0,
 
524
                                        TRUE);
 
525
                            syncWindowPosition (w);
 
526
                        }
 
527
                    }
 
528
                    else
 
529
                        focusDefaultWindow (s->display);
 
530
 
 
531
                    rs->moveWindow = 0;
 
532
                }
 
533
                break;
 
534
            }
 
535
        }
 
536
 
 
537
        if (rs->moveWindow)
 
538
        {
 
539
            CompWindow *w;
 
540
 
 
541
            w = findWindowAtScreen (s, rs->moveWindow);
 
542
            if (w)
 
543
            {
 
544
                float xrot = (s->size * (rs->baseXrot + rs->xrot)) / 360.0f;
 
545
 
 
546
                moveWindowToViewportPosition (w,
 
547
                                              rs->moveWindowX - xrot * s->width,
 
548
                                              FALSE);
 
549
            }
 
550
        }
 
551
    }
 
552
 
 
553
    UNWRAP (rs, s, preparePaintScreen);
 
554
    (*s->preparePaintScreen) (s, msSinceLastPaint);
 
555
    WRAP (rs, s, preparePaintScreen, rotatePreparePaintScreen);
 
556
}
 
557
 
 
558
static void
 
559
rotateDonePaintScreen (CompScreen *s)
 
560
{
 
561
    ROTATE_SCREEN (s);
 
562
 
 
563
    if (rs->grabIndex)
 
564
    {
 
565
        if ((!rs->grabbed && !rs->snapTop) || rs->xVelocity || rs->yVelocity)
 
566
            damageScreen (s);
 
567
    }
 
568
 
 
569
    UNWRAP (rs, s, donePaintScreen);
 
570
    (*s->donePaintScreen) (s);
 
571
    WRAP (rs, s, donePaintScreen, rotateDonePaintScreen);
 
572
}
 
573
 
 
574
static Bool
 
575
rotatePaintScreen (CompScreen              *s,
 
576
                   const ScreenPaintAttrib *sAttrib,
 
577
                   Region                  region,
 
578
                   unsigned int            mask)
 
579
{
 
580
    Bool status;
 
581
 
 
582
    ROTATE_SCREEN (s);
 
583
 
 
584
    if (rs->grabIndex)
 
585
    {
 
586
        ScreenPaintAttrib sa = *sAttrib;
 
587
 
 
588
        sa.xRotate += rs->baseXrot + rs->xrot;
 
589
        sa.vRotate += rs->yrot;
 
590
 
 
591
        mask &= ~PAINT_SCREEN_REGION_MASK;
 
592
        mask |= PAINT_SCREEN_TRANSFORMED_MASK;
 
593
 
 
594
        UNWRAP (rs, s, paintScreen);
 
595
        status = (*s->paintScreen) (s, &sa, region, mask);
 
596
        WRAP (rs, s, paintScreen, rotatePaintScreen);
 
597
    }
 
598
    else
 
599
    {
 
600
        UNWRAP (rs, s, paintScreen);
 
601
        status = (*s->paintScreen) (s, sAttrib, region, mask);
 
602
        WRAP (rs, s, paintScreen, rotatePaintScreen);
 
603
    }
 
604
 
 
605
    return status;
 
606
}
 
607
 
 
608
static void
 
609
rotateInitiate (CompScreen *s,
 
610
                int        x,
 
611
                int        y)
 
612
{
 
613
    ROTATE_SCREEN (s);
 
614
 
 
615
    rs->prevPointerX = x;
 
616
    rs->prevPointerY = y;
 
617
 
 
618
    rs->moving = FALSE;
 
619
 
 
620
    /* some other plugin have already grabbed the screen */
 
621
    if (s->maxGrab - rs->grabIndex)
 
622
        return;
 
623
 
 
624
    if (!rs->grabIndex)
 
625
    {
 
626
        rs->grabIndex = pushScreenGrab (s, s->invisibleCursor);
 
627
        if (rs->grabIndex)
 
628
        {
 
629
            rs->savedPointer.x = rs->prevPointerX;
 
630
            rs->savedPointer.y = rs->prevPointerY;
 
631
        }
 
632
    }
 
633
 
 
634
    if (rs->grabIndex)
 
635
    {
 
636
        rs->grabbed = TRUE;
 
637
        rs->snapTop = rs->opt[ROTATE_SCREEN_OPTION_SNAP_TOP].value.b;
 
638
    }
 
639
}
 
640
 
 
641
static void
 
642
rotate (CompScreen *s,
 
643
        int        x,
 
644
        int        y,
 
645
        int        direction)
 
646
{
 
647
    ROTATE_SCREEN (s);
 
648
 
 
649
    if (!rs->grabIndex)
 
650
        rotateInitiate (s, x, y);
 
651
 
 
652
    if (rs->grabIndex)
 
653
    {
 
654
        rs->moving  = TRUE;
 
655
        rs->moveTo += (360.0f / s->size) * direction;
 
656
        rs->grabbed = FALSE;
 
657
 
 
658
        damageScreen (s);
 
659
    }
 
660
}
 
661
 
 
662
static void
 
663
rotateWithWindow (CompScreen *s,
 
664
                  int        x,
 
665
                  int        y,
 
666
                  int        direction)
 
667
{
 
668
    CompWindow *w;
 
669
 
 
670
    ROTATE_SCREEN (s);
 
671
 
 
672
    if (!rs->grabIndex)
 
673
    {
 
674
        for (w = s->windows; w; w = w->next)
 
675
            if (s->display->activeWindow == w->id)
 
676
                break;
 
677
 
 
678
        if (!w)
 
679
            return;
 
680
 
 
681
        if (w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
 
682
            return;
 
683
 
 
684
        if (w->state & CompWindowStateStickyMask)
 
685
            return;
 
686
 
 
687
        rotateInitiate (s, x, y);
 
688
 
 
689
        rs->moveWindow  = w->id;
 
690
        rs->moveWindowX = w->attrib.x;
 
691
    }
 
692
 
 
693
    if (rs->grabIndex)
 
694
    {
 
695
        rs->moving  = TRUE;
 
696
        rs->moveTo += (360.0f / s->size) * direction;
 
697
        rs->grabbed = FALSE;
 
698
 
 
699
        damageScreen (s);
 
700
    }
 
701
}
 
702
 
 
703
static void
 
704
rotateTerminate (CompScreen *s)
 
705
{
 
706
    ROTATE_SCREEN (s);
 
707
 
 
708
    if (rs->grabIndex)
 
709
    {
 
710
        rs->grabbed = FALSE;
 
711
        damageScreen (s);
 
712
    }
 
713
}
 
714
 
 
715
static void
 
716
rotateHandleEvent (CompDisplay *d,
 
717
                   XEvent      *event)
 
718
{
 
719
    CompScreen *s;
 
720
 
 
721
    ROTATE_DISPLAY (d);
 
722
 
 
723
    switch (event->type) {
 
724
    case KeyPress:
 
725
    case KeyRelease:
 
726
        s = findScreenAtDisplay (d, event->xkey.root);
 
727
        if (s)
 
728
        {
 
729
            ROTATE_SCREEN (s);
 
730
 
 
731
            if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_INITIATE], event))
 
732
                rotateInitiate (s, event->xkey.x_root, event->xkey.y_root);
 
733
 
 
734
            if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_LEFT_WINDOW], event))
 
735
                rotateWithWindow (s, event->xkey.x_root, event->xkey.y_root, -1);
 
736
            else if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_LEFT], event))
 
737
                rotate (s, event->xkey.x_root, event->xkey.y_root, -1);
 
738
 
 
739
            if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_RIGHT_WINDOW], event))
 
740
                rotateWithWindow (s, event->xkey.x_root, event->xkey.y_root, 1);
 
741
            else if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_RIGHT], event))
 
742
                rotate (s, event->xkey.x_root, event->xkey.y_root, 1);
 
743
 
 
744
            if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_TERMINATE], event))
 
745
                rotateTerminate (s);
 
746
 
 
747
            if (event->type         == KeyPress &&
 
748
                event->xkey.keycode == s->escapeKeyCode)
 
749
            {
 
750
                rs->snapTop = FALSE;
 
751
                rotateTerminate (s);
 
752
            }
 
753
        }
 
754
        break;
 
755
    case ButtonPress:
 
756
    case ButtonRelease:
 
757
        s = findScreenAtDisplay (d, event->xbutton.root);
 
758
        if (s)
 
759
        {
 
760
            ROTATE_SCREEN (s);
 
761
 
 
762
            if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_INITIATE], event))
 
763
                rotateInitiate (s,
 
764
                                event->xbutton.x_root,
 
765
                                event->xbutton.y_root);
 
766
 
 
767
            if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_LEFT_WINDOW], event))
 
768
                rotateWithWindow (s, event->xbutton.x_root,
 
769
                                  event->xbutton.y_root, -1);
 
770
            else if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_LEFT], event))
 
771
                rotate (s, event->xbutton.x_root, event->xbutton.y_root, -1);
 
772
 
 
773
            if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_RIGHT_WINDOW], event))
 
774
                rotateWithWindow (s, event->xbutton.x_root,
 
775
                                  event->xbutton.y_root, 1);
 
776
            else if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_RIGHT], event))
 
777
                rotate (s, event->xbutton.x_root, event->xbutton.y_root, 1);
 
778
 
 
779
            if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_TERMINATE], event))
 
780
                rotateTerminate (s);
 
781
        }
 
782
        break;
 
783
    case MotionNotify:
 
784
        s = findScreenAtDisplay (d, event->xmotion.root);
 
785
        if (s)
 
786
        {
 
787
            ROTATE_SCREEN (s);
 
788
 
 
789
            if (rs->grabIndex && rs->grabbed)
 
790
            {
 
791
                GLfloat pointerDx;
 
792
                GLfloat pointerDy;
 
793
 
 
794
                pointerDx = event->xmotion.x_root - rs->prevPointerX;
 
795
                pointerDy = event->xmotion.y_root - rs->prevPointerY;
 
796
                rs->prevPointerX = event->xmotion.x_root;
 
797
                rs->prevPointerY = event->xmotion.y_root;
 
798
 
 
799
                if (event->xmotion.x_root < 50             ||
 
800
                    event->xmotion.y_root < 50             ||
 
801
                    event->xmotion.x_root > s->width  - 50 ||
 
802
                    event->xmotion.y_root > s->height - 50)
 
803
                {
 
804
                    rs->prevPointerX = s->width / 2;
 
805
                    rs->prevPointerY = s->height / 2;
 
806
 
 
807
                    XWarpPointer (d->display, None, s->root, 0, 0, 0, 0,
 
808
                                  rs->prevPointerX, rs->prevPointerY);
 
809
                }
 
810
 
 
811
                if (rs->pointerInvertY)
 
812
                    pointerDy = -pointerDy;
 
813
 
 
814
                rs->xVelocity += pointerDx * rs->pointerSensitivity * rs->invert;
 
815
                rs->yVelocity += pointerDy * rs->pointerSensitivity;
 
816
 
 
817
                damageScreen (s);
 
818
 
 
819
                return;
 
820
            }
 
821
        }
 
822
        break;
 
823
    case ClientMessage:
 
824
        if (event->xclient.message_type == d->winActiveAtom)
 
825
        {
 
826
            CompWindow *w;
 
827
 
 
828
            w = findWindowAtDisplay (d, event->xclient.window);
 
829
            if (w)
 
830
            {
 
831
                s = w->screen;
 
832
 
 
833
                if (w->attrib.x >= s->width || w->attrib.x + w->width <= 0)
 
834
                {
 
835
                    Window       win;
 
836
                    int          i, x, y, dx;
 
837
                    unsigned int ui;
 
838
 
 
839
                    XQueryPointer (d->display, s->root,
 
840
                                   &win, &win, &x, &y, &i, &i, &ui);
 
841
 
 
842
                    if (w->attrib.x >= s->width)
 
843
                        dx = w->attrib.x / s->width;
 
844
                    else
 
845
                        dx = ((w->attrib.x + w->width) / s->width) - 1;
 
846
 
 
847
                    if (dx > (s->size + 1) / 2)
 
848
                        dx -= s->size;
 
849
                    else if (dx < -(s->size + 1) / 2)
 
850
                        dx += s->size;
 
851
 
 
852
                    rotate (s, x, y, dx);
 
853
                }
 
854
            }
 
855
        }
 
856
        else if (event->xclient.message_type == d->desktopViewportAtom)
 
857
        {
 
858
            s = findScreenAtDisplay (d, event->xclient.window);
 
859
            if (s)
 
860
            {
 
861
                int dx;
 
862
 
 
863
                dx = event->xclient.data.l[0] / s->width - s->x;
 
864
                if (dx)
 
865
                {
 
866
                    Window       win;
 
867
                    int          i, x, y;
 
868
                    unsigned int ui;
 
869
 
 
870
                    XQueryPointer (d->display, s->root,
 
871
                                   &win, &win, &x, &y, &i, &i, &ui);
 
872
 
 
873
                    if (dx > (s->size + 1) / 2)
 
874
                        dx -= s->size;
 
875
                    else if (dx < -(s->size + 1) / 2)
 
876
                        dx += s->size;
 
877
 
 
878
                    rotate (s, x, y, dx);
 
879
                }
 
880
            }
 
881
        }
 
882
    default:
 
883
        break;
 
884
    }
 
885
 
 
886
    UNWRAP (rd, d, handleEvent);
 
887
    (*d->handleEvent) (d, event);
 
888
    WRAP (rd, d, handleEvent, rotateHandleEvent);
 
889
}
 
890
 
 
891
static void
 
892
rotateUpdateCubeOptions (CompScreen *s)
 
893
{
 
894
    CompPlugin *p;
 
895
 
 
896
    ROTATE_SCREEN (s);
 
897
 
 
898
    p = findActivePlugin ("cube");
 
899
    if (p && p->vTable->getScreenOptions)
 
900
    {
 
901
        CompOption *options, *option;
 
902
        int        nOptions;
 
903
 
 
904
        options = (*p->vTable->getScreenOptions) (s, &nOptions);
 
905
        option = compFindOption (options, nOptions, "in", 0);
 
906
        if (option)
 
907
            rs->invert = option->value.b ? -1 : 1;
 
908
    }
 
909
}
 
910
 
 
911
static Bool
 
912
rotateSetScreenOptionForPlugin (CompScreen      *s,
 
913
                                char            *plugin,
 
914
                                char            *name,
 
915
                                CompOptionValue *value)
 
916
{
 
917
    Bool status;
 
918
 
 
919
    ROTATE_SCREEN (s);
 
920
 
 
921
    UNWRAP (rs, s, setScreenOptionForPlugin);
 
922
    status = (*s->setScreenOptionForPlugin) (s, plugin, name, value);
 
923
    WRAP (rs, s, setScreenOptionForPlugin, rotateSetScreenOptionForPlugin);
 
924
 
 
925
    if (status && strcmp (plugin, "cube") == 0 && strcmp (name, "in") == 0)
 
926
        rotateUpdateCubeOptions (s);
 
927
 
 
928
    return status;
 
929
}
 
930
 
 
931
static Bool
 
932
rotateInitDisplay (CompPlugin  *p,
 
933
                   CompDisplay *d)
 
934
{
 
935
    RotateDisplay *rd;
 
936
 
 
937
    rd = malloc (sizeof (RotateDisplay));
 
938
    if (!rd)
 
939
        return FALSE;
 
940
 
 
941
    rd->screenPrivateIndex = allocateScreenPrivateIndex (d);
 
942
    if (rd->screenPrivateIndex < 0)
 
943
    {
 
944
        free (rd);
 
945
        return FALSE;
 
946
    }
 
947
 
 
948
    WRAP (rd, d, handleEvent, rotateHandleEvent);
 
949
 
 
950
    d->privates[displayPrivateIndex].ptr = rd;
 
951
 
 
952
    return TRUE;
 
953
}
 
954
 
 
955
static void
 
956
rotateFiniDisplay (CompPlugin  *p,
 
957
                   CompDisplay *d)
 
958
{
 
959
    ROTATE_DISPLAY (d);
 
960
 
 
961
    freeScreenPrivateIndex (d, rd->screenPrivateIndex);
 
962
 
 
963
    UNWRAP (rd, d, handleEvent);
 
964
 
 
965
    free (rd);
 
966
}
 
967
 
 
968
static Bool
 
969
rotateInitScreen (CompPlugin *p,
 
970
                  CompScreen *s)
 
971
{
 
972
    RotateScreen *rs;
 
973
 
 
974
    ROTATE_DISPLAY (s->display);
 
975
 
 
976
    rs = malloc (sizeof (RotateScreen));
 
977
    if (!rs)
 
978
        return FALSE;
 
979
 
 
980
    rs->grabIndex = 0;
 
981
 
 
982
    rs->xrot = 0.0f;
 
983
    rs->xVelocity = 0.0f;
 
984
    rs->yrot = 0.0f;
 
985
    rs->yVelocity = 0.0f;
 
986
 
 
987
    rs->baseXrot = 0.0f;
 
988
 
 
989
    rs->moving = FALSE;
 
990
    rs->moveTo = 0.0f;
 
991
 
 
992
    rs->moveWindow = 0;
 
993
 
 
994
    rs->savedPointer.x = 0;
 
995
    rs->savedPointer.y = 0;
 
996
    rs->prevPointerX = 0;
 
997
    rs->prevPointerY = 0;
 
998
 
 
999
    rs->grabbed = FALSE;
 
1000
    rs->snapTop = FALSE;
 
1001
 
 
1002
    rs->acceleration = ROTATE_ACCELERATION_DEFAULT;
 
1003
 
 
1004
    rs->pointerInvertY     = ROTATE_POINTER_INVERT_Y_DEFAULT;
 
1005
    rs->pointerSensitivity = ROTATE_POINTER_SENSITIVITY_DEFAULT *
 
1006
        ROTATE_POINTER_SENSITIVITY_FACTOR;
 
1007
 
 
1008
    rs->speed    = ROTATE_SPEED_DEFAULT;
 
1009
    rs->timestep = ROTATE_TIMESTEP_DEFAULT;
 
1010
 
 
1011
    rotateScreenInitOptions (rs, s->display->display);
 
1012
 
 
1013
    addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_INITIATE].value.bind);
 
1014
    addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_LEFT].value.bind);
 
1015
    addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_RIGHT].value.bind);
 
1016
    addScreenBinding (s,
 
1017
                      &rs->opt[ROTATE_SCREEN_OPTION_LEFT_WINDOW].value.bind);
 
1018
    addScreenBinding (s,
 
1019
                      &rs->opt[ROTATE_SCREEN_OPTION_RIGHT_WINDOW].value.bind);
 
1020
 
 
1021
    WRAP (rs, s, preparePaintScreen, rotatePreparePaintScreen);
 
1022
    WRAP (rs, s, donePaintScreen, rotateDonePaintScreen);
 
1023
    WRAP (rs, s, paintScreen, rotatePaintScreen);
 
1024
    WRAP (rs, s, setScreenOptionForPlugin, rotateSetScreenOptionForPlugin);
 
1025
 
 
1026
    s->privates[rd->screenPrivateIndex].ptr = rs;
 
1027
 
 
1028
    rotateUpdateCubeOptions (s);
 
1029
 
 
1030
    return TRUE;
 
1031
}
 
1032
 
 
1033
static void
 
1034
rotateFiniScreen (CompPlugin *p,
 
1035
                  CompScreen *s)
 
1036
{
 
1037
    ROTATE_SCREEN (s);
 
1038
 
 
1039
    UNWRAP (rs, s, preparePaintScreen);
 
1040
    UNWRAP (rs, s, donePaintScreen);
 
1041
    UNWRAP (rs, s, paintScreen);
 
1042
    UNWRAP (rs, s, setScreenOptionForPlugin);
 
1043
 
 
1044
    free (rs);
 
1045
}
 
1046
 
 
1047
static Bool
 
1048
rotateInit (CompPlugin *p)
 
1049
{
 
1050
    displayPrivateIndex = allocateDisplayPrivateIndex ();
 
1051
    if (displayPrivateIndex < 0)
 
1052
        return FALSE;
 
1053
 
 
1054
    return TRUE;
 
1055
}
 
1056
 
 
1057
static void
 
1058
rotateFini (CompPlugin *p)
 
1059
{
 
1060
    if (displayPrivateIndex >= 0)
 
1061
        freeDisplayPrivateIndex (displayPrivateIndex);
 
1062
}
 
1063
 
 
1064
CompPluginDep rotateDeps[] = {
 
1065
    { CompPluginRuleAfter, "cube" }
 
1066
};
 
1067
 
 
1068
CompPluginVTable rotateVTable = {
 
1069
    "rotate",
 
1070
    "Rotate Cube",
 
1071
    "Rotate desktop cube",
 
1072
    rotateInit,
 
1073
    rotateFini,
 
1074
    rotateInitDisplay,
 
1075
    rotateFiniDisplay,
 
1076
    rotateInitScreen,
 
1077
    rotateFiniScreen,
 
1078
    0, /* InitWindow */
 
1079
    0, /* FiniWindow */
 
1080
    0, /* GetDisplayOptions */
 
1081
    0, /* SetDisplayOption */
 
1082
    rotateGetScreenOptions,
 
1083
    rotateSetScreenOption,
 
1084
    rotateDeps,
 
1085
    sizeof (rotateDeps) / sizeof (rotateDeps[0])
 
1086
};
 
1087
 
 
1088
CompPluginVTable *
 
1089
getCompPluginInfo (void)
 
1090
{
 
1091
    return &rotateVTable;
 
1092
}