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