1 /*
2  * Compiz login/logout effect plugin
3  *
4  * loginout.c
5  *
6  * Copyright : (C) 2008 by Dennis Kasprzyk
7  * E-mail    : onestone@opencompositing.org
8  *
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  */
21 
22 #include <compiz-core.h>
23 
24 #include "loginout_options.h"
25 
26 static int displayPrivateIndex = 0;
27 
28 typedef struct _LoginoutDisplay
29 {
30     MatchExpHandlerChangedProc matchExpHandlerChanged;
31     MatchPropertyChangedProc   matchPropertyChanged;
32 
33     int screenPrivateIndex;
34 
35     Atom kdeLogoutInfoAtom;
36 }
37 LoginoutDisplay;
38 
39 typedef struct _LoginoutScreen
40 {
41     int windowPrivateIndex;
42 
43     PreparePaintScreenProc preparePaintScreen;
44     DonePaintScreenProc    donePaintScreen;
45     PaintWindowProc        paintWindow;
46     DrawWindowProc         drawWindow;
47 
48     int numLoginWin;
49     int numLogoutWin;
50 
51     float brightness;
52     float saturation;
53     float opacity;
54 
55     float in;
56     float out;
57 }
58 LoginoutScreen;
59 
60 typedef struct _LoginoutWindow {
61     Bool login;
62     Bool logout;
63 } LoginoutWindow;
64 
65 #define GET_LOGINOUT_DISPLAY(d)                                  \
66     ((LoginoutDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
67 
68 #define LOGINOUT_DISPLAY(d)                                      \
69     LoginoutDisplay *ld = GET_LOGINOUT_DISPLAY (d)
70 
71 #define GET_LOGINOUT_SCREEN(s, ld)                               \
72     ((LoginoutScreen *) (s)->base.privates[(ld)->screenPrivateIndex].ptr)
73 
74 #define LOGINOUT_SCREEN(s)                                       \
75     LoginoutScreen *ls = GET_LOGINOUT_SCREEN (s, GET_LOGINOUT_DISPLAY (s->display))
76 
77 #define GET_LOGINOUT_WINDOW(w, ls)					 \
78     ((LoginoutWindow *) (w)->base.privates[(ls)->windowPrivateIndex].ptr)
79 
80 #define LOGINOUT_WINDOW(w)					     \
81     LoginoutWindow *lw = GET_LOGINOUT_WINDOW  (w,		     \
82 			 GET_LOGINOUT_SCREEN  (w->screen,	     \
83 			 GET_LOGINOUT_DISPLAY (w->screen->display)))
84 
85 static void
loginoutUpdateWindowMatch(CompWindow * w)86 loginoutUpdateWindowMatch (CompWindow *w)
87 {
88     Bool curr;
89 
90     LOGINOUT_WINDOW (w);
91     LOGINOUT_SCREEN (w->screen);
92 
93     curr = matchEval (loginoutGetInMatch (w->screen), w);
94     if (curr != lw->login)
95     {
96 	lw->login = curr;
97 	if (curr)
98 	    ls->numLoginWin++;
99 	else
100 	    ls->numLoginWin--;
101 	damageScreen (w->screen);
102     }
103     curr = matchEval (loginoutGetOutMatch (w->screen), w);
104     if (curr != lw->logout)
105     {
106 	lw->logout = curr;
107 	if (curr)
108 	    ls->numLogoutWin++;
109 	else
110 	    ls->numLogoutWin--;
111 	damageScreen (w->screen);
112     }
113 }
114 
115 static void
loginoutScreenOptionChanged(CompScreen * s,CompOption * opt,LoginoutScreenOptions num)116 loginoutScreenOptionChanged (CompScreen          *s,
117 			     CompOption          *opt,
118 			     LoginoutScreenOptions num)
119 {
120     CompWindow *w;
121 
122     switch (num)
123     {
124     case LoginoutScreenOptionInMatch:
125     case LoginoutScreenOptionOutMatch:
126 	for (w = s->windows; w; w = w->next)
127 	    loginoutUpdateWindowMatch (w);
128 
129 	damageScreen (s);
130 	break;
131 
132     default:
133 	damageScreen (s);
134 	break;
135     }
136 }
137 
138 static void
loginoutMatchExpHandlerChanged(CompDisplay * d)139 loginoutMatchExpHandlerChanged (CompDisplay *d)
140 {
141     CompScreen *s;
142     CompWindow *w;
143 
144     LOGINOUT_DISPLAY (d);
145 
146     UNWRAP (ld, d, matchExpHandlerChanged);
147     (*d->matchExpHandlerChanged) (d);
148     WRAP (ld, d, matchExpHandlerChanged, loginoutMatchExpHandlerChanged);
149 
150     /* match options are up to date after the call to matchExpHandlerChanged */
151     for (s = d->screens; s; s = s->next)
152     {
153 	for (w = s->windows; w; w = w->next)
154 	    loginoutUpdateWindowMatch (w);
155     }
156 }
157 
158 static void
loginoutMatchPropertyChanged(CompDisplay * d,CompWindow * w)159 loginoutMatchPropertyChanged (CompDisplay *d,
160 			    CompWindow  *w)
161 {
162     LOGINOUT_DISPLAY (d);
163 
164     loginoutUpdateWindowMatch (w);
165 
166     UNWRAP (ld, d, matchPropertyChanged);
167     (*d->matchPropertyChanged) (d, w);
168     WRAP (ld, d, matchPropertyChanged, loginoutMatchPropertyChanged);
169 }
170 
171 static Bool
loginoutPaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)172 loginoutPaintWindow (CompWindow              *w,
173 		     const WindowPaintAttrib *attrib,
174 		     const CompTransform     *transform,
175 		     Region                  region,
176 		     unsigned int            mask)
177 {
178     CompScreen *s = w->screen;
179     Bool status;
180 
181     LOGINOUT_WINDOW (w);
182     LOGINOUT_SCREEN (s);
183 
184     if ((ls->in > 0.0 || ls->out > 0.0) && !lw->login && !lw->logout &&
185 	!(w->wmType & CompWindowTypeDesktopMask) && ls->opacity < 1.0)
186 	mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
187 
188     UNWRAP (ls, s, paintWindow);
189     status = (*s->paintWindow) (w, attrib, transform, region, mask);
190     WRAP (ls, s, paintWindow, loginoutPaintWindow);
191 
192     return status;
193 }
194 
195 static Bool
loginoutDrawWindow(CompWindow * w,const CompTransform * transform,const FragmentAttrib * fragment,Region region,unsigned int mask)196 loginoutDrawWindow (CompWindow           *w,
197 		    const CompTransform  *transform,
198 		    const FragmentAttrib *fragment,
199 		    Region	         region,
200 		    unsigned int	 mask)
201 {
202     Bool       status;
203     CompScreen *s = w->screen;
204 
205     LOGINOUT_WINDOW (w);
206     LOGINOUT_SCREEN (s);
207 
208     if ((ls->in > 0.0 || ls->out > 0.0) && !lw->login && !lw->logout)
209     {
210 	FragmentAttrib fA = *fragment;
211 
212 	if (!(w->wmType & CompWindowTypeDesktopMask))
213 	    fA.opacity = fragment->opacity * ls->opacity;
214 
215 	fA.brightness = fragment->brightness * ls->brightness;
216 	fA.saturation = fragment->saturation * ls->saturation;
217 
218 	UNWRAP (ls, s, drawWindow);
219 	status = (*s->drawWindow) (w, transform, &fA, region, mask);
220 	WRAP (ls, s, drawWindow, loginoutDrawWindow);
221     }
222     else
223     {
224 	UNWRAP (ls, s, drawWindow);
225 	status = (*s->drawWindow) (w, transform, fragment, region, mask);
226 	WRAP (ls, s, drawWindow, loginoutDrawWindow);
227     }
228     return status;
229 }
230 
231 static void
loginoutPreparePaintScreen(CompScreen * s,int ms)232 loginoutPreparePaintScreen (CompScreen *s,
233 			    int        ms)
234 {
235     LOGINOUT_SCREEN (s);
236 
237     float val, val2;
238 
239     val = ((float)ms / 1000.0) / loginoutGetInTime (s);
240 
241     if (ls->numLoginWin)
242 	ls->in = MIN (1.0, ls->in + val);
243     else
244 	ls->in = MAX (0.0, ls->in - val);
245 
246     val = ((float)ms / 1000.0) / loginoutGetOutTime (s);
247 
248     if (ls->numLogoutWin)
249 	ls->out = MIN (1.0, ls->out + val);
250     else
251 	ls->out = MAX (0.0, ls->out - val);
252 
253     if (ls->in > 0.0 || ls->out > 0.0)
254     {
255 	val  = (ls->in * loginoutGetInOpacity (s) / 100.0) + (1.0 - ls->in);
256 	val2 = (ls->out * loginoutGetOutOpacity (s) / 100.0) + (1.0 - ls->out);
257 	ls->opacity = MIN (val, val2);
258 
259 	val  = (ls->in * loginoutGetInSaturation (s) / 100.0) + (1.0 - ls->in);
260 	val2 = (ls->out * loginoutGetOutSaturation (s) / 100.0) +
261 	       (1.0 - ls->out);
262 	ls->saturation = MIN (val, val2);
263 
264 	val  = (ls->in * loginoutGetInBrightness (s) / 100.0) +
265 	       (1.0 - ls->in);
266 	val2 = (ls->out * loginoutGetOutBrightness (s) / 100.0) +
267 	       (1.0 - ls->out);
268 	ls->brightness = MIN (val, val2);
269     }
270 
271     UNWRAP (ls, s, preparePaintScreen);
272     (*s->preparePaintScreen) (s, ms);
273     WRAP (ls, s, preparePaintScreen, loginoutPreparePaintScreen);
274 }
275 
276 static void
loginoutDonePaintScreen(CompScreen * s)277 loginoutDonePaintScreen (CompScreen * s)
278 {
279     LOGINOUT_SCREEN (s);
280 
281     if ((ls->in > 0.0 && ls->in < 1.0) || (ls->out > 0.0 && ls->out < 1.0))
282 	damageScreen (s);
283 
284     UNWRAP (ls, s, donePaintScreen);
285     (*s->donePaintScreen) (s);
286     WRAP (ls, s, donePaintScreen, loginoutDonePaintScreen);
287 }
288 
289 static Bool
loginoutInitDisplay(CompPlugin * p,CompDisplay * d)290 loginoutInitDisplay (CompPlugin  *p,
291 		     CompDisplay *d)
292 {
293     LoginoutDisplay *ld;
294 
295     if (!checkPluginABI ("core", CORE_ABIVERSION))
296 	return FALSE;
297 
298     ld = malloc (sizeof (LoginoutDisplay) );
299 
300     if (!ld)
301 	return FALSE;
302 
303     ld->screenPrivateIndex = allocateScreenPrivateIndex (d);
304 
305     if (ld->screenPrivateIndex < 0)
306     {
307 	free (ld);
308 	return FALSE;
309     }
310 
311     d->base.privates[displayPrivateIndex].ptr = ld;
312 
313     ld->kdeLogoutInfoAtom = XInternAtom (d->display,
314 					 "_KWIN_LOGOUT_EFFECT", 0);
315 
316     WRAP (ld, d, matchExpHandlerChanged, loginoutMatchExpHandlerChanged);
317     WRAP (ld, d, matchPropertyChanged, loginoutMatchPropertyChanged);
318 
319     return TRUE;
320 }
321 
322 static void
loginoutFiniDisplay(CompPlugin * p,CompDisplay * d)323 loginoutFiniDisplay (CompPlugin  *p,
324 		     CompDisplay *d)
325 {
326     LOGINOUT_DISPLAY (d);
327     freeScreenPrivateIndex (d, ld->screenPrivateIndex);
328 
329     UNWRAP (ld, d, matchExpHandlerChanged);
330     UNWRAP (ld, d, matchPropertyChanged);
331 
332     free (ld);
333 }
334 
335 
336 static Bool
loginoutInitScreen(CompPlugin * p,CompScreen * s)337 loginoutInitScreen (CompPlugin *p,
338 		  CompScreen *s)
339 {
340     LoginoutScreen *ls;
341 
342     LOGINOUT_DISPLAY (s->display);
343 
344     ls = malloc (sizeof (LoginoutScreen) );
345 
346     if (!ls)
347 	return FALSE;
348 
349     ls->windowPrivateIndex = allocateWindowPrivateIndex (s);
350 
351     if (ls->windowPrivateIndex < 0)
352     {
353 	free (ls);
354 	return FALSE;
355     }
356 
357     loginoutSetInMatchNotify (s, loginoutScreenOptionChanged);
358     loginoutSetOutMatchNotify (s, loginoutScreenOptionChanged);
359 
360     s->base.privates[ld->screenPrivateIndex].ptr = ls;
361 
362     ls->numLoginWin  = 0;
363     ls->numLogoutWin = 0;
364 
365     ls->saturation = 1.0;
366     ls->brightness = 1.0;
367     ls->opacity    = 1.0;
368 
369     ls->in  = 0.0;
370     ls->out = 0.0;
371 
372     WRAP (ls, s, preparePaintScreen, loginoutPreparePaintScreen);
373     WRAP (ls, s, donePaintScreen, loginoutDonePaintScreen);
374     WRAP (ls, s, paintWindow, loginoutPaintWindow);
375     WRAP (ls, s, drawWindow, loginoutDrawWindow);
376 
377     /* This is a temporary solution until an official spec will be released */
378     XChangeProperty (s->display->display, s->wmSnSelectionWindow,
379 		     ld->kdeLogoutInfoAtom, ld->kdeLogoutInfoAtom, 8,
380 		     PropModeReplace,
381 		     (unsigned char*)&ld->kdeLogoutInfoAtom, 1);
382 
383 
384     return TRUE;
385 }
386 
387 
388 static void
loginoutFiniScreen(CompPlugin * p,CompScreen * s)389 loginoutFiniScreen (CompPlugin *p,
390 		    CompScreen *s)
391 {
392     LOGINOUT_SCREEN (s);
393     LOGINOUT_DISPLAY (s->display);
394 
395     freeWindowPrivateIndex (s, ls->windowPrivateIndex);
396 
397     UNWRAP (ls, s, preparePaintScreen);
398     UNWRAP (ls, s, donePaintScreen);
399     UNWRAP (ls, s, paintWindow);
400     UNWRAP (ls, s, drawWindow);
401 
402     XDeleteProperty (s->display->display, s->wmSnSelectionWindow,
403 		     ld->kdeLogoutInfoAtom);
404 
405     free (ls);
406 }
407 
408 static Bool
loginoutInitWindow(CompPlugin * p,CompWindow * w)409 loginoutInitWindow (CompPlugin *p,
410 		    CompWindow *w)
411 {
412     LoginoutWindow *lw;
413 
414     LOGINOUT_SCREEN (w->screen);
415 
416     lw = malloc (sizeof (LoginoutWindow));
417     if (!lw)
418 	return FALSE;
419 
420     lw->login  = FALSE;
421     lw->logout = FALSE;
422 
423     w->base.privates[ls->windowPrivateIndex].ptr = lw;
424 
425     loginoutUpdateWindowMatch (w);
426 
427     return TRUE;
428 }
429 
430 static void
loginoutFiniWindow(CompPlugin * p,CompWindow * w)431 loginoutFiniWindow (CompPlugin *p,
432 		    CompWindow *w)
433 {
434     LOGINOUT_WINDOW (w);
435     LOGINOUT_SCREEN (w->screen);
436 
437     if (lw->login)
438     {
439 	ls->numLoginWin--;
440 	damageScreen (w->screen);
441     }
442     if (lw->logout)
443     {
444 	ls->numLogoutWin--;
445 	damageScreen (w->screen);
446     }
447 
448     free (lw);
449 }
450 
451 static Bool
loginoutInit(CompPlugin * p)452 loginoutInit (CompPlugin *p)
453 {
454     displayPrivateIndex = allocateDisplayPrivateIndex ();
455 
456     if (displayPrivateIndex < 0)
457 	return FALSE;
458 
459     return TRUE;
460 }
461 
462 static void
loginoutFini(CompPlugin * p)463 loginoutFini (CompPlugin *p)
464 {
465     if (displayPrivateIndex >= 0)
466 	freeDisplayPrivateIndex (displayPrivateIndex);
467 }
468 
469 static CompBool
loginoutInitObject(CompPlugin * p,CompObject * o)470 loginoutInitObject (CompPlugin *p,
471 		    CompObject *o)
472 {
473     static InitPluginObjectProc dispTab[] = {
474 	(InitPluginObjectProc) 0, /* InitCore */
475 	(InitPluginObjectProc) loginoutInitDisplay,
476 	(InitPluginObjectProc) loginoutInitScreen,
477 	(InitPluginObjectProc) loginoutInitWindow
478     };
479 
480     RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
481 }
482 
483 static void
loginoutFiniObject(CompPlugin * p,CompObject * o)484 loginoutFiniObject (CompPlugin *p,
485 		    CompObject *o)
486 {
487     static FiniPluginObjectProc dispTab[] = {
488 	(FiniPluginObjectProc) 0, /* FiniCore */
489 	(FiniPluginObjectProc) loginoutFiniDisplay,
490 	(FiniPluginObjectProc) loginoutFiniScreen,
491 	(FiniPluginObjectProc) loginoutFiniWindow
492     };
493 
494     DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
495 }
496 
497 CompPluginVTable loginoutVTable = {
498     "loginout",
499     0,
500     loginoutInit,
501     loginoutFini,
502     loginoutInitObject,
503     loginoutFiniObject,
504     0,
505     0
506 };
507 
508 CompPluginVTable *
getCompPluginInfo(void)509 getCompPluginInfo (void)
510 {
511     return &loginoutVTable;
512 }
513