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
30 #include <X11/cursorfont.h>
31
32 #include <compiz-core.h>
33
34 static CompMetadata moveMetadata;
35
36 struct _MoveKeys {
37 char *name;
38 int dx;
39 int dy;
40 } mKeys[] = {
41 { "Left", -1, 0 },
42 { "Right", 1, 0 },
43 { "Up", 0, -1 },
44 { "Down", 0, 1 }
45 };
46
47 #define NUM_KEYS (sizeof (mKeys) / sizeof (mKeys[0]))
48
49 #define KEY_MOVE_INC 24
50
51 #define SNAP_BACK 20
52 #define SNAP_OFF 100
53
54 static int displayPrivateIndex;
55
56 #define MOVE_DISPLAY_OPTION_INITIATE_BUTTON 0
57 #define MOVE_DISPLAY_OPTION_INITIATE_KEY 1
58 #define MOVE_DISPLAY_OPTION_OPACITY 2
59 #define MOVE_DISPLAY_OPTION_CONSTRAIN_Y 3
60 #define MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED 4
61 #define MOVE_DISPLAY_OPTION_LAZY_POSITIONING 5
62 #define MOVE_DISPLAY_OPTION_NUM 6
63
64 typedef struct _MoveDisplay {
65 int screenPrivateIndex;
66 HandleEventProc handleEvent;
67
68 CompOption opt[MOVE_DISPLAY_OPTION_NUM];
69
70 CompWindow *w;
71 int savedX;
72 int savedY;
73 int x;
74 int y;
75 Region region;
76 int status;
77 Bool constrainY;
78 KeyCode key[NUM_KEYS];
79
80 int releaseButton;
81
82 GLushort moveOpacity;
83 } MoveDisplay;
84
85 typedef struct _MoveScreen {
86 PaintWindowProc paintWindow;
87
88 int grabIndex;
89
90 Cursor moveCursor;
91
92 unsigned int origState;
93
94 int snapOffY;
95 int snapBackY;
96 } MoveScreen;
97
98 #define GET_MOVE_DISPLAY(d) \
99 ((MoveDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
100
101 #define MOVE_DISPLAY(d) \
102 MoveDisplay *md = GET_MOVE_DISPLAY (d)
103
104 #define GET_MOVE_SCREEN(s, md) \
105 ((MoveScreen *) (s)->base.privates[(md)->screenPrivateIndex].ptr)
106
107 #define MOVE_SCREEN(s) \
108 MoveScreen *ms = GET_MOVE_SCREEN (s, GET_MOVE_DISPLAY (s->display))
109
110 #define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
111
112 static Bool
moveInitiate(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)113 moveInitiate (CompDisplay *d,
114 CompAction *action,
115 CompActionState state,
116 CompOption *option,
117 int nOption)
118 {
119 CompWindow *w;
120 Window xid;
121
122 MOVE_DISPLAY (d);
123
124 xid = getIntOptionNamed (option, nOption, "window", 0);
125
126 w = findWindowAtDisplay (d, xid);
127 if (w && (w->actions & CompWindowActionMoveMask))
128 {
129 XRectangle workArea;
130 unsigned int mods;
131 int x, y, button;
132 Bool sourceExternalApp;
133
134 MOVE_SCREEN (w->screen);
135
136 mods = getIntOptionNamed (option, nOption, "modifiers", 0);
137
138 x = getIntOptionNamed (option, nOption, "x",
139 w->attrib.x + (w->width / 2));
140 y = getIntOptionNamed (option, nOption, "y",
141 w->attrib.y + (w->height / 2));
142
143 button = getIntOptionNamed (option, nOption, "button", -1);
144
145 if (otherScreenGrabExist (w->screen, "move", NULL))
146 return FALSE;
147
148 if (md->w)
149 return FALSE;
150
151 if (w->type & (CompWindowTypeDesktopMask |
152 CompWindowTypeDockMask |
153 CompWindowTypeFullscreenMask))
154 return FALSE;
155
156 if (w->attrib.override_redirect)
157 return FALSE;
158
159 if (state & CompActionStateInitButton)
160 action->state |= CompActionStateTermButton;
161
162 if (md->region)
163 {
164 XDestroyRegion (md->region);
165 md->region = NULL;
166 }
167
168 md->status = RectangleOut;
169
170 md->savedX = w->serverX;
171 md->savedY = w->serverY;
172
173 md->x = 0;
174 md->y = 0;
175
176 sourceExternalApp = getBoolOptionNamed (option, nOption, "external",
177 FALSE);
178 md->constrainY = sourceExternalApp &&
179 md->opt[MOVE_DISPLAY_OPTION_CONSTRAIN_Y].value.b;
180
181 lastPointerX = x;
182 lastPointerY = y;
183
184 ms->origState = w->state;
185
186 getWorkareaForOutput (w->screen,
187 outputDeviceForWindow (w),
188 &workArea);
189
190 ms->snapBackY = w->serverY - workArea.y;
191 ms->snapOffY = y - workArea.y;
192
193 if (!ms->grabIndex)
194 ms->grabIndex = pushScreenGrab (w->screen, ms->moveCursor, "move");
195
196 if (ms->grabIndex)
197 {
198 unsigned int grabMask = CompWindowGrabMoveMask |
199 CompWindowGrabButtonMask;
200
201 if (sourceExternalApp)
202 grabMask |= CompWindowGrabExternalAppMask;
203
204 md->w = w;
205
206 md->releaseButton = button;
207
208 (w->screen->windowGrabNotify) (w, x, y, mods, grabMask);
209
210 if (d->opt[COMP_DISPLAY_OPTION_RAISE_ON_CLICK].value.b)
211 updateWindowAttributes (w,
212 CompStackingUpdateModeAboveFullscreen);
213
214 if (state & CompActionStateInitKey)
215 {
216 int xRoot, yRoot;
217
218 xRoot = w->attrib.x + (w->width / 2);
219 yRoot = w->attrib.y + (w->height / 2);
220
221 warpPointer (w->screen, xRoot - pointerX, yRoot - pointerY);
222 }
223
224 if (md->moveOpacity != OPAQUE)
225 addWindowDamage (w);
226 }
227 }
228
229 return FALSE;
230 }
231
232 static Bool
moveTerminate(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)233 moveTerminate (CompDisplay *d,
234 CompAction *action,
235 CompActionState state,
236 CompOption *option,
237 int nOption)
238 {
239 MOVE_DISPLAY (d);
240
241 if (md->w)
242 {
243 MOVE_SCREEN (md->w->screen);
244
245 if (state & CompActionStateCancel)
246 moveWindow (md->w,
247 md->savedX - md->w->attrib.x,
248 md->savedY - md->w->attrib.y,
249 TRUE, FALSE);
250
251 syncWindowPosition (md->w);
252
253 /* update window size as window constraints may have
254 changed - needed e.g. if a maximized window was moved
255 to another output device */
256 updateWindowSize (md->w);
257
258 (md->w->screen->windowUngrabNotify) (md->w);
259
260 if (ms->grabIndex)
261 {
262 removeScreenGrab (md->w->screen, ms->grabIndex, NULL);
263 ms->grabIndex = 0;
264 }
265
266 if (md->moveOpacity != OPAQUE)
267 addWindowDamage (md->w);
268
269 md->w = 0;
270 md->releaseButton = 0;
271 }
272
273 action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
274
275 return FALSE;
276 }
277
278 /* creates a region containing top and bottom struts. only struts that are
279 outside the screen workarea are considered. */
280 static Region
moveGetYConstrainRegion(CompScreen * s)281 moveGetYConstrainRegion (CompScreen *s)
282 {
283 CompWindow *w;
284 Region region;
285 REGION r;
286 XRectangle workArea;
287 BoxRec extents;
288 int i;
289
290 region = XCreateRegion ();
291 if (!region)
292 return NULL;
293
294 r.rects = &r.extents;
295 r.numRects = r.size = 1;
296
297 r.extents.x1 = MINSHORT;
298 r.extents.y1 = 0;
299 r.extents.x2 = 0;
300 r.extents.y2 = s->height;
301
302 XUnionRegion (&r, region, region);
303
304 r.extents.x1 = s->width;
305 r.extents.x2 = MAXSHORT;
306
307 XUnionRegion (&r, region, region);
308
309 for (i = 0; i < s->nOutputDev; i++)
310 {
311 XUnionRegion (&s->outputDev[i].region, region, region);
312
313 getWorkareaForOutput (s, i, &workArea);
314 extents = s->outputDev[i].region.extents;
315
316 for (w = s->windows; w; w = w->next)
317 {
318 if (!w->mapNum)
319 continue;
320
321 if (w->struts)
322 {
323 r.extents.x1 = w->struts->top.x;
324 r.extents.y1 = w->struts->top.y;
325 r.extents.x2 = r.extents.x1 + w->struts->top.width;
326 r.extents.y2 = r.extents.y1 + w->struts->top.height;
327
328 if (r.extents.x1 < extents.x1)
329 r.extents.x1 = extents.x1;
330 if (r.extents.x2 > extents.x2)
331 r.extents.x2 = extents.x2;
332 if (r.extents.y1 < extents.y1)
333 r.extents.y1 = extents.y1;
334 if (r.extents.y2 > extents.y2)
335 r.extents.y2 = extents.y2;
336
337 if (r.extents.x1 < r.extents.x2 && r.extents.y1 < r.extents.y2)
338 {
339 if (r.extents.y2 <= workArea.y)
340 XSubtractRegion (region, &r, region);
341 }
342
343 r.extents.x1 = w->struts->bottom.x;
344 r.extents.y1 = w->struts->bottom.y;
345 r.extents.x2 = r.extents.x1 + w->struts->bottom.width;
346 r.extents.y2 = r.extents.y1 + w->struts->bottom.height;
347
348 if (r.extents.x1 < extents.x1)
349 r.extents.x1 = extents.x1;
350 if (r.extents.x2 > extents.x2)
351 r.extents.x2 = extents.x2;
352 if (r.extents.y1 < extents.y1)
353 r.extents.y1 = extents.y1;
354 if (r.extents.y2 > extents.y2)
355 r.extents.y2 = extents.y2;
356
357 if (r.extents.x1 < r.extents.x2 && r.extents.y1 < r.extents.y2)
358 {
359 if (r.extents.y1 >= (workArea.y + workArea.height))
360 XSubtractRegion (region, &r, region);
361 }
362 }
363 }
364 }
365
366 return region;
367 }
368
369 static void
moveHandleMotionEvent(CompScreen * s,int xRoot,int yRoot)370 moveHandleMotionEvent (CompScreen *s,
371 int xRoot,
372 int yRoot)
373 {
374 MOVE_SCREEN (s);
375
376 if (ms->grabIndex)
377 {
378 CompWindow *w;
379 int dx, dy;
380 int wX, wY;
381 int wWidth, wHeight;
382
383 MOVE_DISPLAY (s->display);
384
385 w = md->w;
386
387 wX = w->serverX;
388 wY = w->serverY;
389 wWidth = w->serverWidth + w->serverBorderWidth * 2;
390 wHeight = w->serverHeight + w->serverBorderWidth * 2;
391
392 md->x += xRoot - lastPointerX;
393 md->y += yRoot - lastPointerY;
394
395 if (w->type & CompWindowTypeFullscreenMask)
396 {
397 dx = dy = 0;
398 }
399 else
400 {
401 XRectangle workArea;
402 int min, max;
403
404 dx = md->x;
405 dy = md->y;
406
407 getWorkareaForOutput (s,
408 outputDeviceForWindow (w),
409 &workArea);
410
411 if (md->constrainY)
412 {
413 if (!md->region)
414 md->region = moveGetYConstrainRegion (s);
415
416 /* make sure that the top frame extents or the top row of
417 pixels are within what is currently our valid screen
418 region */
419 if (md->region)
420 {
421 int x, y, width, height;
422 int status;
423
424 x = wX + dx - w->input.left;
425 y = wY + dy - w->input.top;
426 width = wWidth + w->input.left + w->input.right;
427 height = w->input.top ? w->input.top : 1;
428
429 status = XRectInRegion (md->region, x, y, width, height);
430
431 /* only constrain movement if previous position was valid */
432 if (md->status == RectangleIn)
433 {
434 int xStatus = status;
435
436 while (dx && xStatus != RectangleIn)
437 {
438 xStatus = XRectInRegion (md->region,
439 x, y - dy,
440 width, height);
441
442 if (xStatus != RectangleIn)
443 dx += (dx < 0) ? 1 : -1;
444
445 x = wX + dx - w->input.left;
446 }
447
448 while (dy && status != RectangleIn)
449 {
450 status = XRectInRegion (md->region,
451 x, y,
452 width, height);
453
454 if (status != RectangleIn)
455 dy += (dy < 0) ? 1 : -1;
456
457 y = wY + dy - w->input.top;
458 }
459 }
460 else
461 {
462 md->status = status;
463 }
464 }
465 }
466
467 if (md->opt[MOVE_DISPLAY_OPTION_SNAPOFF_MAXIMIZED].value.b)
468 {
469 if (w->state & CompWindowStateMaximizedVertMask)
470 {
471 if (abs ((yRoot - workArea.y) - ms->snapOffY) >= SNAP_OFF)
472 {
473 if (!otherScreenGrabExist (s, "move", NULL))
474 {
475 int width = w->serverWidth;
476
477 w->saveMask |= CWX | CWY;
478
479 if (w->saveMask & CWWidth)
480 width = w->saveWc.width;
481
482 w->saveWc.x = xRoot - (width >> 1);
483 w->saveWc.y = yRoot + (w->input.top >> 1);
484
485 md->x = md->y = 0;
486
487 maximizeWindow (w, 0);
488
489 ms->snapOffY = ms->snapBackY;
490
491 return;
492 }
493 }
494 }
495 else if (ms->origState & CompWindowStateMaximizedVertMask)
496 {
497 if (abs ((yRoot - workArea.y) - ms->snapBackY) < SNAP_BACK)
498 {
499 if (!otherScreenGrabExist (s, "move", NULL))
500 {
501 int wy;
502
503 /* update server position before maximizing
504 window again so that it is maximized on
505 correct output */
506 syncWindowPosition (w);
507
508 maximizeWindow (w, ms->origState);
509
510 wy = workArea.y + (w->input.top >> 1);
511 wy += w->sizeHints.height_inc >> 1;
512
513 warpPointer (s, 0, wy - pointerY);
514
515 return;
516 }
517 }
518 }
519 }
520
521 if (w->state & CompWindowStateMaximizedVertMask)
522 {
523 min = workArea.y + w->input.top;
524 max = workArea.y + workArea.height - w->input.bottom - wHeight;
525
526 if (wY + dy < min)
527 dy = min - wY;
528 else if (wY + dy > max)
529 dy = max - wY;
530 }
531
532 if (w->state & CompWindowStateMaximizedHorzMask)
533 {
534 if (wX > s->width || wX + w->width < 0)
535 return;
536
537 if (wX + wWidth < 0)
538 return;
539
540 min = workArea.x + w->input.left;
541 max = workArea.x + workArea.width - w->input.right - wWidth;
542
543 if (wX + dx < min)
544 dx = min - wX;
545 else if (wX + dx > max)
546 dx = max - wX;
547 }
548 }
549
550 if (dx || dy)
551 {
552 moveWindow (w,
553 wX + dx - w->attrib.x,
554 wY + dy - w->attrib.y,
555 TRUE, FALSE);
556
557 if (md->opt[MOVE_DISPLAY_OPTION_LAZY_POSITIONING].value.b)
558 {
559 /* FIXME: This form of lazy positioning is broken and should
560 be replaced asap. Current code exists just to avoid a
561 major performance regression in the 0.5.2 release. */
562 w->serverX = w->attrib.x;
563 w->serverY = w->attrib.y;
564 }
565 else
566 {
567 syncWindowPosition (w);
568 }
569
570 md->x -= dx;
571 md->y -= dy;
572 }
573 }
574 }
575
576 static void
moveHandleEvent(CompDisplay * d,XEvent * event)577 moveHandleEvent (CompDisplay *d,
578 XEvent *event)
579 {
580 CompScreen *s;
581
582 MOVE_DISPLAY (d);
583
584 switch (event->type) {
585 case ButtonPress:
586 case ButtonRelease:
587 s = findScreenAtDisplay (d, event->xbutton.root);
588 if (s)
589 {
590 MOVE_SCREEN (s);
591
592 if (ms->grabIndex)
593 {
594 if (md->releaseButton == -1 ||
595 md->releaseButton == event->xbutton.button)
596 {
597 CompAction *action;
598 int opt = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
599
600 action = &md->opt[opt].value.action;
601 moveTerminate (d, action, CompActionStateTermButton,
602 NULL, 0);
603 }
604 }
605 }
606 break;
607 case KeyPress:
608 s = findScreenAtDisplay (d, event->xkey.root);
609 if (s)
610 {
611 MOVE_SCREEN (s);
612
613 if (ms->grabIndex)
614 {
615 int i;
616
617 for (i = 0; i < NUM_KEYS; i++)
618 {
619 if (event->xkey.keycode == md->key[i])
620 {
621 XWarpPointer (d->display, None, None, 0, 0, 0, 0,
622 mKeys[i].dx * KEY_MOVE_INC,
623 mKeys[i].dy * KEY_MOVE_INC);
624 break;
625 }
626 }
627 }
628 }
629 break;
630 case MotionNotify:
631 s = findScreenAtDisplay (d, event->xmotion.root);
632 if (s)
633 moveHandleMotionEvent (s, pointerX, pointerY);
634 break;
635 case EnterNotify:
636 case LeaveNotify:
637 s = findScreenAtDisplay (d, event->xcrossing.root);
638 if (s)
639 moveHandleMotionEvent (s, pointerX, pointerY);
640 break;
641 case ClientMessage:
642 if (event->xclient.message_type == d->wmMoveResizeAtom)
643 {
644 CompWindow *w;
645
646 if (event->xclient.data.l[2] == WmMoveResizeMove ||
647 event->xclient.data.l[2] == WmMoveResizeMoveKeyboard)
648 {
649 w = findWindowAtDisplay (d, event->xclient.window);
650 if (w)
651 {
652 CompOption o[6];
653 int xRoot, yRoot;
654 int option;
655
656 o[0].type = CompOptionTypeInt;
657 o[0].name = "window";
658 o[0].value.i = event->xclient.window;
659
660 o[1].type = CompOptionTypeBool;
661 o[1].name = "external";
662 o[1].value.b = TRUE;
663
664 if (event->xclient.data.l[2] == WmMoveResizeMoveKeyboard)
665 {
666 option = MOVE_DISPLAY_OPTION_INITIATE_KEY;
667
668 moveInitiate (d, &md->opt[option].value.action,
669 CompActionStateInitKey,
670 o, 2);
671 }
672 else
673 {
674 unsigned int mods;
675 Window root, child;
676 int i;
677
678 option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
679
680 XQueryPointer (d->display, w->screen->root,
681 &root, &child, &xRoot, &yRoot,
682 &i, &i, &mods);
683
684 /* TODO: not only button 1 */
685 if (mods & Button1Mask)
686 {
687 o[2].type = CompOptionTypeInt;
688 o[2].name = "modifiers";
689 o[2].value.i = mods;
690
691 o[3].type = CompOptionTypeInt;
692 o[3].name = "x";
693 o[3].value.i = event->xclient.data.l[0];
694
695 o[4].type = CompOptionTypeInt;
696 o[4].name = "y";
697 o[4].value.i = event->xclient.data.l[1];
698
699 o[5].type = CompOptionTypeInt;
700 o[5].name = "button";
701 o[5].value.i = event->xclient.data.l[3] ?
702 event->xclient.data.l[3] : -1;
703
704 moveInitiate (d,
705 &md->opt[option].value.action,
706 CompActionStateInitButton,
707 o, 6);
708
709 moveHandleMotionEvent (w->screen, xRoot, yRoot);
710 }
711 }
712 }
713 }
714 else if (md->w && event->xclient.data.l[2] == WmMoveResizeCancel)
715 {
716 if (md->w->id == event->xclient.window)
717 {
718 int option;
719
720 option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
721 moveTerminate (d,
722 &md->opt[option].value.action,
723 CompActionStateCancel, NULL, 0);
724 option = MOVE_DISPLAY_OPTION_INITIATE_KEY;
725 moveTerminate (d,
726 &md->opt[option].value.action,
727 CompActionStateCancel, NULL, 0);
728 }
729 }
730 }
731 break;
732 case DestroyNotify:
733 if (md->w && md->w->id == event->xdestroywindow.window)
734 {
735 int option;
736
737 option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
738 moveTerminate (d,
739 &md->opt[option].value.action,
740 0, NULL, 0);
741 option = MOVE_DISPLAY_OPTION_INITIATE_KEY;
742 moveTerminate (d,
743 &md->opt[option].value.action,
744 0, NULL, 0);
745 }
746 break;
747 case UnmapNotify:
748 if (md->w && md->w->id == event->xunmap.window)
749 {
750 int option;
751
752 option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
753 moveTerminate (d,
754 &md->opt[option].value.action,
755 0, NULL, 0);
756 option = MOVE_DISPLAY_OPTION_INITIATE_KEY;
757 moveTerminate (d,
758 &md->opt[option].value.action,
759 0, NULL, 0);
760 }
761 default:
762 break;
763 }
764
765 UNWRAP (md, d, handleEvent);
766 (*d->handleEvent) (d, event);
767 WRAP (md, d, handleEvent, moveHandleEvent);
768 }
769
770 static Bool
movePaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)771 movePaintWindow (CompWindow *w,
772 const WindowPaintAttrib *attrib,
773 const CompTransform *transform,
774 Region region,
775 unsigned int mask)
776 {
777 WindowPaintAttrib sAttrib;
778 CompScreen *s = w->screen;
779 Bool status;
780
781 MOVE_SCREEN (s);
782
783 if (ms->grabIndex)
784 {
785 MOVE_DISPLAY (s->display);
786
787 if (md->w == w && md->moveOpacity != OPAQUE)
788 {
789 /* modify opacity of windows that are not active */
790 sAttrib = *attrib;
791 attrib = &sAttrib;
792
793 sAttrib.opacity = (sAttrib.opacity * md->moveOpacity) >> 16;
794 }
795 }
796
797 UNWRAP (ms, s, paintWindow);
798 status = (*s->paintWindow) (w, attrib, transform, region, mask);
799 WRAP (ms, s, paintWindow, movePaintWindow);
800
801 return status;
802 }
803
804 static CompOption *
moveGetDisplayOptions(CompPlugin * plugin,CompDisplay * display,int * count)805 moveGetDisplayOptions (CompPlugin *plugin,
806 CompDisplay *display,
807 int *count)
808 {
809 MOVE_DISPLAY (display);
810
811 *count = NUM_OPTIONS (md);
812 return md->opt;
813 }
814
815 static Bool
moveSetDisplayOption(CompPlugin * plugin,CompDisplay * display,const char * name,CompOptionValue * value)816 moveSetDisplayOption (CompPlugin *plugin,
817 CompDisplay *display,
818 const char *name,
819 CompOptionValue *value)
820 {
821 CompOption *o;
822 int index;
823
824 MOVE_DISPLAY (display);
825
826 o = compFindOption (md->opt, NUM_OPTIONS (md), name, &index);
827 if (!o)
828 return FALSE;
829
830 switch (index) {
831 case MOVE_DISPLAY_OPTION_OPACITY:
832 if (compSetIntOption (o, value))
833 {
834 md->moveOpacity = (o->value.i * OPAQUE) / 100;
835 return TRUE;
836 }
837 break;
838 default:
839 return compSetDisplayOption (display, o, value);
840 }
841
842 return FALSE;
843 }
844
845 static const CompMetadataOptionInfo moveDisplayOptionInfo[] = {
846 { "initiate_button", "button", 0, moveInitiate, moveTerminate },
847 { "initiate_key", "key", 0, moveInitiate, moveTerminate },
848 { "opacity", "int", "<min>0</min><max>100</max>", 0, 0 },
849 { "constrain_y", "bool", 0, 0, 0 },
850 { "snapoff_maximized", "bool", 0, 0, 0 },
851 { "lazy_positioning", "bool", 0, 0, 0 }
852 };
853
854 static Bool
moveInitDisplay(CompPlugin * p,CompDisplay * d)855 moveInitDisplay (CompPlugin *p,
856 CompDisplay *d)
857 {
858 MoveDisplay *md;
859 int i;
860
861 if (!checkPluginABI ("core", CORE_ABIVERSION))
862 return FALSE;
863
864 md = malloc (sizeof (MoveDisplay));
865 if (!md)
866 return FALSE;
867
868 if (!compInitDisplayOptionsFromMetadata (d,
869 &moveMetadata,
870 moveDisplayOptionInfo,
871 md->opt,
872 MOVE_DISPLAY_OPTION_NUM))
873 {
874 free (md);
875 return FALSE;
876 }
877
878 md->screenPrivateIndex = allocateScreenPrivateIndex (d);
879 if (md->screenPrivateIndex < 0)
880 {
881 compFiniDisplayOptions (d, md->opt, MOVE_DISPLAY_OPTION_NUM);
882 free (md);
883 return FALSE;
884 }
885
886 md->moveOpacity =
887 (md->opt[MOVE_DISPLAY_OPTION_OPACITY].value.i * OPAQUE) / 100;
888
889 md->w = 0;
890 md->region = NULL;
891 md->status = RectangleOut;
892 md->releaseButton = 0;
893 md->constrainY = FALSE;
894
895 for (i = 0; i < NUM_KEYS; i++)
896 md->key[i] = XKeysymToKeycode (d->display,
897 XStringToKeysym (mKeys[i].name));
898
899 WRAP (md, d, handleEvent, moveHandleEvent);
900
901 d->base.privates[displayPrivateIndex].ptr = md;
902
903 return TRUE;
904 }
905
906 static void
moveFiniDisplay(CompPlugin * p,CompDisplay * d)907 moveFiniDisplay (CompPlugin *p,
908 CompDisplay *d)
909 {
910 MOVE_DISPLAY (d);
911
912 freeScreenPrivateIndex (d, md->screenPrivateIndex);
913
914 UNWRAP (md, d, handleEvent);
915
916 compFiniDisplayOptions (d, md->opt, MOVE_DISPLAY_OPTION_NUM);
917
918 if (md->region)
919 XDestroyRegion (md->region);
920
921 free (md);
922 }
923
924 static Bool
moveInitScreen(CompPlugin * p,CompScreen * s)925 moveInitScreen (CompPlugin *p,
926 CompScreen *s)
927 {
928 MoveScreen *ms;
929
930 MOVE_DISPLAY (s->display);
931
932 ms = malloc (sizeof (MoveScreen));
933 if (!ms)
934 return FALSE;
935
936 ms->grabIndex = 0;
937
938 ms->moveCursor = XCreateFontCursor (s->display->display, XC_fleur);
939
940 WRAP (ms, s, paintWindow, movePaintWindow);
941
942 s->base.privates[md->screenPrivateIndex].ptr = ms;
943
944 return TRUE;
945 }
946
947 static void
moveFiniScreen(CompPlugin * p,CompScreen * s)948 moveFiniScreen (CompPlugin *p,
949 CompScreen *s)
950 {
951 MOVE_SCREEN (s);
952
953 UNWRAP (ms, s, paintWindow);
954
955 if (ms->moveCursor)
956 XFreeCursor (s->display->display, ms->moveCursor);
957
958 free (ms);
959 }
960
961 static CompBool
moveInitObject(CompPlugin * p,CompObject * o)962 moveInitObject (CompPlugin *p,
963 CompObject *o)
964 {
965 static InitPluginObjectProc dispTab[] = {
966 (InitPluginObjectProc) 0, /* InitCore */
967 (InitPluginObjectProc) moveInitDisplay,
968 (InitPluginObjectProc) moveInitScreen
969 };
970
971 RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
972 }
973
974 static void
moveFiniObject(CompPlugin * p,CompObject * o)975 moveFiniObject (CompPlugin *p,
976 CompObject *o)
977 {
978 static FiniPluginObjectProc dispTab[] = {
979 (FiniPluginObjectProc) 0, /* FiniCore */
980 (FiniPluginObjectProc) moveFiniDisplay,
981 (FiniPluginObjectProc) moveFiniScreen
982 };
983
984 DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
985 }
986
987 static CompOption *
moveGetObjectOptions(CompPlugin * plugin,CompObject * object,int * count)988 moveGetObjectOptions (CompPlugin *plugin,
989 CompObject *object,
990 int *count)
991 {
992 static GetPluginObjectOptionsProc dispTab[] = {
993 (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
994 (GetPluginObjectOptionsProc) moveGetDisplayOptions
995 };
996
997 *count = 0;
998 RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
999 (void *) count, (plugin, object, count));
1000 }
1001
1002 static CompBool
moveSetObjectOption(CompPlugin * plugin,CompObject * object,const char * name,CompOptionValue * value)1003 moveSetObjectOption (CompPlugin *plugin,
1004 CompObject *object,
1005 const char *name,
1006 CompOptionValue *value)
1007 {
1008 static SetPluginObjectOptionProc dispTab[] = {
1009 (SetPluginObjectOptionProc) 0, /* SetCoreOption */
1010 (SetPluginObjectOptionProc) moveSetDisplayOption
1011 };
1012
1013 RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
1014 (plugin, object, name, value));
1015 }
1016
1017 static Bool
moveInit(CompPlugin * p)1018 moveInit (CompPlugin *p)
1019 {
1020 if (!compInitPluginMetadataFromInfo (&moveMetadata,
1021 p->vTable->name,
1022 moveDisplayOptionInfo,
1023 MOVE_DISPLAY_OPTION_NUM,
1024 0, 0))
1025 return FALSE;
1026
1027 displayPrivateIndex = allocateDisplayPrivateIndex ();
1028 if (displayPrivateIndex < 0)
1029 {
1030 compFiniMetadata (&moveMetadata);
1031 return FALSE;
1032 }
1033
1034 compAddMetadataFromFile (&moveMetadata, p->vTable->name);
1035
1036 return TRUE;
1037 }
1038
1039 static void
moveFini(CompPlugin * p)1040 moveFini (CompPlugin *p)
1041 {
1042 freeDisplayPrivateIndex (displayPrivateIndex);
1043 compFiniMetadata (&moveMetadata);
1044 }
1045
1046 static CompMetadata *
moveGetMetadata(CompPlugin * plugin)1047 moveGetMetadata (CompPlugin *plugin)
1048 {
1049 return &moveMetadata;
1050 }
1051
1052 CompPluginVTable moveVTable = {
1053 "move",
1054 moveGetMetadata,
1055 moveInit,
1056 moveFini,
1057 moveInitObject,
1058 moveFiniObject,
1059 moveGetObjectOptions,
1060 moveSetObjectOption
1061 };
1062
1063 CompPluginVTable *
getCompPluginInfo20070830(void)1064 getCompPluginInfo20070830 (void)
1065 {
1066 return &moveVTable;
1067 }
1068