1 /*
2  * Compiz/Fusion color filtering plugin
3  *
4  * Author : Guillaume Seguin
5  * Email : guillaume@segu.in
6  *
7  * Copyright (c) 2007 Guillaume Seguin <guillaume@segu.in>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22  */
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 
28 #include <compiz-core.h>
29 #include "parser.h"
30 #include "colorfilter_options.h"
31 
32 static int displayPrivateIndex;
33 static int corePrivateIndex;
34 
35 typedef struct _ColorFilterCore {
36     ObjectAddProc objectAdd;
37 } ColorFilterCore;
38 
39 typedef struct _ColorFilterDisplay
40 {
41     int		    screenPrivateIndex;
42 } ColorFilterDisplay;
43 
44 typedef struct _ColorFilterScreen
45 {
46     int			    windowPrivateIndex;
47 
48     DrawWindowTextureProc   drawWindowTexture;
49 
50     Bool		    isFiltered;
51     int			    currentFilter; /* 0 : cumulative mode
52 					      0 < c <= count : single mode */
53 
54     /* The plugin can not immediately load the filters because it needs to
55      * know what texture target it will use : when required, this boolean
56      * is set to TRUE and filters will be loaded on next filtered window
57      * texture painting */
58     Bool		    filtersLoaded;
59     int			    *filtersFunctions;
60     int			    filtersCount;
61 } ColorFilterScreen;
62 
63 typedef struct _ColorFilterWindow
64 {
65     Bool    isFiltered;
66 } ColorFilterWindow;
67 
68 #define GET_FILTER_CORE(c) \
69     ((ColorFilterCore *) (c)->base.privates[corePrivateIndex].ptr)
70 #define FILTER_CORE(c) \
71     ColorFilterCore *fc = GET_FILTER_CORE (c)
72 #define GET_FILTER_DISPLAY(d)					    \
73     ((ColorFilterDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
74 #define FILTER_DISPLAY(d)			    \
75     ColorFilterDisplay *cfd = GET_FILTER_DISPLAY (d)
76 #define GET_FILTER_SCREEN(s, cfd)					\
77     ((ColorFilterScreen *) (s)->base.privates[(cfd)->screenPrivateIndex].ptr)
78 #define FILTER_SCREEN(s)					\
79     ColorFilterScreen *cfs = GET_FILTER_SCREEN (s,		\
80 			     GET_FILTER_DISPLAY ((s)->display))
81 #define GET_FILTER_WINDOW(w, cfs)					\
82     ((ColorFilterWindow *) (w)->base.privates[(cfs)->windowPrivateIndex].ptr)
83 #define FILTER_WINDOW(w)						\
84     ColorFilterWindow *cfw = GET_FILTER_WINDOW  (w,			\
85 			     GET_FILTER_SCREEN  ((w)->screen,		\
86 			     GET_FILTER_DISPLAY ((w)->screen->display)))
87 
88 /* Compiz-core imports ------------------------------------------------------ */
89 
90 /* _CompFunction struct definition (from compiz-core/src/fragment.c)
91  * I just keep the beginning of the struct, since I just want the name
92  * and importing the remainder would mean importing several other definitions.
93  * I guess this is a bit risky though.. maybe should I bring this issue on
94  * the mailing list? */
95 struct _CompFunction {
96     struct _CompFunction *next;
97 
98     int			 id;
99     char		 *name;
100 };
101 
102 /*
103  * Find fragment function by id (imported from compiz-core/src/fragment.c)
104  */
105 static CompFunction *
findFragmentFunction(CompScreen * s,int id)106 findFragmentFunction (CompScreen *s, int id)
107 {
108     CompFunction *function;
109 
110     for (function = s->fragmentFunctions; function; function = function->next)
111     {
112 	if (function->id == id)
113 	    return function;
114     }
115 
116     return NULL;
117 }
118 
119 /* Actions handling functions ----------------------------------------------- */
120 
121 /*
122  * Toggle filtering for a specific window
123  */
124 static void
colorFilterToggleWindow(CompWindow * w)125 colorFilterToggleWindow (CompWindow * w)
126 {
127     FILTER_WINDOW (w);
128 
129     /* Toggle window filtering flag */
130     cfw->isFiltered = !cfw->isFiltered;
131 
132     /* Check exclude list */
133     if (matchEval (colorfilterGetExcludeMatch (w->screen), w))
134 	cfw->isFiltered = FALSE;
135 
136     /* Ensure window is going to be repainted */
137     addWindowDamage (w);
138 }
139 
140 /*
141  * Toggle filtering for the whole screen
142  */
143 static void
colorFilterToggleScreen(CompScreen * s)144 colorFilterToggleScreen (CompScreen * s)
145 {
146     CompWindow *w;
147 
148     FILTER_SCREEN (s);
149 
150     /* Toggle screen filtering flag */
151     cfs->isFiltered = !cfs->isFiltered;
152 
153     /* Toggle filtering for every window */
154     for (w = s->windows; w; w = w->next)
155 	if (w)
156 	    colorFilterToggleWindow (w);
157 }
158 
159 /*
160  * Switch current filter
161  */
162 static void
colorFilterSwitchFilter(CompScreen * s)163 colorFilterSwitchFilter (CompScreen * s)
164 {
165     int id;
166     CompFunction *function;
167     CompWindow *w;
168     FILTER_SCREEN (s);
169 
170     /* % (count + 1) because of the cumulative filters mode */
171     cfs->currentFilter = ++cfs->currentFilter % (cfs->filtersCount + 1);
172     if (cfs->currentFilter == 0)
173 	compLogMessage ("colorfilter", CompLogLevelInfo,
174 			"Cumulative filters mode");
175     else
176     {
177 	id = cfs->filtersFunctions[cfs->currentFilter - 1];
178 	if (id)
179 	{
180 	    function = findFragmentFunction (s, id);
181 	    compLogMessage ("colorfilter", CompLogLevelInfo,
182 			    "Single filter mode (using %s filter)",
183 			    function->name);
184 	}
185 	else
186 	{
187 	    compLogMessage ("colorfilter", CompLogLevelInfo,
188 			    "Single filter mode (filter loading failure)");
189 	}
190     }
191 
192     /* Damage currently filtered windows */
193     for (w = s->windows; w; w = w->next)
194     {
195 	FILTER_WINDOW (w);
196 	if (cfw->isFiltered)
197 	    addWindowDamage (w);
198     }
199 }
200 
201 /*
202  * Window filtering toggle action
203  */
204 static Bool
colorFilterToggle(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)205 colorFilterToggle (CompDisplay * d, CompAction * action,
206 		   CompActionState state, CompOption * option, int nOption)
207 {
208     CompWindow *w;
209     Window xid;
210 
211     xid = getIntOptionNamed (option, nOption, "window", 0);
212 
213     w = findWindowAtDisplay (d, xid);
214 
215     if (w && w->screen->fragmentProgram)
216 	colorFilterToggleWindow (w);
217 
218     return TRUE;
219 }
220 
221 /*
222  * Screen filtering toggle action
223  */
224 static Bool
colorFilterToggleAll(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)225 colorFilterToggleAll (CompDisplay * d, CompAction * action,
226 		      CompActionState state, CompOption * option, int nOption)
227 {
228     CompScreen *s;
229     Window xid;
230 
231     xid = getIntOptionNamed (option, nOption, "root", 0);
232 
233     s = findScreenAtDisplay(d, xid);
234 
235     if (s && s->fragmentProgram)
236 	colorFilterToggleScreen (s);
237 
238     return TRUE;
239 }
240 
241 /*
242  * Filter switching action
243  */
244 static Bool
colorFilterSwitch(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)245 colorFilterSwitch (CompDisplay * d, CompAction * action,
246 		   CompActionState state, CompOption * option, int nOption)
247 {
248     CompScreen *s;
249     Window xid;
250 
251     xid = getIntOptionNamed (option, nOption, "root", 0);
252 
253     s = findScreenAtDisplay(d, xid);
254 
255     if (s && s->fragmentProgram)
256 	colorFilterSwitchFilter (s);
257 
258     return TRUE;
259 }
260 
261 /* Filters handling functions ----------------------------------------------- */
262 
263 /*
264  * Free filters resources if any
265  */
266 static void
unloadFilters(CompScreen * s)267 unloadFilters (CompScreen *s)
268 {
269     int i;
270 
271     FILTER_SCREEN (s);
272 
273     if (cfs->filtersFunctions)
274     {
275 	/* Destroy loaded filters one by one */
276 	for (i = 0; i < cfs->filtersCount; i++)
277 	{
278 	    if (cfs->filtersFunctions[i])
279 		destroyFragmentFunction (s, cfs->filtersFunctions[i]);
280 	}
281 	free (cfs->filtersFunctions);
282 	cfs->filtersFunctions = NULL;
283 	cfs->filtersCount = 0;
284 	/* Reset current filter */
285 	cfs->currentFilter = 0;
286     }
287 }
288 
289 /*
290  * Load filters from a list of files for current screen
291  */
292 static int
loadFilters(CompScreen * s,CompTexture * texture)293 loadFilters (CompScreen *s, CompTexture *texture)
294 {
295     int i, target, loaded, function, count;
296     char *name;
297     CompListValue *filters;
298     CompWindow *w;
299 
300     FILTER_SCREEN (s);
301 
302     cfs->filtersLoaded = TRUE;
303 
304     /* Fetch filters filenames */
305     filters = colorfilterGetFilters (s);
306     count = filters->nValue;
307 
308     /* The texture target that will be used for some ops */
309     if (texture->target == GL_TEXTURE_2D)
310 	target = COMP_FETCH_TARGET_2D;
311     else
312 	target = COMP_FETCH_TARGET_RECT;
313 
314     /* Free previously loaded filters and malloc */
315     unloadFilters (s);
316     cfs->filtersFunctions = malloc (sizeof (int) * count);
317     if (!cfs->filtersFunctions)
318 	return 0;
319     cfs->filtersCount = count;
320 
321     /* Load each filter one by one */
322     loaded = 0;
323     for (i = 0; i < count; i++)
324     {
325 	name = base_name (filters->value[i].s);
326 	if (!name || !strlen (name))
327 	{
328 	    if (name)
329 		free (name);
330 
331 	    cfs->filtersFunctions[i] = 0;
332 	    continue;
333 	}
334 
335 	compLogMessage ("colorfilter", CompLogLevelInfo,
336 			"Loading filter %s (item %s).", name,
337 			filters->value[i].s);
338 	function = loadFragmentProgram (filters->value[i].s, name, s, target);
339 	free (name);
340 	cfs->filtersFunctions[i] = function;
341 	if (function)
342 	    loaded++;
343     }
344 
345     /* Warn if there was at least one loading failure */
346     if (loaded < count)
347 	compLogMessage ("colorfilter", CompLogLevelWarn,
348 			"Tried to load %d filter(s), %d succeeded.",
349 			count, loaded);
350 
351     if (!loaded)
352 	cfs->filtersCount = 0;
353 
354     /* Damage currently filtered windows */
355     for (w = s->windows; w; w = w->next)
356     {
357 	FILTER_WINDOW (w);
358 	if (cfw->isFiltered)
359 	    addWindowDamage (w);
360     }
361 
362     return loaded;
363 }
364 
365 /*
366  * Wrapper that enables filters if the window is filtered
367  */
368 static void
colorFilterDrawWindowTexture(CompWindow * w,CompTexture * texture,const FragmentAttrib * attrib,unsigned int mask)369 colorFilterDrawWindowTexture (CompWindow *w, CompTexture *texture,
370 			      const FragmentAttrib *attrib, unsigned int mask)
371 {
372     int i, function;
373 
374     FILTER_SCREEN (w->screen);
375     FILTER_WINDOW (w);
376 
377     /* Check if filters have to be loaded and load them if so
378      * Maybe should this check be done only if a filter is going to be applied
379      * for this texture? */
380     if (!cfs->filtersLoaded)
381 	loadFilters (w->screen, texture);
382 
383     /* Filter texture if :
384      *   o GL_ARB_fragment_program available
385      *   o Filters are loaded
386      *   o Texture's window is filtered */
387     /* Note : if required, filter window contents only and not decorations
388      * (use that w->texture->name != texture->name for decorations) */
389     if (cfs->filtersCount && cfw->isFiltered &&
390 	(colorfilterGetFilterDecorations (w->screen) ||
391 	 (texture->name == w->texture->name)))
392     {
393 	FragmentAttrib fa = *attrib;
394 	if (cfs->currentFilter == 0) /* Cumulative filters mode */
395 	{
396 	    /* Enable each filter one by one */
397 	    for (i = 0; i < cfs->filtersCount; i++)
398 	    {
399 		function = cfs->filtersFunctions[i];
400 		if (function)
401 		    addFragmentFunction (&fa, function);
402 	    }
403 	}
404 	/* Single filter mode */
405 	else if (cfs->currentFilter <= cfs->filtersCount)
406 	{
407 	    /* Enable the currently selected filter if possible (i.e. if it
408 	     * was successfully loaded) */
409 	    function = cfs->filtersFunctions[cfs->currentFilter - 1];
410 	    if (function)
411 		addFragmentFunction (&fa, function);
412 	}
413 	UNWRAP (cfs, w->screen, drawWindowTexture);
414 	(*w->screen->drawWindowTexture) (w, texture, &fa, mask);
415 	WRAP(cfs, w->screen, drawWindowTexture, colorFilterDrawWindowTexture);
416     }
417     else /* Not filtering */
418     {
419 	UNWRAP (cfs, w->screen, drawWindowTexture);
420 	(*w->screen->drawWindowTexture) (w, texture, attrib, mask);
421 	WRAP(cfs, w->screen, drawWindowTexture, colorFilterDrawWindowTexture);
422     }
423 }
424 
425 /*
426  * Filter windows when they are open if they match the filtering rules
427  */
428 static void
colorFilterWindowAdd(CompScreen * s,CompWindow * w)429 colorFilterWindowAdd (CompScreen *s,
430 		      CompWindow *w)
431 {
432     FILTER_SCREEN (s);
433 
434     /* cfw->isFiltered is initialized to FALSE in InitWindow, so we only
435        have to toggle it to TRUE if necessary */
436     if (cfs->isFiltered && matchEval (colorfilterGetFilterMatch (s), w))
437 	colorFilterToggleWindow (w);
438 }
439 
440 /* Internal stuff ----------------------------------------------------------- */
441 
442 /*
443  * Filtering match settings update callback
444  */
445 static void
colorFilterMatchsChanged(CompScreen * s,CompOption * opt,ColorfilterScreenOptions num)446 colorFilterMatchsChanged (CompScreen *s, CompOption *opt,
447 			  ColorfilterScreenOptions num)
448 {
449     CompWindow *w;
450 
451     FILTER_SCREEN (s);
452 
453     /* Re-check every window against new match settings */
454     for (w = s->windows; w; w = w->next)
455     {
456 	FILTER_WINDOW (w);
457 	if (matchEval (colorfilterGetFilterMatch (s), w) &&
458 	    cfs->isFiltered && !cfw->isFiltered)
459 	{
460 	    colorFilterToggleWindow (w);
461 	}
462     }
463 }
464 
465 /*
466  * Exclude match settings update callback
467  */
468 static void
colorFilterExcludeMatchsChanged(CompScreen * s,CompOption * opt,ColorfilterScreenOptions num)469 colorFilterExcludeMatchsChanged (CompScreen *s, CompOption *opt,
470 				 ColorfilterScreenOptions num)
471 {
472     CompWindow *w;
473 
474     FILTER_SCREEN (s);
475 
476     /* Re-check every window against new match settings */
477     for (w = s->windows; w; w = w->next)
478     {
479 	Bool isExcluded;
480 
481 	FILTER_WINDOW (w);
482 
483 	isExcluded = matchEval (colorfilterGetExcludeMatch (s), w);
484 	if (isExcluded && cfw->isFiltered)
485 	    colorFilterToggleWindow (w);
486 	else if (!isExcluded && cfs->isFiltered && !cfw->isFiltered)
487 	    colorFilterToggleWindow (w);
488     }
489 }
490 
491 /*
492  * Filters list setting update callback
493  */
494 static void
colorFiltersChanged(CompScreen * s,CompOption * opt,ColorfilterScreenOptions num)495 colorFiltersChanged (CompScreen *s, CompOption *opt,
496 		     ColorfilterScreenOptions num)
497 {
498     FILTER_SCREEN (s);
499     /* Just set the filtersLoaded boolean to FALSE, unloadFilters will be
500      * called in loadFilters */
501     cfs->filtersLoaded = FALSE;
502 }
503 
504 /*
505  * Damage decorations after the "Filter Decorations" setting got changed
506  */
507 static void
colorFilterDamageDecorations(CompScreen * s,CompOption * opt,ColorfilterScreenOptions num)508 colorFilterDamageDecorations (CompScreen *s, CompOption *opt,
509 			      ColorfilterScreenOptions num)
510 {
511     damageScreen (s);
512 }
513 
514 static void
colorFilterObjectAdd(CompObject * parent,CompObject * object)515 colorFilterObjectAdd (CompObject *parent,
516 		      CompObject *object)
517 {
518     static ObjectAddProc dispTab[] = {
519 	(ObjectAddProc) 0, /* CoreAdd */
520         (ObjectAddProc) 0, /* DisplayAdd */
521         (ObjectAddProc) 0, /* ScreenAdd */
522         (ObjectAddProc) colorFilterWindowAdd
523     };
524 
525     FILTER_CORE (&core);
526 
527     UNWRAP (fc, &core, objectAdd);
528     (*core.objectAdd) (parent, object);
529     WRAP (fc, &core, objectAdd, colorFilterObjectAdd);
530 
531     DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), (parent, object));
532 }
533 
534 static Bool
colorFilterInitCore(CompPlugin * p,CompCore * c)535 colorFilterInitCore (CompPlugin *p,
536 		     CompCore   *c)
537 {
538     ColorFilterCore *fc;
539 
540     if (!checkPluginABI ("core", CORE_ABIVERSION))
541         return FALSE;
542 
543     fc = malloc (sizeof (ColorFilterCore));
544     if (!fc)
545         return FALSE;
546 
547     displayPrivateIndex = allocateDisplayPrivateIndex ();
548     if (displayPrivateIndex < 0)
549     {
550         free (fc);
551         return FALSE;
552     }
553 
554     WRAP (fc, c, objectAdd, colorFilterObjectAdd);
555 
556     c->base.privates[corePrivateIndex].ptr = fc;
557 
558     return TRUE;
559 }
560 
561 static void
colorFilterFiniCore(CompPlugin * p,CompCore * c)562 colorFilterFiniCore (CompPlugin *p,
563 		     CompCore   *c)
564 {
565     FILTER_CORE (c);
566 
567     freeDisplayPrivateIndex (displayPrivateIndex);
568 
569     UNWRAP (fc, c, objectAdd);
570 
571     free (fc);
572 }
573 
574 static Bool
colorFilterInitDisplay(CompPlugin * p,CompDisplay * d)575 colorFilterInitDisplay (CompPlugin * p, CompDisplay * d)
576 {
577     ColorFilterDisplay *cfd;
578 
579     cfd = malloc (sizeof (ColorFilterDisplay));
580     if (!cfd)
581 	return FALSE;
582 
583     cfd->screenPrivateIndex = allocateScreenPrivateIndex (d);
584     if (cfd->screenPrivateIndex < 0)
585     {
586 	free (cfd);
587 	return FALSE;
588     }
589 
590     colorfilterSetToggleWindowKeyInitiate (d, colorFilterToggle);
591     colorfilterSetToggleScreenKeyInitiate (d, colorFilterToggleAll);
592     colorfilterSetSwitchFilterKeyInitiate (d, colorFilterSwitch);
593 
594     d->base.privates[displayPrivateIndex].ptr = cfd;
595 
596     return TRUE;
597 }
598 
599 static void
colorFilterFiniDisplay(CompPlugin * p,CompDisplay * d)600 colorFilterFiniDisplay (CompPlugin * p, CompDisplay * d)
601 {
602     FILTER_DISPLAY (d);
603     freeScreenPrivateIndex (d, cfd->screenPrivateIndex);
604     free (cfd);
605 }
606 
607 static Bool
colorFilterInitScreen(CompPlugin * p,CompScreen * s)608 colorFilterInitScreen (CompPlugin * p, CompScreen * s)
609 {
610     ColorFilterScreen *cfs;
611 
612     FILTER_DISPLAY (s->display);
613 
614     if (!s->fragmentProgram)
615     {
616 	compLogMessage ("colorfilter", CompLogLevelFatal,
617 			"Fragment program support missing.");
618 	return TRUE;
619     }
620 
621     cfs = malloc (sizeof (ColorFilterScreen));
622     if (!cfs)
623 	return FALSE;
624 
625     cfs->windowPrivateIndex = allocateWindowPrivateIndex (s);
626     if (cfs->windowPrivateIndex < 0)
627     {
628 	free (cfs);
629 	return FALSE;
630     }
631 
632     cfs->isFiltered = FALSE;
633     cfs->currentFilter = 0;
634 
635     cfs->filtersLoaded = FALSE;
636     cfs->filtersFunctions = NULL;
637     cfs->filtersCount = 0;
638 
639     colorfilterSetFilterMatchNotify (s, colorFilterMatchsChanged);
640     colorfilterSetExcludeMatchNotify (s, colorFilterExcludeMatchsChanged);
641     colorfilterSetFiltersNotify (s, colorFiltersChanged);
642     colorfilterSetFilterDecorationsNotify (s, colorFilterDamageDecorations);
643 
644     WRAP (cfs, s, drawWindowTexture, colorFilterDrawWindowTexture);
645 
646     s->base.privates[cfd->screenPrivateIndex].ptr = cfs;
647 
648     return TRUE;
649 }
650 
651 static void
colorFilterFiniScreen(CompPlugin * p,CompScreen * s)652 colorFilterFiniScreen (CompPlugin * p, CompScreen * s)
653 {
654     FILTER_SCREEN (s);
655 
656     freeWindowPrivateIndex (s, cfs->windowPrivateIndex);
657     UNWRAP (cfs, s, drawWindowTexture);
658 
659     unloadFilters (s);
660 
661     free (cfs);
662 }
663 
664 static Bool
colorFilterInitWindow(CompPlugin * p,CompWindow * w)665 colorFilterInitWindow (CompPlugin * p, CompWindow * w)
666 {
667     ColorFilterWindow *cfw;
668 
669     if (!w->screen->fragmentProgram)
670 	return TRUE;
671 
672     FILTER_SCREEN (w->screen);
673 
674     cfw = malloc (sizeof (ColorFilterWindow));
675     if (!cfw)
676 	return FALSE;
677 
678     cfw->isFiltered = FALSE;
679 
680     w->base.privates[cfs->windowPrivateIndex].ptr = cfw;
681 
682     return TRUE;
683 }
684 
685 static void
colorFilterFiniWindow(CompPlugin * p,CompWindow * w)686 colorFilterFiniWindow (CompPlugin * p, CompWindow * w)
687 {
688     if (!w->screen->fragmentProgram)
689 	return;
690 
691     FILTER_WINDOW (w);
692     free (cfw);
693 }
694 
695 static CompBool
colorFilterInitObject(CompPlugin * p,CompObject * o)696 colorFilterInitObject (CompPlugin *p,
697 		       CompObject *o)
698 {
699     static InitPluginObjectProc dispTab[] = {
700 	(InitPluginObjectProc) colorFilterInitCore,
701 	(InitPluginObjectProc) colorFilterInitDisplay,
702 	(InitPluginObjectProc) colorFilterInitScreen,
703 	(InitPluginObjectProc) colorFilterInitWindow
704     };
705 
706     RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
707 }
708 
709 static void
colorFilterFiniObject(CompPlugin * p,CompObject * o)710 colorFilterFiniObject (CompPlugin *p,
711 		       CompObject *o)
712 {
713     static FiniPluginObjectProc dispTab[] = {
714 	(FiniPluginObjectProc) colorFilterFiniCore,
715 	(FiniPluginObjectProc) colorFilterFiniDisplay,
716 	(FiniPluginObjectProc) colorFilterFiniScreen,
717 	(FiniPluginObjectProc) colorFilterFiniWindow
718     };
719 
720     DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
721 }
722 
723 static Bool
colorFilterInit(CompPlugin * p)724 colorFilterInit (CompPlugin * p)
725 {
726     corePrivateIndex = allocateCorePrivateIndex ();
727     if (corePrivateIndex < 0)
728 	return FALSE;
729 
730     return TRUE;
731 }
732 
733 static void
colorFilterFini(CompPlugin * p)734 colorFilterFini (CompPlugin * p)
735 {
736     freeCorePrivateIndex (corePrivateIndex);
737 }
738 
739 CompPluginVTable colorFilterVTable = {
740     "colorfilter",
741     0,
742     colorFilterInit,
743     colorFilterFini,
744     colorFilterInitObject,
745     colorFilterFiniObject,
746     NULL,
747     NULL
748 };
749 
getCompPluginInfo(void)750 CompPluginVTable *getCompPluginInfo (void)
751 {
752     return &colorFilterVTable;
753 }
754