1 /*
2 * Copyright © 2006 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 <compiz-core.h>
33
34 static CompMetadata cloneMetadata;
35
36 static int displayPrivateIndex;
37
38 #define CLONE_DISPLAY_OPTION_INITIATE_BUTTON 0
39 #define CLONE_DISPLAY_OPTION_NUM 1
40
41 typedef struct _CloneDisplay {
42 int screenPrivateIndex;
43 HandleEventProc handleEvent;
44
45 CompOption opt[CLONE_DISPLAY_OPTION_NUM];
46 } CloneDisplay;
47
48 typedef struct _CloneClone {
49 int src;
50 int dst;
51 Region region;
52 Window input;
53 } CloneClone;
54
55 typedef struct _CloneScreen {
56 PreparePaintScreenProc preparePaintScreen;
57 DonePaintScreenProc donePaintScreen;
58 PaintOutputProc paintOutput;
59 PaintWindowProc paintWindow;
60 OutputChangeNotifyProc outputChangeNotify;
61
62 int grabIndex;
63 Bool grab;
64
65 float offset;
66
67 Bool transformed;
68
69 CloneClone *clone;
70 int nClone;
71
72 int x, y;
73 int grabbedOutput;
74 int src, dst;
75 } CloneScreen;
76
77 #define GET_CLONE_DISPLAY(d) \
78 ((CloneDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
79
80 #define CLONE_DISPLAY(d) \
81 CloneDisplay *cd = GET_CLONE_DISPLAY (d)
82
83 #define GET_CLONE_SCREEN(s, cd) \
84 ((CloneScreen *) (s)->base.privates[(cd)->screenPrivateIndex].ptr)
85
86 #define CLONE_SCREEN(s) \
87 CloneScreen *cs = GET_CLONE_SCREEN (s, GET_CLONE_DISPLAY (s->display))
88
89 #define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
90
91 static void
cloneRemove(CompScreen * s,int i)92 cloneRemove (CompScreen *s,
93 int i)
94 {
95 CloneClone *clone;
96
97 CLONE_SCREEN (s);
98
99 clone = malloc (sizeof (CloneClone) * (cs->nClone - 1));
100 if (clone)
101 {
102 int j, k = 0;
103
104 for (j = 0; j < cs->nClone; j++)
105 if (j != i)
106 memcpy (&clone[k++], &cs->clone[j],
107 sizeof (CloneClone));
108
109 XDestroyRegion (cs->clone[i].region);
110 XDestroyWindow (s->display->display, cs->clone[i].input);
111
112 free (cs->clone);
113
114 cs->clone = clone;
115 cs->nClone--;
116 }
117 }
118
119 static void
cloneFinish(CompScreen * s)120 cloneFinish (CompScreen *s)
121 {
122 CloneClone *clone;
123 int i;
124
125 CLONE_SCREEN (s);
126
127 cs->grab = FALSE;
128
129 if (cs->src != cs->dst)
130 {
131 clone = NULL;
132
133 /* check if we should replace current clone */
134 for (i = 0; i < cs->nClone; i++)
135 {
136 if (cs->clone[i].dst == cs->dst)
137 {
138 clone = &cs->clone[i];
139 break;
140 }
141 }
142
143 /* no existing clone for this destination, we must allocate one */
144 if (!clone)
145 {
146 Region region;
147
148 region = XCreateRegion ();
149 if (region)
150 {
151 clone =
152 realloc (cs->clone,
153 sizeof (CloneClone) * (cs->nClone + 1));
154 if (clone)
155 {
156 XSetWindowAttributes attr;
157 int x, y;
158
159 cs->clone = clone;
160 clone = &cs->clone[cs->nClone++];
161 clone->region = region;
162
163 attr.override_redirect = TRUE;
164
165 x = s->outputDev[cs->dst].region.extents.x1;
166 y = s->outputDev[cs->dst].region.extents.y1;
167
168 clone->input =
169 XCreateWindow (s->display->display,
170 s->root, x, y,
171 s->outputDev[cs->dst].width,
172 s->outputDev[cs->dst].height,
173 0, 0, InputOnly, CopyFromParent,
174 CWOverrideRedirect, &attr);
175 XMapRaised (s->display->display, clone->input);
176 }
177 else
178 {
179 XDestroyRegion (region);
180 }
181 }
182 }
183
184 if (clone)
185 {
186 clone->src = cs->src;
187 clone->dst = cs->dst;
188 }
189 }
190
191 if (cs->grabbedOutput != cs->dst)
192 {
193 /* remove clone */
194 for (i = 0; i < cs->nClone; i++)
195 {
196 if (cs->clone[i].dst == cs->grabbedOutput)
197 {
198 cloneRemove (s, i);
199 break;
200 }
201 }
202 }
203 }
204
205 static void
clonePreparePaintScreen(CompScreen * s,int msSinceLastPaint)206 clonePreparePaintScreen (CompScreen *s,
207 int msSinceLastPaint)
208 {
209 int i;
210
211 CLONE_SCREEN (s);
212
213 if (cs->grab)
214 {
215 if (cs->grabIndex)
216 {
217 cs->offset -= msSinceLastPaint * 0.005f;
218 if (cs->offset < 0.0f)
219 cs->offset = 0.0f;
220 }
221 else
222 {
223 cs->offset += msSinceLastPaint * 0.005f;
224 if (cs->offset >= 1.0f)
225 cs->offset = 1.0f;
226 }
227 }
228
229 UNWRAP (cs, s, preparePaintScreen);
230 (*s->preparePaintScreen) (s, msSinceLastPaint);
231 WRAP (cs, s, preparePaintScreen, clonePreparePaintScreen);
232
233 for (i = 0; i < cs->nClone; i++)
234 {
235 CompOutput *src = &s->outputDev[cs->clone[i].src];
236 CompOutput *dst = &s->outputDev[cs->clone[i].dst];
237 int dx, dy;
238
239 dx = dst->region.extents.x1 - src->region.extents.x1;
240 dy = dst->region.extents.y1 - src->region.extents.y1;
241
242 if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
243 {
244 if (src->width != dst->width || src->height != dst->height)
245 {
246 XSubtractRegion (&dst->region, &emptyRegion,
247 cs->clone[i].region);
248 XUnionRegion (s->damage, cs->clone[i].region, s->damage);
249 XSubtractRegion (&src->region, &emptyRegion,
250 cs->clone[i].region);
251 }
252 else
253 {
254 XSubtractRegion (s->damage, &dst->region, cs->clone[i].region);
255 XOffsetRegion (cs->clone[i].region, dx, dy);
256 XUnionRegion (s->damage, cs->clone[i].region, s->damage);
257 XSubtractRegion (s->damage, &src->region, cs->clone[i].region);
258 XOffsetRegion (cs->clone[i].region, -dx, -dy);
259 }
260 }
261 else
262 {
263 XSubtractRegion (&src->region, &emptyRegion, cs->clone[i].region);
264 }
265 }
266 }
267
268 static void
cloneDonePaintScreen(CompScreen * s)269 cloneDonePaintScreen (CompScreen *s)
270 {
271 CLONE_SCREEN (s);
272
273 if (cs->grab)
274 {
275 if (cs->offset == 1.0f)
276 cloneFinish (s);
277
278 damageScreen (s);
279 }
280
281 UNWRAP (cs, s, donePaintScreen);
282 (*s->donePaintScreen) (s);
283 WRAP (cs, s, donePaintScreen, cloneDonePaintScreen);
284 }
285
286 static Bool
clonePaintOutput(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * outputPtr,unsigned int mask)287 clonePaintOutput (CompScreen *s,
288 const ScreenPaintAttrib *sAttrib,
289 const CompTransform *transform,
290 Region region,
291 CompOutput *outputPtr,
292 unsigned int mask)
293 {
294 Bool status;
295 int i, dst, output = 0;
296
297 CLONE_SCREEN (s);
298
299 dst = output = (outputPtr->id != ~0) ? outputPtr->id : 0;
300
301 if (!cs->grab || cs->grabbedOutput != output)
302 {
303 for (i = 0; i < cs->nClone; i++)
304 {
305 if (cs->clone[i].dst == output)
306 {
307 region = cs->clone[i].region;
308 dst = cs->clone[i].src;
309
310 if (s->outputDev[dst].width != s->outputDev[output].width ||
311 s->outputDev[dst].height != s->outputDev[output].height )
312 cs->transformed = TRUE;
313 else
314 cs->transformed = FALSE;
315
316 break;
317 }
318 }
319 }
320
321 UNWRAP (cs, s, paintOutput);
322 if (outputPtr->id != ~0)
323 status = (*s->paintOutput) (s, sAttrib, transform, region,
324 &s->outputDev[dst], mask);
325 else
326 status = (*s->paintOutput) (s, sAttrib, transform, region,
327 outputPtr, mask);
328 WRAP (cs, s, paintOutput, clonePaintOutput);
329
330 if (cs->grab)
331 {
332 CompTransform sTransform = *transform;
333 CompWindow *w;
334 GLenum filter;
335 float zoom1, zoom2x, zoom2y, x1, y1, x2, y2;
336 float zoomX, zoomY;
337 int dx, dy;
338
339 zoom1 = 160.0f / s->outputDev[cs->src].height;
340
341 x1 = cs->x - (s->outputDev[cs->src].region.extents.x1 * zoom1);
342 y1 = cs->y - (s->outputDev[cs->src].region.extents.y1 * zoom1);
343
344 x1 -= (s->outputDev[cs->src].width * zoom1) / 2;
345 y1 -= (s->outputDev[cs->src].height * zoom1) / 2;
346
347 if (cs->grabIndex)
348 {
349 x2 = s->outputDev[cs->grabbedOutput].region.extents.x1 -
350 s->outputDev[cs->src].region.extents.x1;
351 y2 = s->outputDev[cs->grabbedOutput].region.extents.y1 -
352 s->outputDev[cs->src].region.extents.y1;
353
354 zoom2x = (float) s->outputDev[cs->grabbedOutput].width /
355 s->outputDev[cs->src].width;
356 zoom2y = (float) s->outputDev[cs->grabbedOutput].height /
357 s->outputDev[cs->src].height;
358 }
359 else
360 {
361 x2 = s->outputDev[cs->dst].region.extents.x1 -
362 s->outputDev[cs->src].region.extents.x1;
363 y2 = s->outputDev[cs->dst].region.extents.y1 -
364 s->outputDev[cs->src].region.extents.y1;
365
366 zoom2x = (float) s->outputDev[cs->dst].width /
367 s->outputDev[cs->src].width;
368 zoom2y = (float) s->outputDev[cs->dst].height /
369 s->outputDev[cs->src].height;
370 }
371
372 /* XXX: hmm.. why do I need this.. */
373 if (x2 < 0.0f)
374 x2 *= zoom2x;
375 if (y2 < 0.0f)
376 y2 *= zoom2y;
377
378 dx = x1 * (1.0f - cs->offset) + x2 * cs->offset;
379 dy = y1 * (1.0f - cs->offset) + y2 * cs->offset;
380
381 zoomX = zoom1 * (1.0f - cs->offset) + zoom2x * cs->offset;
382 zoomY = zoom1 * (1.0f - cs->offset) + zoom2y * cs->offset;
383
384 matrixTranslate (&sTransform, -0.5f, -0.5f, -DEFAULT_Z_CAMERA);
385 matrixScale (&sTransform,
386 1.0f / s->outputDev[output].width,
387 -1.0f / s->outputDev[output].height,
388 1.0f);
389 matrixTranslate (&sTransform,
390 dx - s->outputDev[output].region.extents.x1,
391 dy - s->outputDev[output].region.extents.y2,
392 0.0f);
393 matrixScale (&sTransform, zoomX, zoomY, 1.0f);
394
395 glPushMatrix ();
396 glLoadMatrixf (sTransform.m);
397
398 filter = s->display->textureFilter;
399
400 if (cs->offset == 0.0f)
401 s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
402
403 for (w = s->windows; w; w = w->next)
404 {
405 if (w->destroyed)
406 continue;
407
408 if (!w->shaded)
409 {
410 if (w->attrib.map_state != IsViewable || !w->damaged)
411 continue;
412 }
413
414 (*s->paintWindow) (w, &w->paint, &sTransform,
415 &s->outputDev[cs->src].region,
416 PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);
417 }
418
419 s->display->textureFilter = filter;
420
421 glPopMatrix ();
422 }
423
424 return status;
425 }
426
427 static Bool
clonePaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)428 clonePaintWindow (CompWindow *w,
429 const WindowPaintAttrib *attrib,
430 const CompTransform *transform,
431 Region region,
432 unsigned int mask)
433 {
434 Bool status;
435
436 CLONE_SCREEN (w->screen);
437
438 if (cs->nClone && cs->transformed)
439 mask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
440
441 UNWRAP (cs, w->screen, paintWindow);
442 status = (*w->screen->paintWindow) (w, attrib, transform, region, mask);
443 WRAP (cs, w->screen, paintWindow, clonePaintWindow);
444
445 return status;
446 }
447
448 static Bool
cloneInitiate(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)449 cloneInitiate (CompDisplay *d,
450 CompAction *action,
451 CompActionState state,
452 CompOption *option,
453 int nOption)
454 {
455 CompScreen *s;
456 Window xid;
457
458 xid = getIntOptionNamed (option, nOption, "root", 0);
459
460 s = findScreenAtDisplay (d, xid);
461 if (s)
462 {
463 int i;
464
465 CLONE_SCREEN (s);
466
467 if (cs->grab || otherScreenGrabExist (s, "clone", NULL))
468 return FALSE;
469
470 if (!cs->grabIndex)
471 cs->grabIndex = pushScreenGrab (s, None, "clone");
472
473 cs->grab = TRUE;
474
475 cs->x = getIntOptionNamed (option, nOption, "x", 0);
476 cs->y = getIntOptionNamed (option, nOption, "y", 0);
477
478 cs->src = cs->grabbedOutput = outputDeviceForPoint (s, cs->x, cs->y);
479
480 /* trace source */
481 i = 0;
482 while (i < cs->nClone)
483 {
484 if (cs->clone[i].dst == cs->src)
485 {
486 cs->src = cs->clone[i].src;
487 i = 0;
488 }
489 else
490 {
491 i++;
492 }
493 }
494
495 if (state & CompActionStateInitButton)
496 action->state |= CompActionStateTermButton;
497 }
498
499 return FALSE;
500 }
501
502 static Bool
cloneTerminate(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)503 cloneTerminate (CompDisplay *d,
504 CompAction *action,
505 CompActionState state,
506 CompOption *option,
507 int nOption)
508 {
509 CompScreen *s;
510 Window xid;
511
512 xid = getIntOptionNamed (option, nOption, "root", 0);
513
514 for (s = d->screens; s; s = s->next)
515 {
516 CLONE_SCREEN (s);
517
518 if (xid && s->root != xid)
519 continue;
520
521 if (cs->grabIndex)
522 {
523 int x, y;
524
525 removeScreenGrab (s, cs->grabIndex, NULL);
526 cs->grabIndex = 0;
527
528 x = getIntOptionNamed (option, nOption, "x", 0);
529 y = getIntOptionNamed (option, nOption, "y", 0);
530
531 cs->dst = outputDeviceForPoint (s, x, y);
532
533 damageScreen (s);
534 }
535 }
536
537 action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
538
539 return FALSE;
540 }
541
542 static void
cloneSetStrutsForCloneWindow(CompScreen * s,CloneClone * clone)543 cloneSetStrutsForCloneWindow (CompScreen *s,
544 CloneClone *clone)
545 {
546 CompOutput *output = &s->outputDev[clone->dst];
547 XRectangle *rect = NULL;
548 CompStruts *struts;
549 CompWindow *w;
550
551 w = findWindowAtScreen (s, clone->input);
552 if (!w)
553 return;
554
555 struts = malloc (sizeof (CompStruts));
556 if (!struts)
557 return;
558
559 if (w->struts)
560 free (w->struts);
561
562 struts->left.x = 0;
563 struts->left.y = 0;
564 struts->left.width = 0;
565 struts->left.height = s->height;
566
567 struts->right.x = s->width;
568 struts->right.y = 0;
569 struts->right.width = 0;
570 struts->right.height = s->height;
571
572 struts->top.x = 0;
573 struts->top.y = 0;
574 struts->top.width = s->width;
575 struts->top.height = 0;
576
577 struts->bottom.x = 0;
578 struts->bottom.y = s->height;
579 struts->bottom.width = s->width;
580 struts->bottom.height = 0;
581
582 /* create struts relative to a screen edge that this output is next to */
583 if (output->region.extents.x1 == 0)
584 rect = &struts->left;
585 else if (output->region.extents.x2 == s->width)
586 rect = &struts->right;
587 else if (output->region.extents.y1 == 0)
588 rect = &struts->top;
589 else if (output->region.extents.y2 == s->height)
590 rect = &struts->bottom;
591
592 if (rect)
593 {
594 rect->x = output->region.extents.x1;
595 rect->y = output->region.extents.y1;
596 rect->width = output->width;
597 rect->height = output->height;
598 }
599
600 w->struts = struts;
601 }
602
603 static void
cloneHandleMotionEvent(CompScreen * s,int xRoot,int yRoot)604 cloneHandleMotionEvent (CompScreen *s,
605 int xRoot,
606 int yRoot)
607 {
608 CLONE_SCREEN (s);
609
610 if (cs->grabIndex)
611 {
612 cs->x = xRoot;
613 cs->y = yRoot;
614
615 damageScreen (s);
616 }
617 }
618
619 static void
cloneHandleEvent(CompDisplay * d,XEvent * event)620 cloneHandleEvent (CompDisplay *d,
621 XEvent *event)
622 {
623 CompScreen *s;
624
625 CLONE_DISPLAY (d);
626
627 switch (event->type) {
628 case MotionNotify:
629 s = findScreenAtDisplay (d, event->xmotion.root);
630 if (s)
631 cloneHandleMotionEvent (s, pointerX, pointerY);
632 break;
633 case EnterNotify:
634 case LeaveNotify:
635 s = findScreenAtDisplay (d, event->xcrossing.root);
636 if (s)
637 cloneHandleMotionEvent (s, pointerX, pointerY);
638 default:
639 break;
640 }
641
642 UNWRAP (cd, d, handleEvent);
643 (*d->handleEvent) (d, event);
644 WRAP (cd, d, handleEvent, cloneHandleEvent);
645
646 switch (event->type) {
647 case CreateNotify:
648 s = findScreenAtDisplay (d, event->xcreatewindow.parent);
649 if (s)
650 {
651 int i;
652
653 CLONE_SCREEN (s);
654
655 for (i = 0; i < cs->nClone; i++)
656 if (event->xcreatewindow.window == cs->clone[i].input)
657 cloneSetStrutsForCloneWindow (s, &cs->clone[i]);
658 }
659 default:
660 break;
661 }
662 }
663
664 static void
cloneOutputChangeNotify(CompScreen * s)665 cloneOutputChangeNotify (CompScreen *s)
666 {
667 int i;
668
669 CLONE_SCREEN (s);
670
671 /* remove clones with destination or source that doesn't exist */
672 for (i = 0; i < cs->nClone; i++)
673 {
674 if (cs->clone[i].dst >= s->nOutputDev ||
675 cs->clone[i].src >= s->nOutputDev)
676 {
677 cloneRemove (s, i);
678 i = 0;
679 continue;
680 }
681 }
682
683 UNWRAP (cs, s, outputChangeNotify);
684 (*s->outputChangeNotify) (s);
685 WRAP (cs, s, outputChangeNotify, cloneOutputChangeNotify);
686 }
687
688 static CompOption *
cloneGetDisplayOptions(CompPlugin * plugin,CompDisplay * display,int * count)689 cloneGetDisplayOptions (CompPlugin *plugin,
690 CompDisplay *display,
691 int *count)
692 {
693 CLONE_DISPLAY (display);
694
695 *count = NUM_OPTIONS (cd);
696 return cd->opt;
697 }
698
699 static Bool
cloneSetDisplayOption(CompPlugin * plugin,CompDisplay * display,const char * name,CompOptionValue * value)700 cloneSetDisplayOption (CompPlugin *plugin,
701 CompDisplay *display,
702 const char *name,
703 CompOptionValue *value)
704 {
705 CompOption *o;
706
707 CLONE_DISPLAY (display);
708
709 o = compFindOption (cd->opt, NUM_OPTIONS (cd), name, NULL);
710 if (!o)
711 return FALSE;
712
713 return compSetDisplayOption (display, o, value);
714 }
715
716 static const CompMetadataOptionInfo cloneDisplayOptionInfo[] = {
717 { "initiate_button", "button", 0, cloneInitiate, cloneTerminate }
718 };
719
720 static Bool
cloneInitDisplay(CompPlugin * p,CompDisplay * d)721 cloneInitDisplay (CompPlugin *p,
722 CompDisplay *d)
723 {
724 CloneDisplay *cd;
725
726 if (!checkPluginABI ("core", CORE_ABIVERSION))
727 return FALSE;
728
729 cd = malloc (sizeof (CloneDisplay));
730 if (!cd)
731 return FALSE;
732
733 if (!compInitDisplayOptionsFromMetadata (d,
734 &cloneMetadata,
735 cloneDisplayOptionInfo,
736 cd->opt,
737 CLONE_DISPLAY_OPTION_NUM))
738 {
739 free (cd);
740 return FALSE;
741 }
742
743 cd->screenPrivateIndex = allocateScreenPrivateIndex (d);
744 if (cd->screenPrivateIndex < 0)
745 {
746 compFiniDisplayOptions (d, cd->opt, CLONE_DISPLAY_OPTION_NUM);
747 free (cd);
748 return FALSE;
749 }
750
751 WRAP (cd, d, handleEvent, cloneHandleEvent);
752
753 d->base.privates[displayPrivateIndex].ptr = cd;
754
755 return TRUE;
756 }
757
758 static void
cloneFiniDisplay(CompPlugin * p,CompDisplay * d)759 cloneFiniDisplay (CompPlugin *p,
760 CompDisplay *d)
761 {
762 CLONE_DISPLAY (d);
763
764 freeScreenPrivateIndex (d, cd->screenPrivateIndex);
765
766 UNWRAP (cd, d, handleEvent);
767
768 compFiniDisplayOptions (d, cd->opt, CLONE_DISPLAY_OPTION_NUM);
769
770 free (cd);
771 }
772
773 static Bool
cloneInitScreen(CompPlugin * p,CompScreen * s)774 cloneInitScreen (CompPlugin *p,
775 CompScreen *s)
776 {
777 CloneScreen *cs;
778
779 CLONE_DISPLAY (s->display);
780
781 cs = malloc (sizeof (CloneScreen));
782 if (!cs)
783 return FALSE;
784
785 cs->grabIndex = 0;
786 cs->grab = FALSE;
787
788 cs->offset = 1.0f;
789
790 cs->transformed = FALSE;
791
792 cs->nClone = 0;
793 cs->clone = NULL;
794
795 cs->src = 0;
796
797 WRAP (cs, s, preparePaintScreen, clonePreparePaintScreen);
798 WRAP (cs, s, donePaintScreen, cloneDonePaintScreen);
799 WRAP (cs, s, paintOutput, clonePaintOutput);
800 WRAP (cs, s, paintWindow, clonePaintWindow);
801 WRAP (cs, s, outputChangeNotify, cloneOutputChangeNotify);
802
803 s->base.privates[cd->screenPrivateIndex].ptr = cs;
804
805 return TRUE;
806 }
807
808 static void
cloneFiniScreen(CompPlugin * p,CompScreen * s)809 cloneFiniScreen (CompPlugin *p,
810 CompScreen *s)
811 {
812 int i;
813
814 CLONE_SCREEN (s);
815
816 for (i = 0; i < cs->nClone; i++)
817 cloneRemove (s, i);
818
819 if (cs->clone)
820 free (cs->clone);
821
822 UNWRAP (cs, s, preparePaintScreen);
823 UNWRAP (cs, s, donePaintScreen);
824 UNWRAP (cs, s, paintOutput);
825 UNWRAP (cs, s, paintWindow);
826 UNWRAP (cs, s, outputChangeNotify);
827
828 free (cs);
829 }
830
831 static CompBool
cloneInitObject(CompPlugin * p,CompObject * o)832 cloneInitObject (CompPlugin *p,
833 CompObject *o)
834 {
835 static InitPluginObjectProc dispTab[] = {
836 (InitPluginObjectProc) 0, /* InitCore */
837 (InitPluginObjectProc) cloneInitDisplay,
838 (InitPluginObjectProc) cloneInitScreen
839 };
840
841 RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
842 }
843
844 static void
cloneFiniObject(CompPlugin * p,CompObject * o)845 cloneFiniObject (CompPlugin *p,
846 CompObject *o)
847 {
848 static FiniPluginObjectProc dispTab[] = {
849 (FiniPluginObjectProc) 0, /* FiniCore */
850 (FiniPluginObjectProc) cloneFiniDisplay,
851 (FiniPluginObjectProc) cloneFiniScreen
852 };
853
854 DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
855 }
856
857 static CompOption *
cloneGetObjectOptions(CompPlugin * plugin,CompObject * object,int * count)858 cloneGetObjectOptions (CompPlugin *plugin,
859 CompObject *object,
860 int *count)
861 {
862 static GetPluginObjectOptionsProc dispTab[] = {
863 (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
864 (GetPluginObjectOptionsProc) cloneGetDisplayOptions
865 };
866
867 *count = 0;
868 RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
869 (void *) count, (plugin, object, count));
870 }
871
872 static CompBool
cloneSetObjectOption(CompPlugin * plugin,CompObject * object,const char * name,CompOptionValue * value)873 cloneSetObjectOption (CompPlugin *plugin,
874 CompObject *object,
875 const char *name,
876 CompOptionValue *value)
877 {
878 static SetPluginObjectOptionProc dispTab[] = {
879 (SetPluginObjectOptionProc) 0, /* SetCoreOption */
880 (SetPluginObjectOptionProc) cloneSetDisplayOption
881 };
882
883 RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
884 (plugin, object, name, value));
885 }
886
887 static Bool
cloneInit(CompPlugin * p)888 cloneInit (CompPlugin *p)
889 {
890 if (!compInitPluginMetadataFromInfo (&cloneMetadata,
891 p->vTable->name,
892 cloneDisplayOptionInfo,
893 CLONE_DISPLAY_OPTION_NUM,
894 0, 0))
895 return FALSE;
896
897 displayPrivateIndex = allocateDisplayPrivateIndex ();
898 if (displayPrivateIndex < 0)
899 {
900 compFiniMetadata (&cloneMetadata);
901 return FALSE;
902 }
903
904 compAddMetadataFromFile (&cloneMetadata, p->vTable->name);
905
906 return TRUE;
907 }
908
909 static void
cloneFini(CompPlugin * p)910 cloneFini (CompPlugin *p)
911 {
912 freeDisplayPrivateIndex (displayPrivateIndex);
913 compFiniMetadata (&cloneMetadata);
914 }
915
916 static CompMetadata *
cloneGetMetadata(CompPlugin * plugin)917 cloneGetMetadata (CompPlugin *plugin)
918 {
919 return &cloneMetadata;
920 }
921
922 CompPluginVTable cloneVTable = {
923 "clone",
924 cloneGetMetadata,
925 cloneInit,
926 cloneFini,
927 cloneInitObject,
928 cloneFiniObject,
929 cloneGetObjectOptions,
930 cloneSetObjectOption
931 };
932
933 CompPluginVTable *
getCompPluginInfo20070830(void)934 getCompPluginInfo20070830 (void)
935 {
936 return &cloneVTable;
937 }
938