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