1 /*
  2  * Compiz splash plugin
  3  *
  4  * splash.cpp
  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 "splash.h"
 23 
 24 COMPIZ_PLUGIN_20090315 (splash, SplashPluginVTable);
 25 
 26 const std::string SPLASH_BACKGROUND_DEFAULT("");
 27 const std::string SPLASH_LOGO_DEFAULT("");
 28 
 29 void
 30 SplashScreen::preparePaint (int ms)
 31 {
 32     bool lastShot = false;
 33 
 34     fade_in -= ms;
 35 
 36     if (fade_in < 0)
 37     {
 38 	time += fade_in;
 39 	fade_in = 0;
 40 
 41 	if (time < 0)
 42 	{
 43 	    if (fade_out > 0 && fade_out <= ms)
 44 		lastShot = true;
 45 
 46 	    fade_out += time;
 47 
 48 	    time = 0;
 49 
 50 	    if (fade_out < 0)
 51 		fade_out = 0;
 52 	}
 53     }
 54 
 55     if (initiate)
 56     {
 57 	fade_in = fade_out = optionGetFadeTime () * 1000.0;
 58 	time = optionGetDisplayTime () * 1000.0;
 59 	initiate = false;
 60     }
 61 
 62     if (fade_in || fade_out || time || lastShot)
 63     {
 64 	active = true;
 65 	mMove += ms / 500.0;
 66 
 67 	if (!hasInit)
 68 	{
 69 	    hasInit = true;
 70 	    mMove = 0.0;
 71 	    CompString back_s (optionGetBackground ());
 72 	    CompString logo_s (optionGetLogo ());
 73 	    CompString pname ("splash");
 74 
 75 	    back_img =
 76 		GLTexture::readImageToTexture (back_s, pname,
 77 				    	       backSize);
 78 	    logo_img =
 79 		GLTexture::readImageToTexture (logo_s, pname,
 80 				    	       logoSize);
 81 
 82 	    if (!back_img.size ())
 83 	    {
 84 		CompString defaultBack (SPLASH_BACKGROUND_DEFAULT);
 85 		back_img =
 86 		    GLTexture::readImageToTexture (defaultBack, pname, backSize);
 87 
 88 		if (back_img.size ())
 89 		{
 90 		    compLogMessage ("splash", CompLogLevelWarn,
 91 				    "Could not load splash background image "
 92 				    "\"%s\" using default!",
 93 				    back_s.c_str () );
 94 		}
 95 	    }
 96 
 97 	    if (!logo_img.size ())
 98 	    {
 99 		CompString defaultLogo (SPLASH_LOGO_DEFAULT);
100 		logo_img =
101 		    GLTexture::readImageToTexture (defaultLogo, pname, logoSize);
102 
103 		if (logo_img.size ())
104 		{
105 		    compLogMessage ("splash", CompLogLevelWarn,
106 				    "Could not load splash logo image "
107 				    "\"%s\" using default!",
108 				    logo_s.c_str () );
109 		}
110 	    }
111 
112 	    if (!back_img.size ())
113 		compLogMessage ("splash", CompLogLevelWarn,
114 				"Could not load splash background image "
115 				"\"%s\" !", back_s.c_str () );
116 
117 	    if (!logo_img.size ())
118 		compLogMessage ("splash", CompLogLevelWarn,
119 				"Could not load splash logo image \"%s\" !",
120 				logo_s.c_str () );
121 	}
122     }
123     else
124     {
125 	active = false;
126 
127 	if (hasInit)
128 	    hasInit = false;
129 
130 	cScreen->preparePaintSetEnabled (this, false);
131 	gScreen->glPaintOutputSetEnabled (this, false);
132 	cScreen->donePaintSetEnabled (this, false);
133 
134 	foreach (CompWindow *w, screen->windows ())
135 	{
136 	    SPLASH_WINDOW (w);
137 
138 	    sw->gWindow->glPaintSetEnabled (sw, false);
139 	}
140 
141     }
142 
143     cScreen->preparePaint (ms);
144 
145 }
146 
147 void
148 SplashScreen::donePaint ()
149 {
150     if (fade_in || fade_out || time)
151 	cScreen->damageScreen ();
152 
153     cScreen->donePaint ();
154 }
155 
156 static CompRect
157 splashGetCurrentOutputRect ()
158 {
159     int root_x = 0, root_y = 0;
160     int ignore_i;
161     unsigned int ignore_ui;
162     int output;
163     Window ignore_w;
164 
165 
166     if (screen->outputDevs ().size () == 1)
167 	output = 0;
168     else
169     {
170 	XQueryPointer (screen->dpy (), screen->root (), &ignore_w, &ignore_w,
171 		       &root_x, &root_y, &ignore_i, &ignore_i, &ignore_ui);
172 	output = screen->outputDeviceForPoint (root_x, root_y);
173     }
174 
175     CompRect rect (screen->outputDevs ()[output]);
176 
177     return rect;
178 
179 }
180 
181 bool
182 SplashScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
183 		       	     const GLMatrix &transform,
184 		       	     const CompRegion &region,
185 		       	     CompOutput *output,
186 		       	     unsigned int mask)
187 {
188     GLMatrix sTransform = transform;
189 
190     bool status = true;
191 
192     float alpha = 0.0;
193 
194     if (active)
195     {
196 	alpha = (1.0 - (fade_in / (optionGetFadeTime () * 1000.0) ) ) *
197 		(fade_out / (optionGetFadeTime () * 1000.0) );
198 	saturation = 1.0 -
199 			 ((1.0 - (optionGetSaturation () / 100.0) ) * alpha);
200 	brightness = 1.0 -
201 			 ((1.0 - (optionGetBrightness () / 100.0) ) * alpha);
202     }
203 
204     status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
205 
206     if (!active)
207 	return status;
208 
209     sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
210 
211     glPushMatrix ();
212     glLoadMatrixf (sTransform.getMatrix ());
213     glEnable (GL_BLEND);
214     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
215     glColor4f (1.0, 1.0, 1.0, alpha);
216     glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
217 
218     if (back_img.size ())
219     {
220 	int x, y;
221 
222 	for (x = 0; x < MESH_W; x++)
223 	{
224 	    for (y = 0; y < MESH_H; y++)
225 	    {
226 		mesh[x][y][0] =
227 		    (x / (MESH_W - 1.0) ) +
228 		    (0.02 * sin ( (y / (MESH_H - 1.0) * 8) + mMove) );
229 		mesh[x][y][1] =
230 		    (y / (MESH_H - 1.0) ) +
231 		    (0.02 * sin ( (mesh[x][y][0] * 8) + mMove) );
232 		;
233 	    }
234 	}
235 
236 	foreach (GLTexture* tex, back_img)
237 	{
238 	    tex->enable (GLTexture::Good);
239 
CID 12419 - CONSTANT_EXPRESSION_RESULT
"!screen->outputDevs()->size() > 1" is always false regardless of the values of its operands. This occurs as the logical operand of if.
240 	    if (!screen->outputDevs ().size () > 1)
241 	    {
242 	        CompRect headOutputRect = 
243 			splashGetCurrentOutputRect ();
244 
245 		x = (headOutputRect.width () - backSize.width ()) / 2;
246 		y = (headOutputRect.height () - backSize.height ()) / 2;
247 
248 		x += headOutputRect.x ();
249 		y += headOutputRect.y ();
250 	    }
251 	    else
252 	    {
253 		x = (screen->width () - backSize.width ()) / 2;
254 		y = (screen->height () - backSize.height ()) / 2;
255 	    }
256 
257 	    GLTexture::Matrix mat = tex->matrix ();
258 
259 	    glTranslatef (x, y, 0);
260 
261 	    float cx1, cx2, cy1, cy2;
262 
263 	    glBegin (GL_QUADS);
264 
265 	    for (x = 0; x < MESH_W - 1; x++)
266 	    {
267 		for (y = 0; y < MESH_H - 1; y++)
268 		{
269 		    cx1 = (x / (MESH_W - 1.0) ) * backSize.width ();
270 		    cx2 = ( (x + 1) / (MESH_W - 1.0) ) * backSize.width ();
271 		    cy1 = (y / (MESH_H - 1.0) ) * backSize.height ();
272 		    cy2 = ( (y + 1) / (MESH_H - 1.0) ) * backSize.height ();
273 
274 		    glTexCoord2f (COMP_TEX_COORD_X (mat, cx1),
275 				  COMP_TEX_COORD_Y (mat, cy1) );
276 		    glVertex2f (mesh[x][y][0] *
277 			        backSize.width (),
278 			        mesh[x][y][1] * backSize.height ());
279 		    glTexCoord2f (COMP_TEX_COORD_X (mat, cx1),
280 				  COMP_TEX_COORD_Y (mat, cy2) );
281 		    glVertex2f (mesh[x][y + 1][0] *
282 				backSize.width (),
283 				mesh[x][y + 1][1] * backSize.height ());
284 		    glTexCoord2f (COMP_TEX_COORD_X (mat, cx2),
285 				  COMP_TEX_COORD_Y (mat, cy2) );
286 		    glVertex2f (mesh[x + 1][y + 1][0] *
287 				backSize.width (),
288 				mesh[x + 1][y + 1][1] * backSize.height ());
289 		    glTexCoord2f (COMP_TEX_COORD_X (mat, cx2),
290 				  COMP_TEX_COORD_Y (mat, cy1) );
291 		    glVertex2f (mesh[x + 1][y][0] *
292 				backSize.width (),
293 				mesh[x + 1][y][1] * backSize.height ());
294 		}
295 	    }
296 
297 	    glEnd ();
298 
299 	    if (screen->outputDevs ().size () > 1)
300 	    {
301 		CompRect headOutputRect =
302 		    splashGetCurrentOutputRect ();
303 
304 		x = (headOutputRect.width () - backSize.width ()) / 2;
305 		y = (headOutputRect.height () - backSize.height ()) / 2;
306 
307 		x += headOutputRect.x ();
308 		y += headOutputRect.y ();
309 	    }
310 	    else
311 	    {
312 		x = (screen->width () - backSize.width ()) / 2;
313 		y = (screen->height () - backSize.height ()) / 2;
314 	    }
315 
316 	    glTranslatef (-x, -y, 0);
317 
318 	    tex->disable ();
319 
320 	}
321     }
322 
323     if (logo_img.size ())
324     {
325 	foreach (GLTexture* tex, logo_img)
326 	{
327 	    tex->enable (GLTexture::Good);
328 	    int x, y;
329 
330 	    if (screen->outputDevs ().size () > 1)
331 	    {
332 		CompRect headOutputRect =
333 		    splashGetCurrentOutputRect ();
334 
335 		x = (headOutputRect.width () - logoSize.width ()) / 2;
336 		y = (headOutputRect.height () - logoSize.height ()) / 2;
337 
338 		x += headOutputRect.x ();
339 		y += headOutputRect.y ();
340 	    }
341 	    else
342 	    {
343 		x = (screen->width () - logoSize.width ()) / 2;
344 		y = (screen->height () - logoSize.height ()) / 2;
345 	    }
346 
347 	    GLTexture::Matrix mat = tex->matrix ();
348 
349 	    glTranslatef (x, y, 0);
350 
351 	    glBegin (GL_QUADS);
352 	    glTexCoord2f (COMP_TEX_COORD_X (mat, 0), COMP_TEX_COORD_Y (mat, 0) );
353 	    glVertex2f (0, 0);
354 	    glTexCoord2f (COMP_TEX_COORD_X (mat, 0),
355 			  COMP_TEX_COORD_Y (mat, logoSize.height ()) );
356 	    glVertex2f (0, logoSize.height ());
357 	    glTexCoord2f (COMP_TEX_COORD_X (mat, logoSize.width ()),
358 			  COMP_TEX_COORD_Y (mat, logoSize.height ()) );
359 	    glVertex2f (logoSize.width (), logoSize.height ());
360 	    glTexCoord2f (COMP_TEX_COORD_X (mat, logoSize.width ()),
361 			  COMP_TEX_COORD_Y (mat, 0) );
362 	    glVertex2f (logoSize.width (), 0);
363 	    glEnd ();
364 
365 	    glTranslatef (-x, -y, 0);
366 
367 	    tex->disable ();
368 	}
369     }
370 
371     glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
372 
373     glDisable (GL_BLEND);
374     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
375     glColor4usv (defaultColor);
376     glPopMatrix ();
377     return status;
378 }
379 
380 bool
381 SplashWindow::glPaint (const GLWindowPaintAttrib &attrib,
382 		       const GLMatrix &transform,
383 		       const CompRegion &region,
384 		       unsigned int mask)
385 {
386     bool status;
387 
388     SPLASH_SCREEN (screen);
389 
390     if (ss->active)
391     {
392 	GLWindowPaintAttrib pA = attrib;
393 	pA.brightness = (attrib.brightness * ss->brightness);
394 	pA.saturation = (attrib.saturation * ss->saturation);
395 
396 	status = gWindow->glPaint (pA, transform, region, mask);
397     }
398     else
399     {
400 	status = gWindow->glPaint (attrib, transform, region, mask);
401     }
402 
403     return status;
404 }
405 
406 
407 bool
408 SplashScreen::initiateSplash (CompAction         *action,
409 	  		      CompAction::State  state,
410 	  		      CompOption::Vector options)
411 {
412     initiate = true;
413 
414     cScreen->preparePaintSetEnabled (this, true);
415     gScreen->glPaintOutputSetEnabled (this, true);
416     cScreen->donePaintSetEnabled (this, true);
417 
418     foreach (CompWindow *w, screen->windows ())
419     {
420 	SPLASH_WINDOW (w);
421 
422 	sw->gWindow->glPaintSetEnabled (sw, true);
423     }
424 
425     return false;
426 }
427 
428 /* replace with ctor, dtor, init etc */
429 
430 SplashScreen::SplashScreen (CompScreen *screen) :
431     PluginClassHandler <SplashScreen, CompScreen> (screen),
432     SplashOptions (),
433     cScreen (CompositeScreen::get (screen)),
434     gScreen (GLScreen::get (screen)),
435     splashAtom (XInternAtom (screen->dpy (), "_COMPIZ_WM_SPLASH", 0)),
436     fade_in (0),
437     fade_out (0),
438     time (0),
439     backSize (0, 0),
440     logoSize (0, 0),
441     hasInit (false),
442     hasLogo (false),
443     hasBack (false),
444     mMove (0.0),
445     brightness (0),
446     saturation (0),
447     initiate (false),
448     active (false)
449 {
450 
451     CompositeScreenInterface::setHandler (cScreen, false);
452     GLScreenInterface::setHandler (gScreen, false);
453 
454     if (optionGetFirststart () )
455     {
456 	Atom actual;
457 	int result, format;
458 	unsigned long n, left;
459 	unsigned char *propData;
460 
461 	result = XGetWindowProperty (screen->dpy (), screen->root (),
462 				     splashAtom, 0L, 8192L, false,
463 				     XA_INTEGER, &actual, &format,
464 				     &n, &left, &propData);
465 
466 	if (result == Success && n && propData)
467 	{
468 	    XFree (propData);
469 	}
470 	else
471 	{
472 	    int value = 1;
473 	    XChangeProperty (screen->dpy (), screen->root (), splashAtom,
474 			     XA_INTEGER, 32, PropModeReplace,
475 			     (unsigned char *) &value, 1);
476 	}
477 
478 	initiate = true; // should fix later
479 
480 	if (initiate)
481 	{
482 	    cScreen->preparePaintSetEnabled (this, true);
483 	    gScreen->glPaintOutputSetEnabled (this, true);
484 	    cScreen->donePaintSetEnabled (this, true);
485 	}
486     }
487 
488     optionSetInitiateKeyInitiate (boost::bind (&SplashScreen::initiateSplash,
489 						this, _1, _2, _3));
490 
491 }
492 
493 SplashWindow::SplashWindow (CompWindow *window) :
494     PluginClassHandler <SplashWindow, CompWindow> (window),
495     window (window),
496     gWindow (GLWindow::get (window))
497 {
498     GLWindowInterface::setHandler (gWindow, false);
499 
500     SPLASH_SCREEN (screen);
501 
502     if (ss->initiate)
503     {
504 	gWindow->glPaintSetEnabled (this, true);
505     }
506 }
507 
508 bool
509 SplashPluginVTable::init ()
510 {
511     if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
512 	!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
513 	!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
514 	return false;
515 
516     return true;
517 }