2
* Copyright © 2005 Novell, Inc.
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
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.
23
* Author: David Reveman <davidr@novell.com>
34
#define ZOOM_POINTER_INVERT_Y_DEFAULT FALSE
36
#define ZOOM_POINTER_SENSITIVITY_DEFAULT 1.0f
37
#define ZOOM_POINTER_SENSITIVITY_MIN 0.01f
38
#define ZOOM_POINTER_SENSITIVITY_MAX 100.0f
39
#define ZOOM_POINTER_SENSITIVITY_PRECISION 0.01f
41
#define ZOOM_POINTER_SENSITIVITY_FACTOR 0.0015f
43
#define ZOOM_INITIATE_BUTTON_DEFAULT Button3
44
#define ZOOM_INITIATE_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
46
#define ZOOM_TERMINATE_BUTTON_DEFAULT Button3
47
#define ZOOM_TERMINATE_MODIFIERS_DEFAULT CompReleaseMask
49
#define ZOOM_IN_BUTTON_DEFAULT Button4
50
#define ZOOM_IN_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
52
#define ZOOM_OUT_BUTTON_DEFAULT Button5
53
#define ZOOM_OUT_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
55
#define ZOOM_SPEED_DEFAULT 1.5f
56
#define ZOOM_SPEED_MIN 0.1f
57
#define ZOOM_SPEED_MAX 50.0f
58
#define ZOOM_SPEED_PRECISION 0.1f
60
#define ZOOM_TIMESTEP_DEFAULT 1.2f
61
#define ZOOM_TIMESTEP_MIN 0.1f
62
#define ZOOM_TIMESTEP_MAX 50.0f
63
#define ZOOM_TIMESTEP_PRECISION 0.1f
65
static int displayPrivateIndex;
67
typedef struct _ZoomDisplay {
68
int screenPrivateIndex;
69
HandleEventProc handleEvent;
72
#define ZOOM_SCREEN_OPTION_POINTER_INVERT_Y 0
73
#define ZOOM_SCREEN_OPTION_POINTER_SENSITIVITY 1
74
#define ZOOM_SCREEN_OPTION_INITIATE 2
75
#define ZOOM_SCREEN_OPTION_TERMINATE 3
76
#define ZOOM_SCREEN_OPTION_IN 4
77
#define ZOOM_SCREEN_OPTION_OUT 5
78
#define ZOOM_SCREEN_OPTION_SPEED 6
79
#define ZOOM_SCREEN_OPTION_TIMESTEP 7
80
#define ZOOM_SCREEN_OPTION_NUM 8
82
typedef struct _ZoomScreen {
83
PreparePaintScreenProc preparePaintScreen;
84
DonePaintScreenProc donePaintScreen;
85
PaintScreenProc paintScreen;
86
SetScreenOptionForPluginProc setScreenOptionForPlugin;
88
CompOption opt[ZOOM_SCREEN_OPTION_NUM];
91
float pointerSensitivity;
120
#define GET_ZOOM_DISPLAY(d) \
121
((ZoomDisplay *) (d)->privates[displayPrivateIndex].ptr)
123
#define ZOOM_DISPLAY(d) \
124
ZoomDisplay *zd = GET_ZOOM_DISPLAY (d)
126
#define GET_ZOOM_SCREEN(s, zd) \
127
((ZoomScreen *) (s)->privates[(zd)->screenPrivateIndex].ptr)
129
#define ZOOM_SCREEN(s) \
130
ZoomScreen *zs = GET_ZOOM_SCREEN (s, GET_ZOOM_DISPLAY (s->display))
132
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
135
zoomGetScreenOptions (CompScreen *screen,
138
ZOOM_SCREEN (screen);
140
*count = NUM_OPTIONS (zs);
145
zoomSetScreenOption (CompScreen *screen,
147
CompOptionValue *value)
152
ZOOM_SCREEN (screen);
154
o = compFindOption (zs->opt, NUM_OPTIONS (zs), name, &index);
159
case ZOOM_SCREEN_OPTION_POINTER_INVERT_Y:
160
if (compSetBoolOption (o, value))
162
zs->pointerInvertY = o->value.b;
166
case ZOOM_SCREEN_OPTION_POINTER_SENSITIVITY:
167
if (compSetFloatOption (o, value))
169
zs->pointerSensitivity = o->value.f *
170
ZOOM_POINTER_SENSITIVITY_FACTOR;
174
case ZOOM_SCREEN_OPTION_INITIATE:
175
case ZOOM_SCREEN_OPTION_IN:
176
if (addScreenBinding (screen, &value->bind))
178
removeScreenBinding (screen, &o->value.bind);
180
if (compSetBindingOption (o, value))
184
case ZOOM_SCREEN_OPTION_TERMINATE:
185
case ZOOM_SCREEN_OPTION_OUT:
186
if (compSetBindingOption (o, value))
189
case ZOOM_SCREEN_OPTION_SPEED:
190
if (compSetFloatOption (o, value))
192
zs->speed = o->value.f;
196
case ZOOM_SCREEN_OPTION_TIMESTEP:
197
if (compSetFloatOption (o, value))
199
zs->timestep = o->value.f;
211
zoomScreenInitOptions (ZoomScreen *zs,
216
o = &zs->opt[ZOOM_SCREEN_OPTION_POINTER_INVERT_Y];
217
o->name = "invert_y";
218
o->shortDesc = "Pointer Invert Y";
219
o->longDesc = "Invert Y axis for pointer movement";
220
o->type = CompOptionTypeBool;
221
o->value.b = ZOOM_POINTER_INVERT_Y_DEFAULT;
223
o = &zs->opt[ZOOM_SCREEN_OPTION_POINTER_SENSITIVITY];
224
o->name = "sensitivity";
225
o->shortDesc = "Pointer Sensitivity";
226
o->longDesc = "Sensitivity of pointer movement";
227
o->type = CompOptionTypeFloat;
228
o->value.f = ZOOM_POINTER_SENSITIVITY_DEFAULT;
229
o->rest.f.min = ZOOM_POINTER_SENSITIVITY_MIN;
230
o->rest.f.max = ZOOM_POINTER_SENSITIVITY_MAX;
231
o->rest.f.precision = ZOOM_POINTER_SENSITIVITY_PRECISION;
233
o = &zs->opt[ZOOM_SCREEN_OPTION_INITIATE];
234
o->name = "initiate";
235
o->shortDesc = "Initiate";
236
o->longDesc = "Zoom In";
237
o->type = CompOptionTypeBinding;
238
o->value.bind.type = CompBindingTypeButton;
239
o->value.bind.u.button.modifiers = ZOOM_INITIATE_MODIFIERS_DEFAULT;
240
o->value.bind.u.button.button = ZOOM_INITIATE_BUTTON_DEFAULT;
242
o = &zs->opt[ZOOM_SCREEN_OPTION_TERMINATE];
243
o->name = "terminate";
244
o->shortDesc = "Terminate";
245
o->longDesc = "Zoom to Normal View";
246
o->type = CompOptionTypeBinding;
247
o->value.bind.type = CompBindingTypeButton;
248
o->value.bind.u.button.modifiers = ZOOM_TERMINATE_MODIFIERS_DEFAULT;
249
o->value.bind.u.button.button = ZOOM_TERMINATE_BUTTON_DEFAULT;
251
o = &zs->opt[ZOOM_SCREEN_OPTION_IN];
253
o->shortDesc = "Zoom In";
254
o->longDesc = "Zoom In";
255
o->type = CompOptionTypeBinding;
256
o->value.bind.type = CompBindingTypeButton;
257
o->value.bind.u.button.modifiers = ZOOM_IN_MODIFIERS_DEFAULT;
258
o->value.bind.u.button.button = ZOOM_IN_BUTTON_DEFAULT;
260
o = &zs->opt[ZOOM_SCREEN_OPTION_OUT];
261
o->name = "zoom_out";
262
o->shortDesc = "Zoom Out";
263
o->longDesc = "Zoom Out";
264
o->type = CompOptionTypeBinding;
265
o->value.bind.type = CompBindingTypeButton;
266
o->value.bind.u.button.modifiers = ZOOM_OUT_MODIFIERS_DEFAULT;
267
o->value.bind.u.button.button = ZOOM_OUT_BUTTON_DEFAULT;
269
o = &zs->opt[ZOOM_SCREEN_OPTION_SPEED];
271
o->shortDesc = "Speed";
272
o->longDesc = "Zoom Speed";
273
o->type = CompOptionTypeFloat;
274
o->value.f = ZOOM_SPEED_DEFAULT;
275
o->rest.f.min = ZOOM_SPEED_MIN;
276
o->rest.f.max = ZOOM_SPEED_MAX;
277
o->rest.f.precision = ZOOM_SPEED_PRECISION;
279
o = &zs->opt[ZOOM_SCREEN_OPTION_TIMESTEP];
280
o->name = "timestep";
281
o->shortDesc = "Timestep";
282
o->longDesc = "Zoom Timestep";
283
o->type = CompOptionTypeFloat;
284
o->value.f = ZOOM_TIMESTEP_DEFAULT;
285
o->rest.f.min = ZOOM_TIMESTEP_MIN;
286
o->rest.f.max = ZOOM_TIMESTEP_MAX;
287
o->rest.f.precision = ZOOM_TIMESTEP_PRECISION;
293
adjustZoomVelocity (ZoomScreen *zs)
295
float d, adjust, amount;
297
d = (zs->newZoom - zs->currentZoom) * 200.0f;
303
else if (amount > 10.0f)
306
zs->zVelocity = (amount * zs->zVelocity + adjust) / (amount + 1.0f);
308
return (fabs (d) < 0.1f && fabs (zs->zVelocity) < 0.005f);
312
zoomPreparePaintScreen (CompScreen *s,
313
int msSinceLastPaint)
322
amount = msSinceLastPaint * 0.05f * zs->speed;
323
steps = amount / (0.5f * zs->timestep);
324
if (!steps) steps = 1;
325
chunk = amount / (float) steps;
329
zs->xVelocity /= 1.25f;
330
zs->yVelocity /= 1.25f;
332
if (fabs (zs->xVelocity) < 0.001f)
333
zs->xVelocity = 0.0f;
334
if (fabs (zs->yVelocity) < 0.001f)
335
zs->yVelocity = 0.0f;
337
zs->xTranslate += zs->xVelocity * chunk;
338
if (zs->xTranslate < -zs->maxTranslate)
340
zs->xTranslate = -zs->maxTranslate;
341
zs->xVelocity = 0.0f;
343
else if (zs->xTranslate > zs->maxTranslate)
345
zs->xTranslate = zs->maxTranslate;
346
zs->xVelocity = 0.0f;
349
zs->yTranslate += zs->yVelocity * chunk;
350
if (zs->yTranslate < -zs->maxTranslate)
352
zs->yTranslate = -zs->maxTranslate;
353
zs->yVelocity = 0.0f;
355
else if (zs->yTranslate > zs->maxTranslate)
357
zs->yTranslate = zs->maxTranslate;
358
zs->yVelocity = 0.0f;
361
if (adjustZoomVelocity (zs))
363
zs->currentZoom = zs->newZoom;
364
zs->zVelocity = 0.0f;
368
zs->currentZoom += (zs->zVelocity * msSinceLastPaint) /
372
zs->ztrans = DEFAULT_Z_CAMERA * zs->currentZoom;
373
if (zs->ztrans <= 0.0f)
375
zs->zVelocity = 0.0f;
379
zs->xtrans = -zs->xTranslate * (1.0f - zs->currentZoom);
380
zs->ytrans = zs->yTranslate * (1.0f - zs->currentZoom);
384
if (zs->currentZoom == 1.0f && zs->zVelocity == 0.0f)
386
zs->xVelocity = zs->yVelocity = 0.0f;
388
removeScreenGrab (s, zs->grabIndex, &zs->savedPointer);
389
zs->grabIndex = FALSE;
396
UNWRAP (zs, s, preparePaintScreen);
397
(*s->preparePaintScreen) (s, msSinceLastPaint);
398
WRAP (zs, s, preparePaintScreen, zoomPreparePaintScreen);
402
zoomDonePaintScreen (CompScreen *s)
408
if (zs->currentZoom != zs->newZoom ||
409
zs->xVelocity || zs->yVelocity || zs->zVelocity)
413
UNWRAP (zs, s, donePaintScreen);
414
(*s->donePaintScreen) (s);
415
WRAP (zs, s, donePaintScreen, zoomDonePaintScreen);
419
zoomPaintScreen (CompScreen *s,
420
const ScreenPaintAttrib *sAttrib,
430
ScreenPaintAttrib sa = *sAttrib;
432
sa.xTranslate += zs->xtrans;
433
sa.yTranslate += zs->ytrans;
435
sa.zCamera = -zs->ztrans;
437
/* hack to get sides rendered correctly */
438
if (zs->xtrans > 0.0f)
439
sa.xRotate += 0.000001f;
441
sa.xRotate -= 0.000001f;
443
mask &= ~PAINT_SCREEN_REGION_MASK;
444
mask |= PAINT_SCREEN_TRANSFORMED_MASK;
446
UNWRAP (zs, s, paintScreen);
447
status = (*s->paintScreen) (s, &sa, region, mask);
448
WRAP (zs, s, paintScreen, zoomPaintScreen);
452
UNWRAP (zs, s, paintScreen);
453
status = (*s->paintScreen) (s, sAttrib, region, mask);
454
WRAP (zs, s, paintScreen, zoomPaintScreen);
461
zoomIn (CompScreen *s,
467
/* some other plugin has already grabbed the screen */
468
if (s->maxGrab - zs->grabIndex)
471
zs->prevPointerX = x;
472
zs->prevPointerY = y;
476
zs->grabIndex = pushScreenGrab (s, s->invisibleCursor);
478
zs->savedPointer.x = zs->prevPointerX;
479
zs->savedPointer.y = zs->prevPointerY;
490
if (zs->currentZoom == 1.0f)
492
zs->xTranslate = (x - s->width / 2) / (float) s->width;
493
zs->yTranslate = (y - s->height / 2) / (float) s->height;
495
zs->xTranslate /= zs->newZoom;
496
zs->yTranslate /= zs->newZoom;
502
zoomOut (CompScreen *s)
509
if (zs->newZoom > DEFAULT_Z_CAMERA - (DEFAULT_Z_CAMERA / 10.0f))
520
zoomTerminate (CompScreen *s)
534
zoomHandleEvent (CompDisplay *d,
541
switch (event->type) {
544
s = findScreenAtDisplay (d, event->xkey.root);
549
if (EV_KEY (&zs->opt[ZOOM_SCREEN_OPTION_INITIATE], event) ||
550
EV_KEY (&zs->opt[ZOOM_SCREEN_OPTION_IN], event))
555
if (EV_KEY (&zs->opt[ZOOM_SCREEN_OPTION_OUT], event))
558
if (EV_KEY (&zs->opt[ZOOM_SCREEN_OPTION_TERMINATE], event) ||
559
(event->type == KeyPress &&
560
event->xkey.keycode == s->escapeKeyCode))
566
s = findScreenAtDisplay (d, event->xbutton.root);
571
if (EV_BUTTON (&zs->opt[ZOOM_SCREEN_OPTION_INITIATE], event) ||
572
EV_BUTTON (&zs->opt[ZOOM_SCREEN_OPTION_IN], event))
574
event->xbutton.x_root,
575
event->xbutton.y_root);
577
if (EV_BUTTON (&zs->opt[ZOOM_SCREEN_OPTION_OUT], event))
580
if (EV_BUTTON (&zs->opt[ZOOM_SCREEN_OPTION_TERMINATE], event))
585
s = findScreenAtDisplay (d, event->xmotion.root);
590
if (zs->grabIndex && zs->grabbed)
595
pointerDx = event->xmotion.x_root - zs->prevPointerX;
596
pointerDy = event->xmotion.y_root - zs->prevPointerY;
597
zs->prevPointerX = event->xmotion.x_root;
598
zs->prevPointerY = event->xmotion.y_root;
600
if (event->xmotion.x_root < 50 ||
601
event->xmotion.y_root < 50 ||
602
event->xmotion.x_root > s->width - 50 ||
603
event->xmotion.y_root > s->height - 50)
605
zs->prevPointerX = s->width / 2;
606
zs->prevPointerY = s->height / 2;
608
XWarpPointer (d->display, None, s->root, 0, 0, 0, 0,
609
zs->prevPointerX, zs->prevPointerY);
612
if (zs->pointerInvertY)
613
pointerDy = -pointerDy;
615
zs->xVelocity += pointerDx * zs->pointerSensitivity;
616
zs->yVelocity += pointerDy * zs->pointerSensitivity;
625
UNWRAP (zd, d, handleEvent);
626
(*d->handleEvent) (d, event);
627
WRAP (zd, d, handleEvent, zoomHandleEvent);
631
zoomUpdateCubeOptions (CompScreen *s)
637
p = findActivePlugin ("cube");
638
if (p && p->vTable->getScreenOptions)
640
CompOption *options, *option;
643
options = (*p->vTable->getScreenOptions) (s, &nOptions);
644
option = compFindOption (options, nOptions, "in", 0);
646
zs->maxTranslate = option->value.b ? 0.85f : 1.5f;
651
zoomSetScreenOptionForPlugin (CompScreen *s,
654
CompOptionValue *value)
660
UNWRAP (zs, s, setScreenOptionForPlugin);
661
status = (*s->setScreenOptionForPlugin) (s, plugin, name, value);
662
WRAP (zs, s, setScreenOptionForPlugin, zoomSetScreenOptionForPlugin);
664
if (status && strcmp (plugin, "cube") == 0)
665
zoomUpdateCubeOptions (s);
671
zoomInitDisplay (CompPlugin *p,
676
zd = malloc (sizeof (ZoomDisplay));
680
zd->screenPrivateIndex = allocateScreenPrivateIndex (d);
681
if (zd->screenPrivateIndex < 0)
687
WRAP (zd, d, handleEvent, zoomHandleEvent);
689
d->privates[displayPrivateIndex].ptr = zd;
695
zoomFiniDisplay (CompPlugin *p,
700
freeScreenPrivateIndex (d, zd->screenPrivateIndex);
702
UNWRAP (zd, d, handleEvent);
708
zoomInitScreen (CompPlugin *p,
713
ZOOM_DISPLAY (s->display);
715
zs = malloc (sizeof (ZoomScreen));
721
zs->currentZoom = 1.0f;
724
zs->xVelocity = 0.0f;
725
zs->yVelocity = 0.0f;
726
zs->zVelocity = 0.0f;
728
zs->xTranslate = 0.0f;
729
zs->yTranslate = 0.0f;
731
zs->maxTranslate = 0.0f;
733
zs->savedPointer.x = 0;
734
zs->savedPointer.y = 0;
735
zs->prevPointerX = 0;
736
zs->prevPointerY = 0;
740
zs->pointerInvertY = ZOOM_POINTER_INVERT_Y_DEFAULT;
741
zs->pointerSensitivity = ZOOM_POINTER_SENSITIVITY_DEFAULT *
742
ZOOM_POINTER_SENSITIVITY_FACTOR;
744
zs->speed = ZOOM_SPEED_DEFAULT;
745
zs->timestep = ZOOM_TIMESTEP_DEFAULT;
747
zoomScreenInitOptions (zs, s->display->display);
749
addScreenBinding (s, &zs->opt[ZOOM_SCREEN_OPTION_INITIATE].value.bind);
750
addScreenBinding (s, &zs->opt[ZOOM_SCREEN_OPTION_IN].value.bind);
752
WRAP (zs, s, preparePaintScreen, zoomPreparePaintScreen);
753
WRAP (zs, s, donePaintScreen, zoomDonePaintScreen);
754
WRAP (zs, s, paintScreen, zoomPaintScreen);
755
WRAP (zs, s, setScreenOptionForPlugin, zoomSetScreenOptionForPlugin);
757
s->privates[zd->screenPrivateIndex].ptr = zs;
759
zoomUpdateCubeOptions (s);
765
zoomFiniScreen (CompPlugin *p,
770
UNWRAP (zs, s, preparePaintScreen);
771
UNWRAP (zs, s, donePaintScreen);
772
UNWRAP (zs, s, paintScreen);
773
UNWRAP (zs, s, setScreenOptionForPlugin);
779
zoomInit (CompPlugin *p)
781
displayPrivateIndex = allocateDisplayPrivateIndex ();
782
if (displayPrivateIndex < 0)
789
zoomFini (CompPlugin *p)
791
if (displayPrivateIndex >= 0)
792
freeDisplayPrivateIndex (displayPrivateIndex);
795
CompPluginDep zoomDeps[] = {
796
{ CompPluginRuleAfter, "cube" }
799
CompPluginVTable zoomVTable = {
802
"Zoom and pan desktop cube",
811
0, /* GetDisplayOptions */
812
0, /* SetDisplayOption */
813
zoomGetScreenOptions,
816
sizeof (zoomDeps) / sizeof (zoomDeps[0])
820
getCompPluginInfo (void)