1 /**
2 * This file is a part of the Cairo-Dock project
3 * Login : <ctaf42@gmail.com>
4 * Started on  Sun Jan 27 18:35:38 2008 Cedric GESTES
5 * $Id$
6 *
7 * Author(s)
8 *  - Cedric GESTES <ctaf42@gmail.com>
9 *  - Fabrice REY
10 *
11 * Copyright (C) 2008 Cedric GESTES
12 * E-mail    : see the 'copyright' file.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 3
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25 */
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <time.h>
31 
32 #include <GL/gl.h>
33 #include <GL/glu.h>
34 
35 #include "gldi-config.h"
36 #include "cairo-dock-module-manager.h"
37 #include "cairo-dock-animations.h"  // cairo_dock_launch_animation
38 #include "cairo-dock-module-instance-manager.h"  // gldi_module_instance_open_conf_file
39 #include "cairo-dock-config.h"
40 #include "cairo-dock-icon-facility.h"  // cairo_dock_set_icon_container
41 #include "cairo-dock-desktop-manager.h"
42 #include "cairo-dock-log.h"
43 #include "cairo-dock-container.h"
44 #include "cairo-dock-backends-manager.h"
45 #include "cairo-dock-style-manager.h"
46 #include "cairo-dock-draw.h"
47 #include "cairo-dock-draw-opengl.h"
48 #include "cairo-dock-image-buffer.h"
49 #include "cairo-dock-desklet-factory.h"
50 #include "cairo-dock-opengl.h"
51 #include "cairo-dock-opengl-path.h"
52 #define _MANAGER_DEF_
53 #include "cairo-dock-desklet-manager.h"
54 
55 // public (manager, config, data)
56 CairoDeskletsParam myDeskletsParam;
57 GldiManager myDeskletsMgr;
58 GldiObjectManager myDeskletObjectMgr;
59 
60 // dependancies
61 extern gboolean g_bUseOpenGL;
62 extern CairoDock *g_pMainDock;  // pour savoir s'il faut afficher les boutons rattach.
63 
64 // private
65 static CairoDockImageBuffer s_pRotateButtonBuffer;
66 static CairoDockImageBuffer s_pRetachButtonBuffer;
67 static CairoDockImageBuffer s_pDepthRotateButtonBuffer;
68 static CairoDockImageBuffer s_pNoInputButtonBuffer;
69 static GList *s_pDeskletList = NULL;
70 static time_t s_iStartupTime = 0;
71 
72 static gboolean _on_update_desklet_notification (gpointer data, CairoDesklet *pDesklet, gboolean *bContinueAnimation);
73 static gboolean _on_enter_leave_desklet_notification (gpointer data, CairoDesklet *pDesklet, gboolean *bStartAnimation);
74 static gboolean _on_render_desklet_notification (gpointer pUserData, CairoDesklet *pDesklet, cairo_t *pCairoContext);
75 
76 #define _no_input_button_alpha(pDesklet) (pDesklet->bNoInput ? .4+.6*pDesklet->fButtonsAlpha : pDesklet->fButtonsAlpha)
77 #define ANGLE_MIN .1  // under this angle, the rotation is ignored.
78 
_load_desklet_buttons(void)79 void _load_desklet_buttons (void)
80 {
81 	if (myDeskletsParam.cRotateButtonImage != NULL)
82 	{
83 		cairo_dock_load_image_buffer (&s_pRotateButtonBuffer,
84 			myDeskletsParam.cRotateButtonImage,
85 			myDeskletsParam.iDeskletButtonSize,
86 			myDeskletsParam.iDeskletButtonSize,
87 			CAIRO_DOCK_FILL_SPACE);
88 	}
89 	if (s_pRotateButtonBuffer.pSurface == NULL)
90 	{
91 		cairo_dock_load_image_buffer (&s_pRotateButtonBuffer,
92 			GLDI_SHARE_DATA_DIR"/icons/rotate-desklet.svg",
93 			myDeskletsParam.iDeskletButtonSize,
94 			myDeskletsParam.iDeskletButtonSize,
95 			CAIRO_DOCK_FILL_SPACE);
96 	}
97 
98 	if (myDeskletsParam.cRetachButtonImage != NULL)
99 	{
100 		cairo_dock_load_image_buffer (&s_pRetachButtonBuffer,
101 			myDeskletsParam.cRetachButtonImage,
102 			myDeskletsParam.iDeskletButtonSize,
103 			myDeskletsParam.iDeskletButtonSize,
104 			CAIRO_DOCK_FILL_SPACE);
105 	}
106 	if (s_pRetachButtonBuffer.pSurface == NULL)
107 	{
108 		cairo_dock_load_image_buffer (&s_pRetachButtonBuffer,
109 			GLDI_SHARE_DATA_DIR"/icons/retach-desklet.svg",
110 			myDeskletsParam.iDeskletButtonSize,
111 			myDeskletsParam.iDeskletButtonSize,
112 			CAIRO_DOCK_FILL_SPACE);
113 	}
114 
115 	if (myDeskletsParam.cDepthRotateButtonImage != NULL)
116 	{
117 		cairo_dock_load_image_buffer (&s_pDepthRotateButtonBuffer,
118 			myDeskletsParam.cDepthRotateButtonImage,
119 			myDeskletsParam.iDeskletButtonSize,
120 			myDeskletsParam.iDeskletButtonSize,
121 			CAIRO_DOCK_FILL_SPACE);
122 	}
123 	if (s_pDepthRotateButtonBuffer.pSurface == NULL)
124 	{
125 		cairo_dock_load_image_buffer (&s_pDepthRotateButtonBuffer,
126 			GLDI_SHARE_DATA_DIR"/icons/depth-rotate-desklet.svg",
127 			myDeskletsParam.iDeskletButtonSize,
128 			myDeskletsParam.iDeskletButtonSize,
129 			CAIRO_DOCK_FILL_SPACE);
130 	}
131 
132 	if (myDeskletsParam.cNoInputButtonImage != NULL)
133 	{
134 		cairo_dock_load_image_buffer (&s_pNoInputButtonBuffer,
135 			myDeskletsParam.cNoInputButtonImage,
136 			myDeskletsParam.iDeskletButtonSize,
137 			myDeskletsParam.iDeskletButtonSize,
138 			CAIRO_DOCK_FILL_SPACE);
139 	}
140 	if (s_pNoInputButtonBuffer.pSurface == NULL)
141 	{
142 		cairo_dock_load_image_buffer (&s_pNoInputButtonBuffer,
143 			GLDI_SHARE_DATA_DIR"/icons/no-input-desklet.png",
144 			myDeskletsParam.iDeskletButtonSize,
145 			myDeskletsParam.iDeskletButtonSize,
146 			CAIRO_DOCK_FILL_SPACE);
147 	}
148 }
149 
_unload_desklet_buttons(void)150 static void _unload_desklet_buttons (void)
151 {
152 	cairo_dock_unload_image_buffer (&s_pRotateButtonBuffer);
153 	cairo_dock_unload_image_buffer (&s_pRetachButtonBuffer);
154 	cairo_dock_unload_image_buffer (&s_pDepthRotateButtonBuffer);
155 	cairo_dock_unload_image_buffer (&s_pNoInputButtonBuffer);
156 }
157 
158 
159   ///////////////
160  /// DRAWING ///
161 ///////////////
162 
_compute_zoom_for_rotation(CairoDesklet * pDesklet)163 static inline double _compute_zoom_for_rotation (CairoDesklet *pDesklet)
164 {
165 	double w = pDesklet->container.iWidth/2, h = pDesklet->container.iHeight/2;
166 	double alpha = atan2 (h, w);
167 	double theta = fabs (pDesklet->fRotation);
168 	if (theta > G_PI/2)
169 		theta -= G_PI/2;
170 
171 	double d = sqrt (w * w + h * h);
172 	double xmax = d * MAX (fabs (cos (alpha + theta)), fabs (cos (alpha - theta)));
173 	double ymax = d * MAX (fabs (sin (alpha + theta)), fabs (sin (alpha - theta)));
174 	double fZoom = MIN (w / xmax, h / ymax);
175 	return fZoom;
176 }
177 
_render_desklet_cairo(CairoDesklet * pDesklet,cairo_t * pCairoContext)178 static void _render_desklet_cairo (CairoDesklet *pDesklet, cairo_t *pCairoContext)
179 {
180 	cairo_save (pCairoContext);
181 	gboolean bUseDefaultColors = pDesklet->bUseDefaultColors;
182 
183 	if (pDesklet->container.fRatio != 1)
184 	{
185 		//g_print (" desklet zoom : %.2f (%dx%d)\n", pDesklet->container.fRatio, pDesklet->container.iWidth, pDesklet->container.iHeight);
186 		cairo_translate (pCairoContext,
187 			pDesklet->container.iWidth * (1 - pDesklet->container.fRatio)/2,
188 			pDesklet->container.iHeight * (1 - pDesklet->container.fRatio)/2);
189 		cairo_scale (pCairoContext, pDesklet->container.fRatio, pDesklet->container.fRatio);
190 	}
191 
192 	if (fabs (pDesklet->fRotation) > ANGLE_MIN)
193 	{
194 		double fZoom = _compute_zoom_for_rotation (pDesklet);
195 
196 		cairo_translate (pCairoContext,
197 			.5*pDesklet->container.iWidth,
198 			.5*pDesklet->container.iHeight);
199 
200 		cairo_rotate (pCairoContext, pDesklet->fRotation);
201 
202 		cairo_scale (pCairoContext, fZoom, fZoom);
203 
204 		cairo_translate (pCairoContext,
205 			-.5*pDesklet->container.iWidth,
206 			-.5*pDesklet->container.iHeight);
207 	}
208 
209 	if (bUseDefaultColors)
210 	{
211 		cairo_save (pCairoContext);
212 		cairo_dock_draw_rounded_rectangle (pCairoContext, myStyleParam.iCornerRadius, myStyleParam.iLineWidth, pDesklet->container.iWidth - 2 * (myStyleParam.iCornerRadius + myStyleParam.iLineWidth), pDesklet->container.iHeight - myStyleParam.iLineWidth);
213 		gldi_style_colors_set_bg_color (pCairoContext);
214 		cairo_fill_preserve (pCairoContext);
215 		gldi_style_colors_set_line_color (pCairoContext);
216 		cairo_set_line_width (pCairoContext, myStyleParam.iLineWidth);
217 		cairo_stroke (pCairoContext);
218 		cairo_restore (pCairoContext);
219 	}
220 	else if (pDesklet->backGroundImageBuffer.pSurface != NULL)
221 	{
222 		cairo_dock_apply_image_buffer_surface (&pDesklet->backGroundImageBuffer, pCairoContext);
223 	}
224 
225 	cairo_save (pCairoContext);
226 	if (pDesklet->iLeftSurfaceOffset != 0 || pDesklet->iTopSurfaceOffset != 0 || pDesklet->iRightSurfaceOffset != 0 || pDesklet->iBottomSurfaceOffset != 0)
227 	{
228 		cairo_translate (pCairoContext, pDesklet->iLeftSurfaceOffset, pDesklet->iTopSurfaceOffset);
229 		cairo_scale (pCairoContext,
230 			1. - (double)(pDesklet->iLeftSurfaceOffset + pDesklet->iRightSurfaceOffset) / pDesklet->container.iWidth,
231 			1. - (double)(pDesklet->iTopSurfaceOffset + pDesklet->iBottomSurfaceOffset) / pDesklet->container.iHeight);
232 	}
233 
234 	if (pDesklet->pRenderer != NULL && pDesklet->pRenderer->render != NULL)  // un moteur de rendu specifique a ete fourni.
235 	{
236 		pDesklet->pRenderer->render (pCairoContext, pDesklet);
237 	}
238 	cairo_restore (pCairoContext);
239 
240 	if (pDesklet->foreGroundImageBuffer.pSurface != NULL)
241 	{
242 		cairo_dock_apply_image_buffer_surface (&pDesklet->foreGroundImageBuffer, pCairoContext);
243 	}
244 
245 	if (! pDesklet->rotating)  // si on est en train de tourner, les boutons suivent le mouvement, sinon ils sont dans les coins.
246 	{
247 		cairo_restore (pCairoContext);
248 		cairo_save (pCairoContext);
249 	}
250 	if ((pDesklet->container.bInside || pDesklet->rotating || pDesklet->fButtonsAlpha != 0) && cairo_dock_desklet_is_free (pDesklet))
251 	{
252 		if (s_pRotateButtonBuffer.pSurface != NULL)
253 		{
254 			cairo_dock_apply_image_buffer_surface_with_offset (&s_pRotateButtonBuffer, pCairoContext,
255 				0., 0., pDesklet->fButtonsAlpha);
256 		}
257 		if (s_pRetachButtonBuffer.pSurface != NULL && g_pMainDock)
258 		{
259 			cairo_dock_apply_image_buffer_surface_with_offset (&s_pRetachButtonBuffer, pCairoContext,
260 				pDesklet->container.iWidth - s_pRetachButtonBuffer.iWidth, 0., pDesklet->fButtonsAlpha);
261 		}
262 	}
263 	if ((pDesklet->container.bInside || pDesklet->bNoInput || pDesklet->fButtonsAlpha) && s_pNoInputButtonBuffer.pSurface != NULL && pDesklet->bAllowNoClickable)
264 	{
265 		cairo_dock_apply_image_buffer_surface_with_offset (&s_pNoInputButtonBuffer, pCairoContext,
266 			pDesklet->container.iWidth - s_pNoInputButtonBuffer.iWidth, pDesklet->container.iHeight - s_pNoInputButtonBuffer.iHeight, _no_input_button_alpha (pDesklet));
267 	}
268 	cairo_restore (pCairoContext);
269 }
270 
_set_desklet_matrix(CairoDesklet * pDesklet)271 static inline void _set_desklet_matrix (CairoDesklet *pDesklet)
272 {
273 	double fDepthRotationY = (fabs (pDesklet->fDepthRotationY) > ANGLE_MIN ? pDesklet->fDepthRotationY : 0.);
274 	double fDepthRotationX = (fabs (pDesklet->fDepthRotationX) > ANGLE_MIN ? pDesklet->fDepthRotationX : 0.);
275 	glTranslatef (0., 0., -pDesklet->container.iHeight * sqrt(3)/2 -
276 		.45 * MAX (pDesklet->container.iWidth * fabs (sin (fDepthRotationY)),
277 			pDesklet->container.iHeight * fabs (sin (fDepthRotationX)))
278 		);  // avec 60 deg de perspective
279 
280 	if (pDesklet->container.fRatio != 1)
281 	{
282 		glScalef (pDesklet->container.fRatio, pDesklet->container.fRatio, 1.);
283 	}
284 
285 	if (fabs (pDesklet->fRotation) > ANGLE_MIN)
286 	{
287 		double fZoom = _compute_zoom_for_rotation (pDesklet);
288 		glScalef (fZoom, fZoom, 1.);
289 		glRotatef (- pDesklet->fRotation / G_PI * 180., 0., 0., 1.);
290 	}
291 
292 	if (fDepthRotationY != 0)
293 	{
294 		glRotatef (- pDesklet->fDepthRotationY / G_PI * 180., 0., 1., 0.);
295 	}
296 
297 	if (fDepthRotationX != 0)
298 	{
299 		glRotatef (- pDesklet->fDepthRotationX / G_PI * 180., 1., 0., 0.);
300 	}
301 }
302 
_render_desklet_opengl(CairoDesklet * pDesklet)303 static void _render_desklet_opengl (CairoDesklet *pDesklet)
304 {
305 	gboolean bUseDefaultColors = pDesklet->bUseDefaultColors;
306 	glPushMatrix ();
307 	///glTranslatef (0*pDesklet->container.iWidth/2, 0*pDesklet->container.iHeight/2, 0.);  // avec une perspective ortho.
308 	///glTranslatef (0*pDesklet->container.iWidth/2, 0*pDesklet->container.iHeight/2, -pDesklet->container.iWidth*(1.87 +.35*fabs (sin(pDesklet->fDepthRotationY))));  // avec 30 deg de perspective
309 	_set_desklet_matrix (pDesklet);
310 
311 	if (bUseDefaultColors)
312 	{
313 		_cairo_dock_set_blend_alpha ();
314 		gldi_style_colors_set_bg_color (NULL);
315 		cairo_dock_draw_rounded_rectangle_opengl (pDesklet->container.iWidth - 2 * (myStyleParam.iCornerRadius + myStyleParam.iLineWidth), pDesklet->container.iHeight - 2*myStyleParam.iLineWidth, myStyleParam.iCornerRadius, 0, NULL);
316 
317 		gldi_style_colors_set_line_color (NULL);
318 		cairo_dock_draw_rounded_rectangle_opengl (pDesklet->container.iWidth - 2 * (myStyleParam.iCornerRadius + myStyleParam.iLineWidth), pDesklet->container.iHeight - 2*myStyleParam.iLineWidth, myStyleParam.iCornerRadius, myStyleParam.iLineWidth, NULL);
319 	}
320 
321 	_cairo_dock_enable_texture ();
322 	_cairo_dock_set_blend_pbuffer ();
323 	_cairo_dock_set_alpha (1.);
324 	if (pDesklet->backGroundImageBuffer.iTexture != 0)
325 	{
326 		cairo_dock_apply_image_buffer_texture (&pDesklet->backGroundImageBuffer);
327 	}
328 
329 	glPushMatrix ();
330 	if (pDesklet->iLeftSurfaceOffset != 0 || pDesklet->iTopSurfaceOffset != 0 || pDesklet->iRightSurfaceOffset != 0 || pDesklet->iBottomSurfaceOffset != 0)
331 	{
332 		glTranslatef ((pDesklet->iLeftSurfaceOffset - pDesklet->iRightSurfaceOffset)/2, (pDesklet->iBottomSurfaceOffset - pDesklet->iTopSurfaceOffset)/2, 0.);
333 		glScalef (1. - (double)(pDesklet->iLeftSurfaceOffset + pDesklet->iRightSurfaceOffset) / pDesklet->container.iWidth,
334 			1. - (double)(pDesklet->iTopSurfaceOffset + pDesklet->iBottomSurfaceOffset) / pDesklet->container.iHeight,
335 			1.);
336 	}
337 
338 	if (pDesklet->pRenderer != NULL && pDesklet->pRenderer->render_opengl != NULL)  // un moteur de rendu specifique a ete fourni.
339 	{
340 		pDesklet->pRenderer->render_opengl (pDesklet);
341 	}
342 	glPopMatrix ();
343 
344 	_cairo_dock_enable_texture ();
345 	_cairo_dock_set_blend_pbuffer ();
346 	if (pDesklet->foreGroundImageBuffer.iTexture != 0)
347 	{
348 		cairo_dock_apply_image_buffer_texture (&pDesklet->foreGroundImageBuffer);
349 	}
350 
351 	//if (pDesklet->container.bInside && cairo_dock_desklet_is_free (pDesklet))
352 	{
353 		if (! pDesklet->rotating && ! pDesklet->rotatingY && ! pDesklet->rotatingX)
354 		{
355 			glPopMatrix ();
356 			glPushMatrix ();
357 			glTranslatef (0., 0., -pDesklet->container.iHeight*(sqrt(3)/2));
358 		}
359 	}
360 
361 	if ((pDesklet->container.bInside || pDesklet->fButtonsAlpha != 0 || pDesklet->rotating || pDesklet->rotatingY || pDesklet->rotatingX) && cairo_dock_desklet_is_free (pDesklet))
362 	{
363 		_cairo_dock_set_blend_alpha ();
364 		_cairo_dock_set_alpha (sqrt(pDesklet->fButtonsAlpha));
365 		if (s_pRotateButtonBuffer.iTexture != 0)
366 		{
367 			cairo_dock_apply_image_buffer_texture_with_offset (&s_pRotateButtonBuffer,
368 				-pDesklet->container.iWidth/2 + s_pRotateButtonBuffer.iWidth/2,
369 				pDesklet->container.iHeight/2 - s_pRotateButtonBuffer.iHeight/2);
370 		}
371 		if (s_pRetachButtonBuffer.iTexture != 0 && g_pMainDock)
372 		{
373 			cairo_dock_apply_image_buffer_texture_with_offset (&s_pRetachButtonBuffer,
374 				pDesklet->container.iWidth/2 - s_pRetachButtonBuffer.iWidth/2,
375 				pDesklet->container.iHeight/2 - s_pRetachButtonBuffer.iHeight/2);
376 		}
377 		if (s_pDepthRotateButtonBuffer.iTexture != 0)
378 		{
379 			cairo_dock_apply_image_buffer_texture_with_offset (&s_pDepthRotateButtonBuffer,
380 				0.,
381 				pDesklet->container.iHeight/2 - s_pDepthRotateButtonBuffer.iHeight/2);
382 
383 			glPushMatrix ();
384 			glRotatef (90., 0., 0., 1.);
385 			cairo_dock_apply_image_buffer_texture_with_offset (&s_pDepthRotateButtonBuffer,
386 				0.,
387 				pDesklet->container.iWidth/2 - s_pDepthRotateButtonBuffer.iHeight/2);
388 			glPopMatrix ();
389 		}
390 	}
391 	if ((pDesklet->container.bInside || pDesklet->fButtonsAlpha != 0 || pDesklet->bNoInput) && s_pNoInputButtonBuffer.iTexture != 0 && pDesklet->bAllowNoClickable)
392 	{
393 		_cairo_dock_set_blend_alpha ();
394 		_cairo_dock_set_alpha (_no_input_button_alpha(pDesklet));
395 		cairo_dock_apply_image_buffer_texture_with_offset (&s_pNoInputButtonBuffer,
396 			pDesklet->container.iWidth/2 - s_pNoInputButtonBuffer.iWidth/2,
397 			- pDesklet->container.iHeight/2 + s_pNoInputButtonBuffer.iHeight/2);
398 	}
399 
400 	_cairo_dock_disable_texture ();
401 	glPopMatrix ();
402 }
403 
_on_render_desklet_notification(G_GNUC_UNUSED gpointer pUserData,CairoDesklet * pDesklet,cairo_t * pCairoContext)404 static gboolean _on_render_desklet_notification (G_GNUC_UNUSED gpointer pUserData, CairoDesklet *pDesklet, cairo_t *pCairoContext)
405 {
406 	if (pCairoContext != NULL)
407 		_render_desklet_cairo (pDesklet, pCairoContext);
408 	else
409 		_render_desklet_opengl (pDesklet);
410 	return GLDI_NOTIFICATION_LET_PASS;
411 }
412 
_on_enter_leave_desklet_notification(G_GNUC_UNUSED gpointer data,CairoDesklet * pDesklet,gboolean * bStartAnimation)413 static gboolean _on_enter_leave_desklet_notification (G_GNUC_UNUSED gpointer data, CairoDesklet *pDesklet, gboolean *bStartAnimation)
414 {
415 	pDesklet->bButtonsApparition = TRUE;
416 	*bStartAnimation = TRUE;
417 	return GLDI_NOTIFICATION_LET_PASS;
418 }
419 
_on_update_desklet_notification(G_GNUC_UNUSED gpointer data,CairoDesklet * pDesklet,gboolean * bContinueAnimation)420 static gboolean _on_update_desklet_notification (G_GNUC_UNUSED gpointer data, CairoDesklet *pDesklet, gboolean *bContinueAnimation)
421 {
422 	if (!pDesklet->bButtonsApparition && !pDesklet->bGrowingUp)
423 		return GLDI_NOTIFICATION_LET_PASS;
424 
425 	if (pDesklet->bButtonsApparition)
426 	{
427 		pDesklet->fButtonsAlpha += (pDesklet->container.bInside ? .1 : -.1);
428 		//g_print ("fButtonsAlpha <- %.2f\n", pDesklet->fButtonsAlpha);
429 
430 		if (pDesklet->fButtonsAlpha <= 0 || pDesklet->fButtonsAlpha >= 1)
431 		{
432 			pDesklet->bButtonsApparition = FALSE;
433 			if (pDesklet->fButtonsAlpha < 0)
434 				pDesklet->fButtonsAlpha = 0.;
435 			else if (pDesklet->fButtonsAlpha > 1)
436 				pDesklet->fButtonsAlpha = 1.;
437 		}
438 		else
439 		{
440 			*bContinueAnimation = TRUE;
441 		}
442 	}
443 
444 	if (pDesklet->bGrowingUp)
445 	{
446 		pDesklet->container.fRatio += .04;
447 		//g_print ("pDesklet->container.fRatio:%.2f\n", pDesklet->container.fRatio);
448 
449 		if (pDesklet->container.fRatio >= 1.1)  // la derniere est a x1.1
450 		{
451 			pDesklet->container.fRatio = 1;
452 			pDesklet->bGrowingUp = FALSE;
453 		}
454 		else
455 		{
456 			*bContinueAnimation = TRUE;
457 		}
458 	}
459 
460 	gtk_widget_queue_draw (pDesklet->container.pWidget);
461 	return GLDI_NOTIFICATION_LET_PASS;
462 }
463 
_cairo_dock_pick_icon_on_opengl_desklet(CairoDesklet * pDesklet)464 static Icon *_cairo_dock_pick_icon_on_opengl_desklet (CairoDesklet *pDesklet)
465 {
466 	GLuint selectBuf[4];
467 	GLint hits=0;
468 	GLint viewport[4];
469 
470 	if (! gldi_gl_container_make_current (CAIRO_CONTAINER (pDesklet)))
471 		return NULL;
472 
473 	glGetIntegerv (GL_VIEWPORT, viewport);
474 	glSelectBuffer (4, selectBuf);
475 
476 	glRenderMode(GL_SELECT);
477 	glInitNames();
478 	glPushName(0);
479 
480 	glMatrixMode (GL_PROJECTION);
481 	glPushMatrix ();
482 	glLoadIdentity ();
483 	gluPickMatrix ((GLdouble) pDesklet->container.iMouseX, (GLdouble) (viewport[3] - pDesklet->container.iMouseY), 2.0, 2.0, viewport);
484 	gluPerspective (60.0, 1.0*(GLfloat)pDesklet->container.iWidth/(GLfloat)pDesklet->container.iHeight, 1., 4*pDesklet->container.iHeight);
485 
486 	glMatrixMode (GL_MODELVIEW);
487 	glPushMatrix ();
488 	glLoadIdentity ();
489 
490 	_set_desklet_matrix (pDesklet);
491 
492 	if (pDesklet->iLeftSurfaceOffset != 0 || pDesklet->iTopSurfaceOffset != 0 || pDesklet->iRightSurfaceOffset != 0 || pDesklet->iBottomSurfaceOffset != 0)
493 	{
494 		glTranslatef ((pDesklet->iLeftSurfaceOffset - pDesklet->iRightSurfaceOffset)/2, (pDesklet->iBottomSurfaceOffset - pDesklet->iTopSurfaceOffset)/2, 0.);
495 		glScalef (1. - (double)(pDesklet->iLeftSurfaceOffset + pDesklet->iRightSurfaceOffset) / pDesklet->container.iWidth,
496 			1. - (double)(pDesklet->iTopSurfaceOffset + pDesklet->iBottomSurfaceOffset) / pDesklet->container.iHeight,
497 			1.);
498 	}
499 
500 	glPolygonMode (GL_FRONT, GL_FILL);
501 	glColor4f (1., 1., 1., 1.);
502 
503 	pDesklet->iPickedObject = 0;
504 	if (pDesklet->render_bounding_box != NULL)  // surclasse la fonction du moteur de rendu.
505 	{
506 		pDesklet->render_bounding_box (pDesklet);
507 	}
508 	else if (pDesklet->pRenderer && pDesklet->pRenderer->render_bounding_box != NULL)
509 	{
510 		pDesklet->pRenderer->render_bounding_box (pDesklet);
511 	}
512 	else  // on le fait nous-memes a partir des coordonnees des icones.
513 	{
514 		glTranslatef (-pDesklet->container.iWidth/2, -pDesklet->container.iHeight/2, 0.);
515 
516 		double x, y, w, h;
517 		Icon *pIcon;
518 
519 		pIcon = pDesklet->pIcon;
520 		if (pIcon != NULL && pIcon->image.iTexture != 0)
521 		{
522 			w = pIcon->fWidth/2;
523 			h = pIcon->fHeight/2;
524 			x = pIcon->fDrawX + w;
525 			y = pDesklet->container.iHeight - pIcon->fDrawY - h;
526 
527 			glLoadName(pIcon->image.iTexture);
528 
529 			glBegin(GL_QUADS);
530 			glVertex3f(x-w, y+h, 0.);
531 			glVertex3f(x+w, y+h, 0.);
532 			glVertex3f(x+w, y-h, 0.);
533 			glVertex3f(x-w, y-h, 0.);
534 			glEnd();
535 		}
536 
537 		GList *ic;
538 		for (ic = pDesklet->icons; ic != NULL; ic = ic->next)
539 		{
540 			pIcon = ic->data;
541 			if (pIcon->image.iTexture == 0)
542 				continue;
543 
544 			w = pIcon->fWidth/2;
545 			h = pIcon->fHeight/2;
546 			x = pIcon->fDrawX + w;
547 			y = pDesklet->container.iHeight - pIcon->fDrawY - h;
548 
549 			glLoadName(pIcon->image.iTexture);
550 
551 			glBegin(GL_QUADS);
552 			glVertex3f(x-w, y+h, 0.);
553 			glVertex3f(x+w, y+h, 0.);
554 			glVertex3f(x+w, y-h, 0.);
555 			glVertex3f(x-w, y-h, 0.);
556 			glEnd();
557 		}
558 	}
559 
560 	glPopName();
561 
562 	hits = glRenderMode (GL_RENDER);
563 
564 	glMatrixMode (GL_PROJECTION);
565 	glPopMatrix ();
566 	glMatrixMode(GL_MODELVIEW);
567 	glPopMatrix ();
568 
569 	Icon *pFoundIcon = NULL;
570 	if (hits != 0)
571 	{
572 		GLuint id = selectBuf[3];
573 		Icon *pIcon;
574 
575 		if (pDesklet->render_bounding_box != NULL)
576 		{
577 			pDesklet->iPickedObject = id;
578 			//g_print ("iPickedObject <- %d\n", id);
579 			pFoundIcon = pDesklet->pIcon;  // il faut mettre qqch, sinon la notification est filtree par la macro CD_APPLET_ON_CLICK_BEGIN.
580 		}
581 		else
582 		{
583 			pIcon = pDesklet->pIcon;
584 			if (pIcon != NULL && pIcon->image.iTexture != 0)
585 			{
586 				if (pIcon->image.iTexture == id)
587 				{
588 					pFoundIcon = pIcon;
589 				}
590 			}
591 
592 			if (pFoundIcon == NULL)
593 			{
594 				GList *ic;
595 				for (ic = pDesklet->icons; ic != NULL; ic = ic->next)
596 				{
597 					pIcon = ic->data;
598 					if (pIcon->image.iTexture == id)
599 					{
600 						pFoundIcon = pIcon;
601 						break ;
602 					}
603 				}
604 			}
605 		}
606 	}
607 
608 	return pFoundIcon;
609 }
gldi_desklet_find_clicked_icon(CairoDesklet * pDesklet)610 Icon *gldi_desklet_find_clicked_icon (CairoDesklet *pDesklet)
611 {
612 	if (g_bUseOpenGL && pDesklet->pRenderer && pDesklet->pRenderer->render_opengl)
613 	{
614 		return _cairo_dock_pick_icon_on_opengl_desklet (pDesklet);
615 	}
616 
617 	int iMouseX = pDesklet->container.iMouseX, iMouseY = pDesklet->container.iMouseY;
618 	if (fabs (pDesklet->fRotation) > ANGLE_MIN)
619 	{
620 		//g_print (" clic en (%d;%d) rotations : %.2frad\n", iMouseX, iMouseY, pDesklet->fRotation);
621 		double x, y;  // par rapport au centre du desklet.
622 		x = iMouseX - pDesklet->container.iWidth/2;
623 		y = pDesklet->container.iHeight/2 - iMouseY;
624 
625 		double r, t;  // coordonnees polaires.
626 		r = sqrt (x*x + y*y);
627 		t = atan2 (y, x);
628 
629 		double z = _compute_zoom_for_rotation (pDesklet);
630 		r /= z;
631 
632 		x = r * cos (t + pDesklet->fRotation);  // la rotation de cairo est dans le sene horaire.
633 		y = r * sin (t + pDesklet->fRotation);
634 
635 		iMouseX = x + pDesklet->container.iWidth/2;
636 		iMouseY = pDesklet->container.iHeight/2 - y;
637 		//g_print (" => (%d;%d)\n", iMouseX, iMouseY);
638 	}
639 	pDesklet->iMouseX2d = iMouseX;
640 	pDesklet->iMouseY2d = iMouseY;
641 
642 	Icon *icon = pDesklet->pIcon;
643 	g_return_val_if_fail (icon != NULL, NULL);  // peut arriver au tout debut, car on associe l'icone au desklet _apres_ l'avoir cree, et on fait tourner la gtk_main entre-temps (pour le redessiner invisible).
644 	if (icon->fDrawX < iMouseX && icon->fDrawX + icon->fWidth * icon->fScale > iMouseX && icon->fDrawY < iMouseY && icon->fDrawY + icon->fHeight * icon->fScale > iMouseY)
645 	{
646 		return icon;
647 	}
648 
649 	if (pDesklet->icons != NULL)
650 	{
651 		GList* ic;
652 		for (ic = pDesklet->icons; ic != NULL; ic = ic->next)
653 		{
654 			icon = ic->data;
655 			if (icon->fDrawX < iMouseX && icon->fDrawX + icon->fWidth * icon->fScale > iMouseX && icon->fDrawY < iMouseY && icon->fDrawY + icon->fHeight * icon->fScale > iMouseY)
656 			{
657 				return icon;
658 			}
659 		}
660 	}
661 	return NULL;
662 }
663 
664 
665   ///////////////
666  /// MANAGER ///
667 ///////////////
668 
gldi_desklets_foreach(GldiDeskletForeachFunc pCallback,gpointer user_data)669 CairoDesklet *gldi_desklets_foreach (GldiDeskletForeachFunc pCallback, gpointer user_data)
670 {
671 	CairoDesklet *pDesklet;
672 	GList *dl;
673 	for (dl = s_pDeskletList; dl != NULL; dl = dl->next)
674 	{
675 		pDesklet = dl->data;
676 		if (pCallback (pDesklet, user_data))
677 			return pDesklet;
678 	}
679 
680 	return NULL;
681 }
682 
_foreach_icons_in_desklet(CairoDesklet * pDesklet,gpointer * data)683 static gboolean _foreach_icons_in_desklet (CairoDesklet *pDesklet, gpointer *data)
684 {
685 	GldiIconFunc pFunction = data[0];
686 	gpointer pUserData = data[1];
687 	if (pDesklet->pIcon != NULL)
688 		pFunction (pDesklet->pIcon, pUserData);
689 	GList *ic;
690 	for (ic = pDesklet->icons; ic != NULL; ic = ic->next)
691 	{
692 		pFunction ((Icon*)ic->data, pUserData);
693 	}
694 	return FALSE;
695 }
gldi_desklets_foreach_icons(GldiIconFunc pFunction,gpointer pUserData)696 void gldi_desklets_foreach_icons (GldiIconFunc pFunction, gpointer pUserData)
697 {
698 	gpointer data[2] = {pFunction, pUserData};
699 	gldi_desklets_foreach ((GldiDeskletForeachFunc) _foreach_icons_in_desklet, data);
700 }
701 
702 
_set_one_desklet_visible(CairoDesklet * pDesklet,gpointer data)703 static void _set_one_desklet_visible (CairoDesklet *pDesklet, gpointer data)
704 {
705 	gboolean bOnWidgetLayerToo = GPOINTER_TO_INT (data);
706 	gboolean bIsOnWidgetLayer = (pDesklet->iVisibility == CAIRO_DESKLET_ON_WIDGET_LAYER);
707 	if (bOnWidgetLayerToo || ! bIsOnWidgetLayer)
708 	{
709 		if (bIsOnWidgetLayer)  // on le passe sur la couche visible.
710 			gldi_desktop_set_on_widget_layer (CAIRO_CONTAINER (pDesklet), FALSE);
711 
712 		gtk_window_set_keep_below (GTK_WINDOW (pDesklet->container.pWidget), FALSE);
713 
714 		gldi_desklet_show (pDesklet);
715 	}
716 }
gldi_desklets_set_visible(gboolean bOnWidgetLayerToo)717 void gldi_desklets_set_visible (gboolean bOnWidgetLayerToo)
718 {
719 	cd_debug ("%s (%d)", __func__, bOnWidgetLayerToo);
720 	CairoDesklet *pDesklet;
721 	GList *dl;
722 	for (dl = s_pDeskletList; dl != NULL; dl = dl->next)
723 	{
724 		pDesklet = dl->data;
725 		_set_one_desklet_visible (pDesklet, GINT_TO_POINTER (bOnWidgetLayerToo));
726 	}
727 }
728 
_set_one_desklet_visibility_to_default(CairoDesklet * pDesklet,CairoDockMinimalAppletConfig * pMinimalConfig)729 static void _set_one_desklet_visibility_to_default (CairoDesklet *pDesklet, CairoDockMinimalAppletConfig *pMinimalConfig)
730 {
731 	if (pDesklet->pIcon != NULL)
732 	{
733 		GldiModuleInstance *pInstance = pDesklet->pIcon->pModuleInstance;
734 		GKeyFile *pKeyFile = gldi_module_instance_open_conf_file (pInstance, pMinimalConfig);
735 		g_key_file_free (pKeyFile);
736 
737 		gldi_desklet_set_accessibility (pDesklet, pMinimalConfig->deskletAttribute.iVisibility, FALSE);
738 	}
739 	pDesklet->bAllowMinimize = FALSE;  /// utile ?...
740 }
gldi_desklets_set_visibility_to_default(void)741 void gldi_desklets_set_visibility_to_default (void)
742 {
743 	CairoDockMinimalAppletConfig minimalConfig;
744 	CairoDesklet *pDesklet;
745 	GList *dl;
746 	for (dl = s_pDeskletList; dl != NULL; dl = dl->next)
747 	{
748 		pDesklet = dl->data;
749 		_set_one_desklet_visibility_to_default (pDesklet, &minimalConfig);
750 	}
751 }
752 
753 
gldi_desklet_manager_is_ready(void)754 gboolean gldi_desklet_manager_is_ready (void)
755 {
756 	static gboolean bReady = FALSE;
757 	if (!bReady)  // once we are ready, no need to test it again.
758 	{
759 		bReady = (time (NULL) > s_iStartupTime + 5);  // 5s delay on startup
760 	}
761 	return bReady;
762 }
763 
_on_desktop_geometry_changed(G_GNUC_UNUSED gpointer data)764 static gboolean _on_desktop_geometry_changed (G_GNUC_UNUSED gpointer data)
765 {
766 	// when the screen size changes, X will send a 'configure' event to each windows (because size and position might have changed), which will be interpreted by the desklet as a user displacement.
767 	// we must therefore replace the desklets at their correct position in the new desktop space.
768 	CairoDesklet *pDesklet;
769 	CairoDockMinimalAppletConfig *pMinimalConfig;
770 	GList *dl;
771 	for (dl = s_pDeskletList; dl != NULL; dl = dl->next)
772 	{
773 		pDesklet = dl->data;
774 		//g_print ("%s : %d;%d\n", pDesklet->pIcon->pModuleInstance->pModule->pVisitCard->cModuleName, pDesklet->container.iWindowPositionX, pDesklet->container.iWindowPositionY);
775 
776 		if (CAIRO_DOCK_IS_APPLET (pDesklet->pIcon))
777 		{
778 			// get the position (and other parameters) as defined by the user.
779 			pMinimalConfig = g_new0 (CairoDockMinimalAppletConfig, 1);
780 			GKeyFile *pKeyFile = gldi_module_instance_open_conf_file (pDesklet->pIcon->pModuleInstance, pMinimalConfig);
781 			//g_print ("  %d;%d\n", pMinimalConfig->deskletAttribute.iDeskletPositionX, pMinimalConfig->deskletAttribute.iDeskletPositionY);
782 
783 			// apply the settings to the desklet (actually we only need the position).
784 			gldi_desklet_configure (pDesklet, &pMinimalConfig->deskletAttribute);
785 			gldi_module_instance_free_generic_config (pMinimalConfig);
786 			g_key_file_free (pKeyFile);
787 		}
788 	}
789 	return GLDI_NOTIFICATION_LET_PASS;
790 }
791 
792 
793   //////////////////
794  /// GET CONFIG ///
795 //////////////////
796 
get_config(GKeyFile * pKeyFile,CairoDeskletsParam * pDesklets)797 static gboolean get_config (GKeyFile *pKeyFile, CairoDeskletsParam *pDesklets)
798 {
799 	gboolean bFlushConfFileNeeded = FALSE;
800 
801 	// register an "automatic" decoration, that takes its colors from the global style (do it now, after the global style has been defined)
802 	CairoDeskletDecoration * pDecoration = cairo_dock_get_desklet_decoration ("automatic");
803 	if (pDecoration == NULL)
804 	{
805 		pDecoration = g_new0 (CairoDeskletDecoration, 1);
806 		pDecoration->cDisplayedName = _("Automatic");
807 		pDecoration->iLeftMargin = pDecoration->iTopMargin = pDecoration->iRightMargin = pDecoration->iBottomMargin = myStyleParam.iLineWidth;
808 		pDecoration->fBackGroundAlpha = 1.;
809 		pDecoration->cBackGroundImagePath = g_strdup ("automatic");  // keyword to say we use global style colors rather an image
810 		cairo_dock_register_desklet_decoration ("automatic", pDecoration);  // we don't actually load an Imagebuffer,
811 	}
812 
813 	// register a "custom" decoration, that takes its colors from the config if the use has defined it
814 	pDesklets->cDeskletDecorationsName = cairo_dock_get_string_key_value (pKeyFile, "Desklets", "decorations", &bFlushConfFileNeeded, NULL, NULL, NULL);
815 	CairoDeskletDecoration *pUserDeskletDecorations = cairo_dock_get_desklet_decoration ("personnal");
816 	if (pUserDeskletDecorations == NULL)
817 	{
818 		pUserDeskletDecorations = g_new0 (CairoDeskletDecoration, 1);
819 		pUserDeskletDecorations->cDisplayedName = _("_custom decoration_");
820 		cairo_dock_register_desklet_decoration ("personnal", pUserDeskletDecorations);
821 	}
822 	if (pDesklets->cDeskletDecorationsName != NULL && strcmp (pDesklets->cDeskletDecorationsName, "personnal") == 0)
823 	{
824 		g_free (pUserDeskletDecorations->cBackGroundImagePath);
825 		pUserDeskletDecorations->cBackGroundImagePath = cairo_dock_get_string_key_value (pKeyFile, "Desklets", "bg desklet", &bFlushConfFileNeeded, NULL, NULL, NULL);
826 		g_free (pUserDeskletDecorations->cForeGroundImagePath);
827 		pUserDeskletDecorations->cForeGroundImagePath = cairo_dock_get_string_key_value (pKeyFile, "Desklets", "fg desklet", &bFlushConfFileNeeded, NULL, NULL, NULL);
828 		pUserDeskletDecorations->iLoadingModifier = CAIRO_DOCK_FILL_SPACE;
829 		pUserDeskletDecorations->fBackGroundAlpha = cairo_dock_get_double_key_value (pKeyFile, "Desklets", "bg alpha", &bFlushConfFileNeeded, 1.0, NULL, NULL);
830 		pUserDeskletDecorations->fForeGroundAlpha = cairo_dock_get_double_key_value (pKeyFile, "Desklets", "fg alpha", &bFlushConfFileNeeded, 1.0, NULL, NULL);
831 		pUserDeskletDecorations->iLeftMargin = cairo_dock_get_integer_key_value (pKeyFile, "Desklets", "left offset", &bFlushConfFileNeeded, 0, NULL, NULL);
832 		pUserDeskletDecorations->iTopMargin = cairo_dock_get_integer_key_value (pKeyFile, "Desklets", "top offset", &bFlushConfFileNeeded, 0, NULL, NULL);
833 		pUserDeskletDecorations->iRightMargin = cairo_dock_get_integer_key_value (pKeyFile, "Desklets", "right offset", &bFlushConfFileNeeded, 0, NULL, NULL);
834 		pUserDeskletDecorations->iBottomMargin = cairo_dock_get_integer_key_value (pKeyFile, "Desklets", "bottom offset", &bFlushConfFileNeeded, 0, NULL, NULL);
835 	}
836 
837 	pDesklets->iDeskletButtonSize = cairo_dock_get_integer_key_value (pKeyFile, "Desklets", "button size", &bFlushConfFileNeeded, 16, NULL, NULL);
838 	pDesklets->cRotateButtonImage = cairo_dock_get_string_key_value (pKeyFile, "Desklets", "rotate image", &bFlushConfFileNeeded, NULL, NULL, NULL);
839 	pDesklets->cRetachButtonImage = cairo_dock_get_string_key_value (pKeyFile, "Desklets", "retach image", &bFlushConfFileNeeded, NULL, NULL, NULL);
840 	pDesklets->cDepthRotateButtonImage = cairo_dock_get_string_key_value (pKeyFile, "Desklets", "depth rotate image", &bFlushConfFileNeeded, NULL, NULL, NULL);
841 	pDesklets->cNoInputButtonImage = cairo_dock_get_string_key_value (pKeyFile, "Desklets", "no input image", &bFlushConfFileNeeded, NULL, NULL, NULL);
842 	return bFlushConfFileNeeded;
843 }
844 
845   ////////////////////
846  /// RESET CONFIG ///
847 ////////////////////
848 
reset_config(CairoDeskletsParam * pDesklets)849 static void reset_config (CairoDeskletsParam *pDesklets)
850 {
851 	g_free (pDesklets->cDeskletDecorationsName);
852 	g_free (pDesklets->cRotateButtonImage);
853 	g_free (pDesklets->cRetachButtonImage);
854 	g_free (pDesklets->cDepthRotateButtonImage);
855 	g_free (pDesklets->cNoInputButtonImage);
856 }
857 
858   //////////////
859  /// RELOAD ///
860 //////////////
861 
reload(CairoDeskletsParam * pPrevDesklets,CairoDeskletsParam * pDesklets)862 static void reload (CairoDeskletsParam *pPrevDesklets, CairoDeskletsParam *pDesklets)
863 {
864 	if (g_strcmp0 (pPrevDesklets->cRotateButtonImage, pDesklets->cRotateButtonImage) != 0
865 	|| g_strcmp0 (pPrevDesklets->cRetachButtonImage, pDesklets->cRetachButtonImage) != 0
866 	|| g_strcmp0 (pPrevDesklets->cDepthRotateButtonImage, pDesklets->cDepthRotateButtonImage) != 0
867 	|| g_strcmp0 (pPrevDesklets->cNoInputButtonImage, pDesklets->cNoInputButtonImage) != 0)
868 	{
869 		_unload_desklet_buttons ();
870 		_load_desklet_buttons ();
871 	}
872 	if (g_strcmp0 (pPrevDesklets->cDeskletDecorationsName, pDesklets->cDeskletDecorationsName) != 0)  // the default theme has changed -> reload all desklets that use it
873 	{
874 		CairoDesklet *pDesklet;
875 		GList *dl;
876 		for (dl = s_pDeskletList; dl != NULL; dl = dl->next)
877 		{
878 			pDesklet = dl->data;
879 			if (pDesklet->cDecorationTheme == NULL || strcmp (pDesklet->cDecorationTheme, "default") == 0)
880 			{
881 				gldi_desklet_load_desklet_decorations (pDesklet);
882 			}
883 		}
884 	}
885 }
886 
887   //////////////
888  /// UNLOAD ///
889 //////////////
890 
unload(void)891 static void unload (void)
892 {
893 	_unload_desklet_buttons ();
894 }
895 
896   ////////////
897  /// INIT ///
898 ////////////
899 
on_style_changed(G_GNUC_UNUSED gpointer data)900 static gboolean on_style_changed (G_GNUC_UNUSED gpointer data)
901 {
902 	cd_debug ("Desklets: style change to %s", myDeskletsParam.cDeskletDecorationsName);
903 	gboolean bUseDefaultColors = (!myDeskletsParam.cDeskletDecorationsName || strcmp (myDeskletsParam.cDeskletDecorationsName, "automatic") == 0);
904 
905 	CairoDeskletDecoration * pDecoration = cairo_dock_get_desklet_decoration ("automatic");
906 	if (pDecoration)
907 		pDecoration->iLeftMargin = pDecoration->iTopMargin = pDecoration->iRightMargin = pDecoration->iBottomMargin = myStyleParam.iLineWidth;
908 
909 	CairoDesklet *pDesklet;
910 	GList *dl;
911 	for (dl = s_pDeskletList; dl != NULL; dl = dl->next)
912 	{
913 		pDesklet = dl->data;
914 		if ( ((pDesklet->cDecorationTheme == NULL || strcmp (pDesklet->cDecorationTheme, "default") == 0) && bUseDefaultColors)
915 		|| strcmp (pDesklet->cDecorationTheme, "automatic") == 0)
916 		{
917 			cd_debug ("Reload desklet's bg...");
918 			gldi_desklet_load_desklet_decorations (pDesklet);
919 			cairo_dock_redraw_container (CAIRO_CONTAINER (pDesklet));
920 		}
921 	}
922 	return GLDI_NOTIFICATION_LET_PASS;
923 }
924 
init(void)925 static void init (void)
926 {
927 	gldi_object_register_notification (&myDeskletObjectMgr,
928 		NOTIFICATION_UPDATE,
929 		(GldiNotificationFunc) _on_update_desklet_notification,
930 		GLDI_RUN_FIRST, NULL);
931 	gldi_object_register_notification (&myDeskletObjectMgr,
932 		NOTIFICATION_ENTER_DESKLET,
933 		(GldiNotificationFunc) _on_enter_leave_desklet_notification,
934 		GLDI_RUN_FIRST, NULL);
935 	gldi_object_register_notification (&myDeskletObjectMgr,
936 		NOTIFICATION_LEAVE_DESKLET,
937 		(GldiNotificationFunc) _on_enter_leave_desklet_notification,
938 		GLDI_RUN_FIRST, NULL);
939 	gldi_object_register_notification (&myDeskletObjectMgr,
940 		NOTIFICATION_RENDER,
941 		(GldiNotificationFunc) _on_render_desklet_notification,
942 		GLDI_RUN_FIRST, NULL);
943 	gldi_object_register_notification (&myDesktopMgr,
944 		NOTIFICATION_DESKTOP_GEOMETRY_CHANGED,
945 		(GldiNotificationFunc) _on_desktop_geometry_changed,
946 		GLDI_RUN_AFTER, NULL);  // replace all desklets that are positionned relatively to the right or bottom edge
947 	gldi_object_register_notification (&myStyleMgr,
948 		NOTIFICATION_STYLE_CHANGED,
949 		(GldiNotificationFunc) on_style_changed,
950 		GLDI_RUN_AFTER, NULL);
951 	s_iStartupTime = time (NULL);  // on startup, the WM can take a long time before it has positionned all the desklets. To avoid irrelevant configure events, we set a delay.
952 }
953 
954   ///////////////
955  /// MANAGER ///
956 ///////////////
957 
init_object(GldiObject * obj,gpointer attr)958 static void init_object (GldiObject *obj, gpointer attr)
959 {
960 	CairoDesklet *pDesklet = (CairoDesklet*)obj;
961 	CairoDeskletAttr *pAttributes = (CairoDeskletAttr*)attr;
962 	g_return_if_fail (pAttributes->pIcon != NULL);
963 
964 	gldi_desklet_init_internals (pDesklet);
965 
966 	// attach the main icon
967 	Icon *pIcon = pAttributes->pIcon;
968 	pDesklet->pIcon = pIcon;
969 	cairo_dock_set_icon_container (pIcon, pDesklet);
970 	if (CAIRO_DOCK_IS_APPLET (pIcon))
971 		gtk_window_set_title (GTK_WINDOW (pDesklet->container.pWidget), pIcon->pModuleInstance->pModule->pVisitCard->cModuleName);
972 
973 	// configure the desklet
974 	gldi_desklet_configure (pDesklet, pAttributes);
975 
976 	// load buttons images
977 	if (s_pRotateButtonBuffer.pSurface == NULL)
978 	{
979 		_load_desklet_buttons ();
980 	}
981 
982 	// register the new desklet
983 	s_pDeskletList = g_list_prepend (s_pDeskletList, pDesklet);
984 
985 	// start the appearance animation
986 	if (! cairo_dock_is_loading ())
987 	{
988 		pDesklet->container.fRatio = 0.1;
989 		pDesklet->bGrowingUp = TRUE;
990 		cairo_dock_launch_animation (CAIRO_CONTAINER (pDesklet));
991 	}
992 }
993 
reset_object(GldiObject * obj)994 static void reset_object (GldiObject *obj)
995 {
996 	CairoDesklet *pDesklet = (CairoDesklet*)obj;
997 
998 	// stop timers
999 	if (pDesklet->iSidWriteSize != 0)
1000 		g_source_remove (pDesklet->iSidWriteSize);
1001 	if (pDesklet->iSidWritePosition != 0)
1002 		g_source_remove (pDesklet->iSidWritePosition);
1003 
1004 	// detach the main icon
1005 	Icon *pIcon = pDesklet->pIcon;
1006 	if (pIcon != NULL)
1007 	{
1008 		if (pIcon->pContainer != NULL && pIcon->pContainer != CAIRO_CONTAINER (pDesklet))  // shouldn't happen
1009 			cd_warning ("This icon (%s) has not been detached from its desklet properly !", pIcon->cName);
1010 		else
1011 			cairo_dock_set_icon_container (pIcon, NULL);
1012 	}
1013 
1014 	// detach the interactive widget
1015 	gldi_desklet_steal_interactive_widget (pDesklet);
1016 
1017 	// free sub-icons
1018 	if (pDesklet->icons != NULL)
1019 	{
1020 		GList *icons = pDesklet->icons;
1021 		pDesklet->icons = NULL;
1022 		g_list_foreach (icons, (GFunc) gldi_object_unref, NULL);
1023 		g_list_free (icons);
1024 	}
1025 
1026 	// free data
1027 	if (pDesklet->pRenderer != NULL)
1028 	{
1029 		if (pDesklet->pRenderer->free_data != NULL)
1030 		{
1031 			pDesklet->pRenderer->free_data (pDesklet);
1032 			pDesklet->pRendererData = NULL;
1033 		}
1034 	}
1035 
1036 	g_free (pDesklet->cDecorationTheme);
1037 	gldi_desklet_decoration_free (pDesklet->pUserDecoration);
1038 
1039 	cairo_dock_unload_image_buffer (&pDesklet->backGroundImageBuffer);
1040 	cairo_dock_unload_image_buffer (&pDesklet->foreGroundImageBuffer);
1041 
1042 	// unregister the desklet
1043 	s_pDeskletList = g_list_remove (s_pDeskletList, pDesklet);
1044 }
1045 
gldi_register_desklets_manager(void)1046 void gldi_register_desklets_manager (void)
1047 {
1048 	// Manager
1049 	memset (&myDeskletsMgr, 0, sizeof (GldiManager));
1050 	gldi_object_init (GLDI_OBJECT(&myDeskletsMgr), &myManagerObjectMgr, NULL);
1051 	myDeskletsMgr.cModuleName  = "Desklets";
1052 	// interface
1053 	myDeskletsMgr.init         = init;
1054 	myDeskletsMgr.load         = NULL;  // data are loaded the first time a desklet is created, to avoid create them for nothing.
1055 	myDeskletsMgr.unload       = unload;
1056 	myDeskletsMgr.reload       = (GldiManagerReloadFunc)reload;
1057 	myDeskletsMgr.get_config   = (GldiManagerGetConfigFunc)get_config;
1058 	myDeskletsMgr.reset_config = (GldiManagerResetConfigFunc)reset_config;
1059 	// Config
1060 	memset (&myDeskletsParam, 0, sizeof (CairoDeskletsParam));
1061 	myDeskletsMgr.pConfig = (GldiManagerConfigPtr)&myDeskletsParam;
1062 	myDeskletsMgr.iSizeOfConfig = sizeof (CairoDeskletsParam);
1063 	// data
1064 	memset (&s_pRotateButtonBuffer, 0, sizeof (CairoDockImageBuffer));
1065 	memset (&s_pRetachButtonBuffer, 0, sizeof (CairoDockImageBuffer));
1066 	memset (&s_pDepthRotateButtonBuffer, 0, sizeof (CairoDockImageBuffer));
1067 	memset (&s_pNoInputButtonBuffer, 0, sizeof (CairoDockImageBuffer));
1068 	myDeskletsMgr.iSizeOfData = 0;
1069 	myDeskletsMgr.pData = (GldiManagerDataPtr)NULL;
1070 
1071 	// Object Manager
1072 	memset (&myDeskletObjectMgr, 0, sizeof (GldiObjectManager));
1073 	myDeskletObjectMgr.cName        = "Desklet";
1074 	myDeskletObjectMgr.iObjectSize  = sizeof (CairoDesklet);
1075 	// interface
1076 	myDeskletObjectMgr.init_object  = init_object;
1077 	myDeskletObjectMgr.reset_object = reset_object;
1078 	// signals
1079 	gldi_object_install_notifications (&myDeskletObjectMgr, NB_NOTIFICATIONS_DESKLET);
1080 	// parent object
1081 	gldi_object_set_manager (GLDI_OBJECT (&myDeskletObjectMgr), &myContainerObjectMgr);
1082 }
1083