1 /*
2 * Compiz splash plugin
3 *
4 * splash.c
5 *
6 * Copyright : (C) 2006 by Dennis Kasprzyk
7 * E-mail : onestone@beryl-project.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 <math.h>
23
24 #include <compiz-core.h>
25 #include <X11/Xatom.h>
26
27 #include "splash_options.h"
28
29 #define SPLASH_BACKGROUND_DEFAULT ""
30 #define SPLASH_LOGO_DEFAULT ""
31
32 #define GET_SPLASH_DISPLAY(d) \
33 ((SplashDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
34
35 #define SPLASH_DISPLAY(d) \
36 SplashDisplay *sd = GET_SPLASH_DISPLAY (d)
37
38 #define GET_SPLASH_SCREEN(s, sd) \
39 ((SplashScreen *) (s)->base.privates[(sd)->screenPrivateIndex].ptr)
40
41 #define SPLASH_SCREEN(s) \
42 SplashScreen *ss = GET_SPLASH_SCREEN (s, GET_SPLASH_DISPLAY (s->display))
43
44
45 static int displayPrivateIndex = 0;
46
47 typedef struct _SplashDisplay
48 {
49 Atom splashAtom;
50 int screenPrivateIndex;
51 }
52 SplashDisplay;
53
54 #define MESH_W 16
55 #define MESH_H 16
56
57 typedef struct _SplashScreen
58 {
59 PreparePaintScreenProc preparePaintScreen;
60 DonePaintScreenProc donePaintScreen;
61 PaintOutputProc paintOutput;
62 PaintWindowProc paintWindow;
63
64 int fade_in;
65 int fade_out;
66 int time;
67
68 CompTexture back_img, logo_img;
69 unsigned int backSize[2], logoSize[2];
70 Bool hasInit, hasLogo, hasBack;
71
72 float mesh[MESH_W][MESH_H][2];
73 float mMove;
74
75 float brightness;
76 float saturation;
77
78 Bool initiate;
79 Bool active;
80
81 }
82 SplashScreen;
83
84
85 static void
splashPreparePaintScreen(CompScreen * s,int ms)86 splashPreparePaintScreen (CompScreen *s,
87 int ms)
88 {
89 SPLASH_SCREEN (s);
90 CompDisplay *d = s->display;
91
92 Bool lastShot = FALSE;
93
94 ss->fade_in -= ms;
95
96 if (ss->fade_in < 0)
97 {
98 ss->time += ss->fade_in;
99 ss->fade_in = 0;
100
101 if (ss->time < 0)
102 {
103 if (ss->fade_out > 0 && ss->fade_out <= ms)
104 lastShot = TRUE;
105
106 ss->fade_out += ss->time;
107
108 ss->time = 0;
109
110 if (ss->fade_out < 0)
111 ss->fade_out = 0;
112 }
113 }
114
115 if (ss->initiate)
116 {
117 ss->fade_in = ss->fade_out = splashGetFadeTime (d) * 1000.0;
118 ss->time = splashGetDisplayTime (d) * 1000.0;
119 ss->initiate = FALSE;
120 }
121
122 if (ss->fade_in || ss->fade_out || ss->time || lastShot)
123 {
124 ss->active = TRUE;
125 ss->mMove += ms / 500.0;
126
127 if (!ss->hasInit)
128 {
129 ss->hasInit = TRUE;
130 ss->mMove = 0.0;
131
132 ss->hasBack =
133 readImageToTexture (s, &ss->back_img, splashGetBackground (d),
134 &ss->backSize[0], &ss->backSize[1]);
135 ss->hasLogo =
136 readImageToTexture (s, &ss->logo_img, splashGetLogo (d),
137 &ss->logoSize[0], &ss->logoSize[1]);
138
139 if (!ss->hasBack)
140 {
141 ss->hasBack =
142 readImageToTexture (s, &ss->back_img,
143 SPLASH_BACKGROUND_DEFAULT,
144 &ss->backSize[0], &ss->backSize[1]);
145
146 if (ss->hasBack)
147 {
148 compLogMessage ("splash", CompLogLevelWarn,
149 "Could not load splash background image "
150 "\"%s\" using default!",
151 splashGetBackground (d) );
152 }
153 }
154
155 if (!ss->hasLogo)
156 {
157 ss->hasLogo =
158 readImageToTexture (s, &ss->logo_img,
159 SPLASH_LOGO_DEFAULT,
160 &ss->logoSize[0], &ss->logoSize[1]);
161
162 if (ss->hasLogo)
163 {
164 compLogMessage ("splash", CompLogLevelWarn,
165 "Could not load splash logo image "
166 "\"%s\" using default!",
167 splashGetLogo (d) );
168 }
169 }
170
171 if (!ss->hasBack)
172 compLogMessage ("splash", CompLogLevelWarn,
173 "Could not load splash background image "
174 "\"%s\" !", splashGetBackground (d) );
175
176 if (!ss->hasLogo)
177 compLogMessage ("splash", CompLogLevelWarn,
178 "Could not load splash logo image \"%s\" !",
179 splashGetLogo (d) );
180 }
181 }
182 else
183 {
184 ss->active = FALSE;
185
186 if (ss->hasInit)
187 {
188 ss->hasInit = FALSE;
189
190 if (ss->hasBack)
191 {
192 finiTexture (s, &ss->back_img);
193 initTexture (s, &ss->back_img);
194 ss->hasBack = FALSE;
195 }
196
197 if (ss->hasLogo)
198 {
199 finiTexture (s, &ss->logo_img);
200 initTexture (s, &ss->logo_img);
201 ss->hasLogo = FALSE;
202 }
203 }
204 }
205
206 UNWRAP (ss, s, preparePaintScreen);
207 (*s->preparePaintScreen) (s, ms);
208 WRAP (ss, s, preparePaintScreen, splashPreparePaintScreen);
209
210 }
211
212 static void
splashDonePaintScreen(CompScreen * s)213 splashDonePaintScreen (CompScreen * s)
214 {
215 SPLASH_SCREEN (s);
216
217 if (ss->fade_in || ss->fade_out || ss->time)
218 damageScreen (s);
219
220 UNWRAP (ss, s, donePaintScreen);
221 (*s->donePaintScreen) (s);
222 WRAP (ss, s, donePaintScreen, splashDonePaintScreen);
223 }
224
225 static void
splashGetCurrentOutputRect(CompScreen * s,XRectangle * outputRect)226 splashGetCurrentOutputRect (CompScreen *s,
227 XRectangle *outputRect)
228 {
229 int root_x = 0, root_y = 0;
230 int ignore_i;
231 unsigned int ignore_ui;
232 int output;
233 Window ignore_w;
234
235
236 if (s->nOutputDev == 1)
237 output = 0;
238 else
239 {
240 XQueryPointer (s->display->display, s->root, &ignore_w, &ignore_w,
241 &root_x, &root_y, &ignore_i, &ignore_i, &ignore_ui);
242 output = outputDeviceForPoint (s, root_x, root_y);
243 }
244
245 outputRect->x = s->outputDev[output].region.extents.x1;
246 outputRect->y = s->outputDev[output].region.extents.y1;
247 outputRect->width = s->outputDev[output].region.extents.x2 -
248 s->outputDev[output].region.extents.x1;
249 outputRect->height = s->outputDev[output].region.extents.y2 -
250 s->outputDev[output].region.extents.y1;
251
252 }
253
254 static Bool
splashPaintOutput(CompScreen * s,const ScreenPaintAttrib * sa,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)255 splashPaintOutput (CompScreen *s,
256 const ScreenPaintAttrib *sa,
257 const CompTransform *transform,
258 Region region,
259 CompOutput *output,
260 unsigned int mask)
261 {
262
263 SPLASH_SCREEN (s);
264 CompDisplay *d = s->display;
265 CompTransform sTransform = *transform;
266
267 Bool status = TRUE;
268
269 float alpha = 0.0;
270
271 if (ss->active)
272 {
273 alpha = (1.0 - (ss->fade_in / (splashGetFadeTime (d) * 1000.0) ) ) *
274 (ss->fade_out / (splashGetFadeTime (d) * 1000.0) );
275 ss->saturation = 1.0 -
276 ((1.0 - (splashGetSaturation (d) / 100.0) ) * alpha);
277 ss->brightness = 1.0 -
278 ((1.0 - (splashGetBrightness (d) / 100.0) ) * alpha);
279 }
280
281 UNWRAP (ss, s, paintOutput);
282 status = (*s->paintOutput) (s, sa, transform, region, output, mask);
283 WRAP (ss, s, paintOutput, splashPaintOutput);
284
285 if (!ss->active)
286 return status;
287
288
289 transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
290
291 glPushMatrix ();
292 glLoadMatrixf (sTransform.m);
293 glEnable (GL_BLEND);
294 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
295 glColor4f (1.0, 1.0, 1.0, alpha);
296 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
297
298 if (ss->hasBack)
299 {
300 int x, y;
301
302 for (x = 0; x < MESH_W; x++)
303 {
304 for (y = 0; y < MESH_H; y++)
305 {
306 ss->mesh[x][y][0] =
307 (x / (MESH_W - 1.0) ) +
308 (0.02 * sin ( (y / (MESH_H - 1.0) * 8) + ss->mMove) );
309 ss->mesh[x][y][1] =
310 (y / (MESH_H - 1.0) ) +
311 (0.02 * sin ( (ss->mesh[x][y][0] * 8) + ss->mMove) );
312 ;
313 }
314 }
315
316 enableTexture (s, &ss->back_img, COMP_TEXTURE_FILTER_GOOD);
317
318 if (s->nOutputDev > 1)
319 {
320 XRectangle headOutputRect;
321
322 splashGetCurrentOutputRect (s, &headOutputRect);
323
324 x = (headOutputRect.width - ss->backSize[0]) / 2;
325 y = (headOutputRect.height - ss->backSize[1]) / 2;
326
327 x += headOutputRect.x;
328 y += headOutputRect.y;
329 }
330 else
331 {
332 x = (s->width - ss->backSize[0]) / 2;
333 y = (s->height - ss->backSize[1]) / 2;
334 }
335
336 CompMatrix mat = ss->back_img.matrix;
337
338 glTranslatef (x, y, 0);
339
340 float cx1, cx2, cy1, cy2;
341
342 glBegin (GL_QUADS);
343
344 for (x = 0; x < MESH_W - 1; x++)
345 {
346 for (y = 0; y < MESH_H - 1; y++)
347 {
348 cx1 = (x / (MESH_W - 1.0) ) * ss->backSize[0];
349 cx2 = ( (x + 1) / (MESH_W - 1.0) ) * ss->backSize[0];
350 cy1 = (y / (MESH_H - 1.0) ) * ss->backSize[1];
351 cy2 = ( (y + 1) / (MESH_H - 1.0) ) * ss->backSize[1];
352
353 glTexCoord2f (COMP_TEX_COORD_X (&mat, cx1),
354 COMP_TEX_COORD_Y (&mat, cy1) );
355 glVertex2f (ss->mesh[x][y][0] *
356 ss->backSize[0],
357 ss->mesh[x][y][1] * ss->backSize[1]);
358 glTexCoord2f (COMP_TEX_COORD_X (&mat, cx1),
359 COMP_TEX_COORD_Y (&mat, cy2) );
360 glVertex2f (ss->mesh[x][y + 1][0] *
361 ss->backSize[0],
362 ss->mesh[x][y + 1][1] * ss->backSize[1]);
363 glTexCoord2f (COMP_TEX_COORD_X (&mat, cx2),
364 COMP_TEX_COORD_Y (&mat, cy2) );
365 glVertex2f (ss->mesh[x + 1][y + 1][0] *
366 ss->backSize[0],
367 ss->mesh[x + 1][y + 1][1] * ss->backSize[1]);
368 glTexCoord2f (COMP_TEX_COORD_X (&mat, cx2),
369 COMP_TEX_COORD_Y (&mat, cy1) );
370 glVertex2f (ss->mesh[x + 1][y][0] *
371 ss->backSize[0],
372 ss->mesh[x + 1][y][1] * ss->backSize[1]);
373 }
374 }
375
376 glEnd ();
377
378 if (s->nOutputDev > 1)
379 {
380 XRectangle headOutputRect;
381
382 splashGetCurrentOutputRect (s, &headOutputRect);
383
384 x = (headOutputRect.width - ss->backSize[0]) / 2;
385 y = (headOutputRect.height - ss->backSize[1]) / 2;
386
387 x += headOutputRect.x;
388 y += headOutputRect.y;
389 }
390 else
391 {
392 x = (s->width - ss->backSize[0]) / 2;
393 y = (s->height - ss->backSize[1]) / 2;
394 }
395
396 glTranslatef (-x, -y, 0);
397
398 disableTexture (s, &ss->back_img);
399 }
400
401 if (ss->hasLogo)
402 {
403 enableTexture (s, &ss->logo_img, COMP_TEXTURE_FILTER_GOOD);
404 int x, y;
405
406 if (s->nOutputDev > 1)
407 {
408 XRectangle headOutputRect;
409
410 splashGetCurrentOutputRect (s, &headOutputRect);
411 x = (headOutputRect.width - ss->logoSize[0]) / 2;
412 y = (headOutputRect.height - ss->logoSize[1]) / 2;
413
414 x += headOutputRect.x;
415 y += headOutputRect.y;
416 }
417 else
418 {
419 x = (s->width - ss->logoSize[0]) / 2;
420 y = (s->height - ss->logoSize[1]) / 2;
421 }
422
423 CompMatrix mat = ss->logo_img.matrix;
424
425 glTranslatef (x, y, 0);
426
427 glBegin (GL_QUADS);
428 glTexCoord2f (COMP_TEX_COORD_X (&mat, 0), COMP_TEX_COORD_Y (&mat, 0) );
429 glVertex2f (0, 0);
430 glTexCoord2f (COMP_TEX_COORD_X (&mat, 0),
431 COMP_TEX_COORD_Y (&mat, ss->logoSize[1]) );
432 glVertex2f (0, ss->logoSize[1]);
433 glTexCoord2f (COMP_TEX_COORD_X (&mat, ss->logoSize[0]),
434 COMP_TEX_COORD_Y (&mat, ss->logoSize[1]) );
435 glVertex2f (ss->logoSize[0], ss->logoSize[1]);
436 glTexCoord2f (COMP_TEX_COORD_X (&mat, ss->logoSize[0]),
437 COMP_TEX_COORD_Y (&mat, 0) );
438 glVertex2f (ss->logoSize[0], 0);
439 glEnd ();
440
441 glTranslatef (-x, -y, 0);
442
443 disableTexture (s, &ss->logo_img);
444 }
445
446 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
447
448 glDisable (GL_BLEND);
449 glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
450 glColor4usv (defaultColor);
451 glPopMatrix ();
452 return status;
453 }
454
455 static Bool
splashPaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)456 splashPaintWindow (CompWindow *w,
457 const WindowPaintAttrib *attrib,
458 const CompTransform *transform,
459 Region region,
460 unsigned int mask)
461 {
462 CompScreen *s = w->screen;
463 Bool status;
464
465 SPLASH_SCREEN (s);
466
467 if (ss->active)
468 {
469 WindowPaintAttrib pA = *attrib;
470 pA.brightness = attrib->brightness * ss->brightness;
471 pA.saturation = attrib->saturation * ss->saturation;
472
473 UNWRAP (ss, s, paintWindow);
474 status = (*s->paintWindow) (w, &pA, transform, region, mask);
475 WRAP (ss, s, paintWindow, splashPaintWindow);
476 }
477 else
478 {
479 UNWRAP (ss, s, paintWindow);
480 status = (*s->paintWindow) (w, attrib, transform, region, mask);
481 WRAP (ss, s, paintWindow, splashPaintWindow);
482 }
483
484 return status;
485 }
486
487 static Bool
splashInitScreen(CompPlugin * p,CompScreen * s)488 splashInitScreen (CompPlugin *p,
489 CompScreen *s)
490 {
491
492 SPLASH_DISPLAY (s->display);
493
494 SplashScreen *ss = (SplashScreen *) calloc (1, sizeof (SplashScreen) );
495
496 s->base.privates[sd->screenPrivateIndex].ptr = ss;
497
498 WRAP (ss, s, paintOutput, splashPaintOutput);
499 WRAP (ss, s, preparePaintScreen, splashPreparePaintScreen);
500 WRAP (ss, s, donePaintScreen, splashDonePaintScreen);
501 WRAP (ss, s, paintWindow, splashPaintWindow);
502
503 initTexture (s, &ss->back_img);
504 initTexture (s, &ss->logo_img);
505
506 ss->initiate = FALSE;
507
508 if (splashGetFirststart (s->display) )
509 {
510 Atom actual;
511 int result, format;
512 unsigned long n, left;
513 unsigned char *propData;
514
515 result = XGetWindowProperty (s->display->display, s->root,
516 sd->splashAtom, 0L, 8192L, FALSE,
517 XA_INTEGER, &actual, &format,
518 &n, &left, &propData);
519
520 if (result == Success && n && propData)
521 {
522 XFree (propData);
523 }
524 else
525 {
526 int value = 1;
527 XChangeProperty (s->display->display, s->root, sd->splashAtom,
528 XA_INTEGER, 32, PropModeReplace,
529 (unsigned char *) &value, 1);
530 ss->initiate = TRUE;
531 }
532 }
533
534 return TRUE;
535 }
536
537
538 static void
splashFiniScreen(CompPlugin * p,CompScreen * s)539 splashFiniScreen (CompPlugin *p,
540 CompScreen *s)
541 {
542
543 SPLASH_SCREEN (s);
544
545 //Restore the original function
546 UNWRAP (ss, s, paintOutput);
547 UNWRAP (ss, s, preparePaintScreen);
548 UNWRAP (ss, s, donePaintScreen);
549 UNWRAP (ss, s, paintWindow);
550
551 finiTexture (s, &ss->back_img);
552 finiTexture (s, &ss->logo_img);
553
554 //Free the pointer
555 free (ss);
556 }
557
558
559
560 static Bool
splashInitiate(CompDisplay * d,CompAction * ac,CompActionState state,CompOption * option,int nOption)561 splashInitiate (CompDisplay *d,
562 CompAction *ac,
563 CompActionState state,
564 CompOption *option,
565 int nOption)
566 {
567 CompScreen *s;
568
569 s = findScreenAtDisplay (d, getIntOptionNamed (option, nOption, "root", 0));
570
571 if (s)
572 {
573 SPLASH_SCREEN (s);
574 ss->initiate = TRUE;
575 damageScreen (s);
576 }
577
578 return FALSE;
579 }
580
581
582 static Bool
splashInitDisplay(CompPlugin * p,CompDisplay * d)583 splashInitDisplay (CompPlugin *p,
584 CompDisplay *d)
585 {
586 SplashDisplay *sd;
587
588 if (!checkPluginABI ("core", CORE_ABIVERSION))
589 return FALSE;
590
591 /* Generate a splash display */
592 sd = (SplashDisplay *) malloc (sizeof (SplashDisplay) );
593
594 if (!sd)
595 return FALSE;
596
597 /* Allocate a private index */
598 sd->screenPrivateIndex = allocateScreenPrivateIndex (d);
599
600 /* Check if its valid */
601 if (sd->screenPrivateIndex < 0)
602 {
603 /* It's invalid so free memory and return */
604 free (sd);
605 return FALSE;
606 }
607
608 sd->splashAtom = XInternAtom (d->display, "_COMPIZ_WM_SPLASH", 0);
609
610 splashSetInitiateKeyInitiate (d, splashInitiate);
611
612 d->base.privates[displayPrivateIndex].ptr = sd;
613 return TRUE;
614 }
615
616 static void
splashFiniDisplay(CompPlugin * p,CompDisplay * d)617 splashFiniDisplay (CompPlugin *p,
618 CompDisplay *d)
619 {
620 SPLASH_DISPLAY (d);
621
622 /* Free the private index */
623 freeScreenPrivateIndex (d, sd->screenPrivateIndex);
624
625 /* Free the pointer */
626 free (sd);
627 }
628
629 static Bool
splashInit(CompPlugin * p)630 splashInit (CompPlugin *p)
631 {
632 displayPrivateIndex = allocateDisplayPrivateIndex ();
633
634 if (displayPrivateIndex < 0)
635 return FALSE;
636
637 return TRUE;
638 }
639
640 static void
splashFini(CompPlugin * p)641 splashFini (CompPlugin *p)
642 {
643 if (displayPrivateIndex >= 0)
644 freeDisplayPrivateIndex (displayPrivateIndex);
645 }
646
647 static CompBool
splashInitObject(CompPlugin * p,CompObject * o)648 splashInitObject (CompPlugin *p,
649 CompObject *o)
650 {
651 static InitPluginObjectProc dispTab[] = {
652 (InitPluginObjectProc) 0, /* InitCore */
653 (InitPluginObjectProc) splashInitDisplay,
654 (InitPluginObjectProc) splashInitScreen
655 };
656
657 RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
658 }
659
660 static void
splashFiniObject(CompPlugin * p,CompObject * o)661 splashFiniObject (CompPlugin *p,
662 CompObject *o)
663 {
664 static FiniPluginObjectProc dispTab[] = {
665 (FiniPluginObjectProc) 0, /* FiniCore */
666 (FiniPluginObjectProc) splashFiniDisplay,
667 (FiniPluginObjectProc) splashFiniScreen
668 };
669
670 DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
671 }
672
673 CompPluginVTable splashVTable = {
674 "splash",
675 0,
676 splashInit,
677 splashFini,
678 splashInitObject,
679 splashFiniObject,
680 0,
681 0
682 };
683
684 CompPluginVTable *
getCompPluginInfo(void)685 getCompPluginInfo (void)
686 {
687 return &splashVTable;
688 }
689