1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail    : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23 
24 #include "gldi-config.h"
25 #include "cairo-dock-log.h"
26 #include "cairo-dock-backends-manager.h"
27 #include "cairo-dock-draw-opengl.h"
28 #include "cairo-dock-opengl-font.h"
29 #include "cairo-dock-animations.h"
30 #include "cairo-dock-desklet-manager.h"  // CAIRO_CONTAINER_IS_OPENGL
31 #include "cairo-dock-dock-manager.h"  // CAIRO_CONTAINER_IS_OPENGL
32 #include "cairo-dock-surface-factory.h"
33 #include "cairo-dock-draw.h"
34 #include "cairo-dock-container.h"
35 #include "cairo-dock-icon-factory.h"
36 #include "cairo-dock-icon-facility.h"
37 #include "cairo-dock-icon-manager.h"  // myIconsParam, NOTIFICATION_UPDATE_ICON_SLOW
38 #include "cairo-dock-image-buffer.h"
39 #include "cairo-dock-keyfile-utilities.h"
40 #include "cairo-dock-packages.h"
41 #include "cairo-dock-overlay.h"
42 #include "cairo-dock-gauge.h"
43 #include "cairo-dock-graph.h"
44 #include "cairo-dock-progressbar.h"
45 #include "cairo-dock-data-renderer.h"
46 
47 extern gboolean g_bUseOpenGL;
48 
49 #define cairo_dock_set_data_renderer_on_icon(pIcon, pRenderer) (pIcon)->pDataRenderer = pRenderer
50 #define CD_MIN_TEXT_WITH 24
51 
_cairo_dock_init_data_renderer(CairoDataRenderer * pRenderer,CairoDataRendererAttribute * pAttribute)52 static void _cairo_dock_init_data_renderer (CairoDataRenderer *pRenderer, CairoDataRendererAttribute *pAttribute)
53 {
54 	//\_______________ On alloue la structure des donnees.
55 	pRenderer->data.iNbValues = MAX (1, pAttribute->iNbValues);
56 	pRenderer->data.iMemorySize = MAX (2, pAttribute->iMemorySize);  // au moins la derniere valeur et la nouvelle.
57 	pRenderer->data.pValuesBuffer = g_new0 (gdouble, pRenderer->data.iNbValues * pRenderer->data.iMemorySize);
58 	pRenderer->data.pTabValues = g_new (gdouble *, pRenderer->data.iMemorySize);
59 	int i;
60 	for (i = 0; i < pRenderer->data.iMemorySize; i ++)
61 	{
62 		pRenderer->data.pTabValues[i] = &pRenderer->data.pValuesBuffer[i*pRenderer->data.iNbValues];
63 	}
64 	pRenderer->data.iCurrentIndex = -1;
65 	pRenderer->data.pMinMaxValues = g_new (gdouble, 2 * pRenderer->data.iNbValues);
66 	if (pAttribute->pMinMaxValues != NULL)
67 	{
68 		memcpy (pRenderer->data.pMinMaxValues, pAttribute->pMinMaxValues, 2 * pRenderer->data.iNbValues * sizeof (gdouble));
69 	}
70 	else
71 	{
72 		if (pAttribute->bUpdateMinMax)
73 		{
74 			for (i = 0; i < pRenderer->data.iNbValues; i ++)
75 			{
76 				pRenderer->data.pMinMaxValues[2*i] = 1.e6;
77 				pRenderer->data.pMinMaxValues[2*i+1] = -1.e6;
78 			}
79 		}
80 		else
81 		{
82 			for (i = 0; i < pRenderer->data.iNbValues; i ++)
83 			{
84 				pRenderer->data.pMinMaxValues[2*i] = 0.;
85 				pRenderer->data.pMinMaxValues[2*i+1] = 1.;
86 			}
87 		}
88 	}
89 
90 	if (pAttribute->cEmblems != NULL)
91 	{
92 		pRenderer->pEmblems = g_new0 (CairoDataRendererEmblem, pRenderer->data.iNbValues);
93 		int i;
94 		for (i = 0; i < pRenderer->data.iNbValues; i ++)
95 		{
96 			pRenderer->pEmblems[i].cImagePath = g_strdup (pAttribute->cEmblems[i]);
97 			pRenderer->pEmblems[i].param.fAlpha = 1.;
98 		}
99 	}
100 	if (pAttribute->cLabels != NULL)
101 	{
102 		pRenderer->pLabels = g_new0 (CairoDataRendererText, pRenderer->data.iNbValues);
103 		int i;
104 		for (i = 0; i < pRenderer->data.iNbValues; i ++)
105 		{
106 			pRenderer->pLabels[i].cText = g_strdup (pAttribute->cLabels[i]);
107 			pRenderer->pLabels[i].param.pColor[3] = 1.;
108 		}
109 	}
110 	pRenderer->pValuesText = g_new0 (CairoDataRendererTextParam, pRenderer->data.iNbValues);
111 
112 	//\_______________ On charge les parametres generaux.
113 	pRenderer->bUpdateMinMax = pAttribute->bUpdateMinMax;
114 	pRenderer->bWriteValues = pAttribute->bWriteValues;
115 	pRenderer->iRotateTheme = pAttribute->iRotateTheme;
116 	pRenderer->iLatencyTime = pAttribute->iLatencyTime;
117 	pRenderer->iSmoothAnimationStep = 0;
118 	pRenderer->format_value = pAttribute->format_value;
119 	pRenderer->pFormatData = pAttribute->pFormatData;
120 }
121 
cairo_data_renderer_get_size(CairoDataRenderer * pRenderer,gint * iWidth,gint * iHeight)122 void cairo_data_renderer_get_size (CairoDataRenderer *pRenderer, gint *iWidth, gint *iHeight)
123 {
124 	if (pRenderer->bisRotate)
125 	{
126 		*iWidth = pRenderer->iHeight;
127 		*iHeight = pRenderer->iWidth;
128 	}
129 	else
130 	{
131 		*iWidth = pRenderer->iWidth;
132 		*iHeight = pRenderer->iHeight;
133 	}
134 }
135 
136 
cairo_dock_render_overlays_to_texture(CairoDataRenderer * pRenderer,int iNumValue)137 void cairo_dock_render_overlays_to_texture (CairoDataRenderer *pRenderer, int iNumValue)
138 {
139 	gint iWidth = pRenderer->iWidth, iHeight = pRenderer->iHeight;
140 	cairo_data_renderer_get_size (pRenderer, &iWidth, &iHeight);
141 	glPushMatrix ();
142 	if (pRenderer->bisRotate)
143 		glRotatef (90., 0., 0., 1.);
144 
145 	if (pRenderer->pEmblems != NULL)
146 	{
147 		_cairo_dock_enable_texture ();
148 		_cairo_dock_set_blend_over ();
149 
150 		CairoDataRendererEmblem *pEmblem;
151 		pEmblem = &pRenderer->pEmblems[iNumValue];
152 		if (pEmblem->iTexture != 0)
153 		{
154 			glBindTexture (GL_TEXTURE_2D, pEmblem->iTexture);
155 			_cairo_dock_set_alpha (pEmblem->param.fAlpha);
156 			_cairo_dock_apply_current_texture_at_size_with_offset (
157 				pEmblem->param.fWidth * iWidth,
158 				pEmblem->param.fHeight * iHeight,
159 				pEmblem->param.fX * iWidth,
160 				pEmblem->param.fY * iHeight);
161 		}
162 		_cairo_dock_disable_texture ();
163 	}
164 
165 	if (pRenderer->pLabels != NULL)
166 	{
167 		_cairo_dock_enable_texture ();
168 		_cairo_dock_set_blend_pbuffer ();  // rend mieux pour les textes
169 
170 		CairoDataRendererText *pLabel;
171 		int w, h, dw, dh;
172 		pLabel = &pRenderer->pLabels[iNumValue];
173 		if (pLabel->iTexture != 0)
174 		{
175 			double f = MIN (pLabel->param.fWidth * iWidth / pLabel->iTextWidth, pLabel->param.fHeight * iHeight / pLabel->iTextHeight);  // on garde le ratio du texte.
176 			w = pLabel->iTextWidth * f;
177 			h = pLabel->iTextHeight * f;
178 			dw = w & 1;
179 			dh = h & 1;
180 
181 			glBindTexture (GL_TEXTURE_2D, pLabel->iTexture);
182 			_cairo_dock_set_alpha (pLabel->param.pColor[3]);
183 			_cairo_dock_apply_current_texture_at_size_with_offset (
184 				w + dw,
185 				h + dh,
186 				pLabel->param.fX * iWidth,
187 				pLabel->param.fY * iHeight);
188 		}
189 		_cairo_dock_disable_texture ();
190 	}
191 
192 	if (pRenderer->bWriteValues && pRenderer->bCanRenderValueAsText)
193 	{
194 		CairoDataRendererTextParam *pText;
195 		pText = &pRenderer->pValuesText[iNumValue];
196 		if (pText->fWidth != 0 && pText->fHeight != 0)
197 		{
198 			cairo_data_renderer_format_value (pRenderer, iNumValue);
199 
200 			CairoDockGLFont *pFont = cairo_dock_get_default_data_renderer_font ();
201 			glColor3f (pText->pColor[0], pText->pColor[1], pText->pColor[2]);
202 			glPushMatrix ();
203 
204 			int w = pText->fWidth * pRenderer->iWidth;
205 			int h = pText->fHeight * pRenderer->iHeight;
206 			int dw = w & 1;
207 			int dh = h & 1;
208 			cairo_dock_draw_gl_text_at_position_in_area ((guchar *) pRenderer->cFormatBuffer,
209 				pFont,
210 				floor (pText->fX * iWidth) + .5*dw,
211 				floor (pText->fY * iHeight) + .5*dh,
212 				w,
213 				h,
214 				TRUE);
215 
216 			glPopMatrix ();
217 			glColor3f (1.0, 1.0, 1.0);
218 		}
219 	}
220 	glPopMatrix ();
221 }
222 
223 
cairo_dock_render_overlays_to_context(CairoDataRenderer * pRenderer,int iNumValue,cairo_t * pCairoContext)224 void cairo_dock_render_overlays_to_context (CairoDataRenderer *pRenderer, int iNumValue, cairo_t *pCairoContext)
225 {
226 	if (pRenderer->pEmblems != NULL)
227 	{
228 		CairoDataRendererEmblem *pEmblem;
229 		pEmblem = &pRenderer->pEmblems[iNumValue];
230 		if (pEmblem->pSurface != NULL)
231 		{
232 			cairo_set_source_surface (pCairoContext,
233 				pEmblem->pSurface,
234 				(.5 + pEmblem->param.fX - pEmblem->param.fWidth/2) * pRenderer->iWidth,
235 				(.5 - pEmblem->param.fY - pEmblem->param.fHeight/2) * pRenderer->iHeight);
236 			cairo_paint_with_alpha (pCairoContext, pEmblem->param.fAlpha);
237 		}
238 	}
239 
240 	if (pRenderer->pLabels != NULL)
241 	{
242 		CairoDataRendererText *pLabel;
243 		pLabel = &pRenderer->pLabels[iNumValue];
244 		if (pLabel->pSurface != NULL)
245 		{
246 			double f = MIN (pLabel->param.fWidth * pRenderer->iWidth / pLabel->iTextWidth, pLabel->param.fHeight * pRenderer->iHeight / pLabel->iTextHeight);  // on garde le ratio du texte.
247 			if (pLabel->iTextHeight * f > 7)  // sinon illisible
248 			{
249 				cairo_save (pCairoContext);
250 				cairo_scale (pCairoContext,
251 					f,
252 					f);
253 				cairo_set_source_surface (pCairoContext,
254 					pLabel->pSurface,
255 					.5+floor ((.5 + pLabel->param.fX) * pRenderer->iWidth/f - pLabel->iTextWidth /2),
256 					.5+floor ((.5 - pLabel->param.fY) * pRenderer->iHeight/f - pLabel->iTextHeight /2));
257 				cairo_paint_with_alpha (pCairoContext, pLabel->param.pColor[3]);
258 				cairo_restore (pCairoContext);
259 			}
260 		}
261 	}
262 
263 	if (pRenderer->bWriteValues && pRenderer->bCanRenderValueAsText)
264 	{
265 		CairoDataRendererTextParam *pText;
266 		pText = &pRenderer->pValuesText[iNumValue];
267 		if (pText->fWidth != 0 && pText->fHeight != 0)
268 		{
269 			cairo_data_renderer_format_value (pRenderer, iNumValue);
270 
271 			cairo_save (pCairoContext);
272 			cairo_set_source_rgb (pCairoContext, pText->pColor[0], pText->pColor[1], pText->pColor[2]);
273 
274 			PangoLayout *pLayout = pango_cairo_create_layout (pCairoContext);
275 			PangoFontDescription *fd = pango_font_description_from_string ("Monospace 12");
276 			pango_layout_set_font_description (pLayout, fd);
277 
278 			PangoRectangle log;
279 			pango_layout_set_text (pLayout, pRenderer->cFormatBuffer, -1);
280 			pango_layout_get_pixel_extents (pLayout, NULL, &log);
281 			double fZoom = MIN (pText->fWidth * pRenderer->iWidth / (log.width), pText->fHeight * pRenderer->iHeight / log.height);
282 
283 			cairo_move_to (pCairoContext,
284 				floor ((.5 + pText->fX) * pRenderer->iWidth - log.width*fZoom/2),
285 				floor ((.5 - pText->fY) * pRenderer->iHeight - log.height*fZoom/2));
286 			cairo_scale (pCairoContext,
287 				fZoom,
288 				fZoom);
289 			pango_cairo_show_layout (pCairoContext, pLayout);
290 			g_object_unref (pLayout);
291 			cairo_restore (pCairoContext);
292 		}
293 	}
294 }
295 
296 
_cairo_dock_render_to_context(CairoDataRenderer * pRenderer,Icon * pIcon,GldiContainer * pContainer,cairo_t * pCairoContext)297 static void _cairo_dock_render_to_context (CairoDataRenderer *pRenderer, Icon *pIcon, GldiContainer *pContainer, cairo_t *pCairoContext)
298 {
299 	cairo_t *ctx = NULL;
300 	if (pRenderer->bUseOverlay && pRenderer->pOverlay != NULL)
301 	{
302 		CairoDataToRenderer *pData = cairo_data_renderer_get_data (pRenderer);
303 		if (! pData->bHasValue)  // if no value has been set yet, it's better to not draw anything, since the icon already has an image (we draw on an overlay).
304 			return;
305 		ctx = cairo_dock_begin_draw_image_buffer_cairo (&pRenderer->pOverlay->image, 0, NULL);
306 		pCairoContext = ctx;
307 	}
308 	else
309 	{
310 		ctx = cairo_dock_begin_draw_icon_cairo (pIcon, 0, pCairoContext);
311 		pCairoContext = ctx;
312 	}
313 	g_return_if_fail (pCairoContext != NULL);
314 
315 	//\________________ On dessine.
316 	cairo_save (pCairoContext);
317 	if ((pRenderer->iRotateTheme == CD_RENDERER_ROTATE_WITH_CONTAINER && pContainer->bIsHorizontal == CAIRO_DOCK_VERTICAL) || pRenderer->iRotateTheme == CD_RENDERER_ROTATE_YES)
318 	{
319 		//cairo_translate (pCairoContext, pRenderer->iWidth/2, pRenderer->iHeight/2);
320 		cairo_rotate (pCairoContext, G_PI/2);
321 		pRenderer->bisRotate = TRUE;
322 		//cairo_translate (pCairoContext, -pRenderer->iHeight/2, -pRenderer->iWidth/2);
323 	}
324 
325 	//cairo_save (pCairoContext);
326 	pRenderer->interface.render (pRenderer, pCairoContext);
327 	//cairo_restore (pCairoContext);
328 
329 	//\________________ On dessine les overlays.
330 	/**int iNbValues = cairo_data_renderer_get_nb_values (pRenderer);
331 	int i;
332 	for (i = 0; i < iNbValues; i ++)
333 	{
334 		cairo_dock_render_overlays_to_context (pRenderer, i, pCairoContext);
335 	}*/
336 	cairo_restore (pCairoContext);
337 
338 	if (pRenderer->bUseOverlay && pRenderer->pOverlay != NULL)
339 		cairo_dock_end_draw_image_buffer_cairo (&pRenderer->pOverlay->image);
340 	else
341 		cairo_dock_end_draw_image_buffer_cairo (&pIcon->image);
342 	/**if (CAIRO_DOCK_CONTAINER_IS_OPENGL (pContainer))
343 	{
344 		if (pRenderer->bUseOverlay)
345 			pRenderer->pOverlay->image.iTexture = cairo_dock_create_texture_from_surface (pRenderer->pOverlay->image.pSurface);
346 		else
347 			cairo_dock_update_icon_texture (pIcon);
348 	}*/
349 
350 	if (ctx != pCairoContext)
351 		cairo_destroy (ctx);
352 }
353 
_cairo_dock_render_to_texture(CairoDataRenderer * pRenderer,Icon * pIcon,GldiContainer * pContainer)354 static void _cairo_dock_render_to_texture (CairoDataRenderer *pRenderer, Icon *pIcon, GldiContainer *pContainer)
355 {
356 	if (pRenderer->bUseOverlay)
357 	{
358 		CairoDataToRenderer *pData = cairo_data_renderer_get_data (pRenderer);
359 		if (! pData->bHasValue)  // if no value has been set yet, it's better to not draw anything, since the icon already has an image (we draw on an overlay).
360 			return;
361 		if (! cairo_dock_begin_draw_image_buffer_opengl (&pRenderer->pOverlay->image, pContainer, 0))
362 		{
363 			pIcon->bDamaged = TRUE;  // damage the icon so that it (and therefore its dada-renderer) will be redrawn.
364 			return ;
365 		}
366 	}
367 	else
368 	{
369 		if (! cairo_dock_begin_draw_icon (pIcon, 0))
370 			return ;
371 	}
372 
373 	//\________________ On dessine.
374 	glPushMatrix ();
375 	if ((pRenderer->iRotateTheme == CD_RENDERER_ROTATE_WITH_CONTAINER && pContainer->bIsHorizontal == CAIRO_DOCK_VERTICAL) || pRenderer->iRotateTheme == CD_RENDERER_ROTATE_YES)
376 	{
377 		glRotatef (-90., 0., 0., 1.);
378 		pRenderer->bisRotate = TRUE;
379 	}
380 
381 	//glPushMatrix ();
382 	pRenderer->interface.render_opengl (pRenderer);
383 	//glPopMatrix ();
384 
385 	//\________________ On dessine les overlays.
386 	/**int iNbValues = cairo_data_renderer_get_nb_values (pRenderer);
387 	int i;
388 	for (i = 0; i < iNbValues; i ++)
389 	{
390 		cairo_dock_render_overlays_to_texture (pRenderer, i);
391 	}*/
392 	glPopMatrix ();
393 
394 	if (pRenderer->bUseOverlay)
395 	{
396 		cairo_dock_end_draw_image_buffer_opengl (&pRenderer->pOverlay->image, pContainer);
397 	}
398 	else
399 	{
400 		cairo_dock_end_draw_icon (pIcon);
401 	}
402 }
403 
_refresh(CairoDataRenderer * pRenderer,Icon * pIcon,GldiContainer * pContainer)404 static inline void _refresh (CairoDataRenderer *pRenderer, Icon *pIcon, GldiContainer *pContainer)
405 {
406 	if (CAIRO_DOCK_CONTAINER_IS_OPENGL (pContainer) && pRenderer->interface.render_opengl)
407 	{
408 		_cairo_dock_render_to_texture (pRenderer, pIcon, pContainer);
409 	}
410 	else
411 	{
412 		_cairo_dock_render_to_context (pRenderer, pIcon, pContainer, NULL);
413 	}
414 }
415 
cairo_dock_update_icon_data_renderer_notification(G_GNUC_UNUSED gpointer pUserData,Icon * pIcon,GldiContainer * pContainer,gboolean * bContinueAnimation)416 static gboolean cairo_dock_update_icon_data_renderer_notification (G_GNUC_UNUSED gpointer pUserData, Icon *pIcon, GldiContainer *pContainer, gboolean *bContinueAnimation)
417 {
418 	CairoDataRenderer *pRenderer = cairo_dock_get_icon_data_renderer (pIcon);
419 	if (pRenderer == NULL)
420 		return GLDI_NOTIFICATION_LET_PASS;
421 
422 	if (pRenderer->iSmoothAnimationStep > 0)
423 	{
424 		pRenderer->iSmoothAnimationStep --;
425 		int iDeltaT = cairo_dock_get_slow_animation_delta_t (pContainer);
426 		int iNbIterations = pRenderer->iLatencyTime / iDeltaT;
427 
428 		pRenderer->fLatency = (double) pRenderer->iSmoothAnimationStep / iNbIterations;
429 		_cairo_dock_render_to_texture (pRenderer, pIcon, pContainer);
430 		cairo_dock_redraw_icon (pIcon);
431 
432 		if (pRenderer->iSmoothAnimationStep < iNbIterations)
433 			*bContinueAnimation = TRUE;
434 	}
435 
436 	return GLDI_NOTIFICATION_LET_PASS;
437 }
438 
_cairo_dock_finish_load_data_renderer(CairoDataRenderer * pRenderer,gboolean bLoadTextures,Icon * pIcon)439 static void _cairo_dock_finish_load_data_renderer (CairoDataRenderer *pRenderer, gboolean bLoadTextures, Icon *pIcon)
440 {
441 	int iNbValues = cairo_data_renderer_get_nb_values (pRenderer);
442 	//\___________________ On charge les emblemes si l'implementation les a valides.
443 	if (pRenderer->pEmblems != NULL)
444 	{
445 		CairoDataRendererEmblem *pEmblem;
446 		cairo_surface_t *pSurface;
447 		int i;
448 		for (i = 0; i < iNbValues; i ++)
449 		{
450 			pEmblem = &pRenderer->pEmblems[i];
451 			if (pEmblem->pSurface != NULL)
452 			{
453 				cairo_surface_destroy (pEmblem->pSurface);
454 				pEmblem->pSurface = NULL;
455 			}
456 			if (pEmblem->iTexture != 0)
457 			{
458 				_cairo_dock_delete_texture (pEmblem->iTexture);
459 				pEmblem->iTexture = 0;
460 			}
461 			if (pEmblem->param.fWidth != 0 && pEmblem->param.fHeight != 0 && pEmblem->cImagePath != NULL)
462 			{
463 				pSurface = cairo_dock_create_surface_from_image_simple (pEmblem->cImagePath,
464 					pEmblem->param.fWidth * pRenderer->iWidth,
465 					pEmblem->param.fHeight * pRenderer->iHeight);
466 				if (bLoadTextures)
467 				{
468 					pEmblem->iTexture = cairo_dock_create_texture_from_surface (pSurface);
469 					cairo_surface_destroy (pSurface);
470 				}
471 				else
472 					pEmblem->pSurface = pSurface;
473 			}
474 		}
475 	}
476 
477 	//\___________________ On charge les labels si l'implementation les a valides.
478 	if (pRenderer->pLabels != NULL)
479 	{
480 		GldiTextDescription textDescription;
481 		gldi_text_description_copy (&textDescription, &myIconsParam.quickInfoTextDescription);
482 
483 		CairoDataRendererText *pLabel;
484 		cairo_surface_t *pSurface;
485 		int i;
486 		for (i = 0; i < iNbValues; i ++)
487 		{
488 			pLabel = &pRenderer->pLabels[i];
489 			if (pLabel->pSurface != NULL)
490 			{
491 				cairo_surface_destroy (pLabel->pSurface);
492 				pLabel->pSurface = NULL;
493 			}
494 			if (pLabel->iTexture != 0)
495 			{
496 				_cairo_dock_delete_texture (pLabel->iTexture);
497 				pLabel->iTexture = 0;
498 			}
499 			if (pLabel->param.fWidth != 0 && pLabel->param.fHeight != 0 && pLabel->cText != NULL)
500 			{
501 				textDescription.bNoDecorations = TRUE;
502 				textDescription.bUseDefaultColors = FALSE;
503 				textDescription.iMargin = 0;
504 				textDescription.bOutlined = TRUE;  /// tester avec et sans ...
505 				textDescription.fColorStart.rgba.red = pLabel->param.pColor[0];
506 				textDescription.fColorStart.rgba.green = pLabel->param.pColor[1];
507 				textDescription.fColorStart.rgba.blue = pLabel->param.pColor[2];
508 				textDescription.fColorStart.rgba.alpha = 1.;
509 				pSurface = cairo_dock_create_surface_from_text (pLabel->cText,
510 					&textDescription,
511 					&pLabel->iTextWidth, &pLabel->iTextHeight);
512 				if (bLoadTextures)
513 				{
514 					pLabel->iTexture = cairo_dock_create_texture_from_surface (pSurface);
515 					cairo_surface_destroy (pSurface);
516 				}
517 				else
518 					pLabel->pSurface = pSurface;
519 			}
520 		}
521 	}
522 
523 	//\___________________ On regarde si le texte dessine sur l'icone sera suffisamment lisible.
524 	if (pRenderer->pValuesText != NULL)
525 	{
526 		CairoDataRendererTextParam *pText = &pRenderer->pValuesText[0];
527 		//g_print ("+++++++pText->fWidth * pRenderer->iWidth : %.2f\n", pText->fWidth * pRenderer->iWidth);
528 		pRenderer->bCanRenderValueAsText = (pText->fWidth * pRenderer->iWidth >= CD_MIN_TEXT_WITH);
529 	}
530 
531 	if (pRenderer->bCanRenderValueAsText && pRenderer->bWriteValues)
532 		gldi_icon_set_quick_info (pIcon, NULL);
533 
534 	//\___________________ Build an overlay if the renderer will use some.
535 	if (pRenderer->bUseOverlay)
536 	{
537 		//g_print ("+ overlay %dx%d\n", pRenderer->iWidth, pRenderer->iHeight);
538 		cairo_surface_t *pSurface = cairo_dock_create_blank_surface (pRenderer->iWidth, pRenderer->iHeight);
539 		pRenderer->pOverlay = cairo_dock_add_overlay_from_surface (pIcon, pSurface, pRenderer->iWidth, pRenderer->iHeight, pRenderer->iOverlayPosition, (gpointer)"data-renderer");  // this string is constant; any previous overlay will be removed.
540 		cairo_dock_set_overlay_scale (pRenderer->pOverlay, 0);  // keep the original size of the image
541 	}
542 }
543 
cairo_dock_add_new_data_renderer_on_icon(Icon * pIcon,GldiContainer * pContainer,CairoDataRendererAttribute * pAttribute)544 void cairo_dock_add_new_data_renderer_on_icon (Icon *pIcon, GldiContainer *pContainer, CairoDataRendererAttribute *pAttribute)
545 {
546 	//\___________________ if a previous renderer exists, keep its data alive.
547 	CairoDataToRenderer *pData = NULL;
548 	CairoDataRenderer *pRenderer = cairo_dock_get_icon_data_renderer (pIcon);
549 	//g_print ("%s (%s, %p)\n", __func__, pIcon->cName, pRenderer);
550 	if (pRenderer != NULL)
551 	{
552 		//\_____________ save the current data.
553 		pAttribute->iNbValues = MAX (1, pAttribute->iNbValues);
554 		if (pRenderer && cairo_data_renderer_get_nb_values (pRenderer) == pAttribute->iNbValues)
555 		{
556 			pData = g_memdup (&pRenderer->data, sizeof (CairoDataToRenderer));
557 			memset (&pRenderer->data, 0, sizeof (CairoDataToRenderer));
558 
559 			pAttribute->iMemorySize = MAX (2, pAttribute->iMemorySize);
560 			if (pData->iMemorySize != pAttribute->iMemorySize)  // on redimensionne le tampon des valeurs.
561 			{
562 				int iOldMemorySize = pData->iMemorySize;
563 				pData->iMemorySize = pAttribute->iMemorySize;
564 				pData->pValuesBuffer = g_realloc (pData->pValuesBuffer, pData->iMemorySize * pData->iNbValues * sizeof (gdouble));
565 				if (pData->iMemorySize > iOldMemorySize)
566 				{
567 					memset (&pData->pValuesBuffer[iOldMemorySize * pData->iNbValues], 0, (pData->iMemorySize - iOldMemorySize) * pData->iNbValues * sizeof (gdouble));
568 				}
569 
570 				g_free (pData->pTabValues);
571 				pData->pTabValues = g_new (gdouble *, pData->iMemorySize);
572 				int i;
573 				for (i = 0; i < pData->iMemorySize; i ++)
574 				{
575 					pData->pTabValues[i] = &pData->pValuesBuffer[i*pData->iNbValues];
576 				}
577 				if (pData->iCurrentIndex >= pData->iMemorySize)
578 					pData->iCurrentIndex = pData->iMemorySize - 1;
579 			}
580 		}
581 
582 		//\_____________ remove the current data-renderer
583 		cairo_dock_remove_data_renderer_on_icon (pIcon);
584 	}
585 
586 	//\___________________ add a new data-renderer.
587 	pRenderer = cairo_dock_new_data_renderer (pAttribute->cModelName);
588 
589 	cairo_dock_set_data_renderer_on_icon (pIcon, pRenderer);
590 	if (pRenderer == NULL)
591 		return ;
592 
593 	//\___________________ load it.
594 	_cairo_dock_init_data_renderer (pRenderer, pAttribute);
595 
596 	pRenderer->iWidth = cairo_dock_icon_get_allocated_width (pIcon);  // we don't need the icon to be loaded already, its allocated size is enough
597 	pRenderer->iHeight = cairo_dock_icon_get_allocated_height (pIcon);
598 	///cairo_dock_get_icon_extent (pIcon, &pRenderer->iWidth, &pRenderer->iHeight);
599 
600 	gboolean bLoadTextures = FALSE;
601 	if (CAIRO_DOCK_CONTAINER_IS_OPENGL (pContainer) && pRenderer->interface.render_opengl)
602 	{
603 		bLoadTextures = TRUE;
604 		gldi_object_register_notification (pIcon,
605 			NOTIFICATION_UPDATE_ICON_SLOW,
606 			(GldiNotificationFunc) cairo_dock_update_icon_data_renderer_notification,
607 			GLDI_RUN_AFTER, NULL);  // pour l'affichage fluide.
608 	}
609 
610 	pRenderer->interface.load (pRenderer, pIcon, pAttribute);
611 
612 	//\___________________ On charge les overlays si l'implementation les a valides.
613 	_cairo_dock_finish_load_data_renderer (pRenderer, bLoadTextures, pIcon);
614 
615 	//\_____________ set back the previous data, if any.
616 	if (pData != NULL)
617 	{
618 		memcpy (&pRenderer->data, pData, sizeof (CairoDataToRenderer));
619 		g_free (pData);
620 		_refresh (pRenderer, pIcon, pContainer);
621 	}
622 }
623 
624 
_render_delayed(Icon * pIcon)625 static gboolean _render_delayed (Icon *pIcon)
626 {
627 	CairoDataRenderer *pRenderer = cairo_dock_get_icon_data_renderer (pIcon);
628 	g_return_val_if_fail (pRenderer != NULL, FALSE);
629 
630 	GldiContainer *pContainer = pIcon->pContainer;
631 	if (pContainer)
632 	{
633 		cd_debug ("Render delayed: (%s, %dx%d)", pIcon->cName, pContainer->iWidth, pContainer->iHeight);
634 		if (pContainer->iWidth == 1 && pContainer->iHeight == 1)  // container not yet resized, retry later
635 			return TRUE;
636 
637 		_cairo_dock_render_to_texture (pRenderer, pIcon, pContainer);
638 		cairo_dock_redraw_icon (pIcon);
639 	}
640 
641 	pRenderer->iSidRenderIdle = 0;
642 	return FALSE;
643 }
cairo_dock_render_new_data_on_icon(Icon * pIcon,GldiContainer * pContainer,cairo_t * pCairoContext,double * pNewValues)644 void cairo_dock_render_new_data_on_icon (Icon *pIcon, GldiContainer *pContainer, cairo_t *pCairoContext, double *pNewValues)
645 {
646 	CairoDataRenderer *pRenderer = cairo_dock_get_icon_data_renderer (pIcon);
647 	g_return_if_fail (pRenderer != NULL);
648 
649 	//\___________________ On met a jour les valeurs du renderer.
650 	CairoDataToRenderer *pData = cairo_data_renderer_get_data (pRenderer);
651 	pData->iCurrentIndex ++;
652 	if (pData->iCurrentIndex >= pData->iMemorySize)
653 		pData->iCurrentIndex -= pData->iMemorySize;
654 	double fNewValue;
655 	int i;
656 	for (i = 0; i < pData->iNbValues; i ++)
657 	{
658 		fNewValue = pNewValues[i];
659 		if (pRenderer->bUpdateMinMax && fNewValue > CAIRO_DATA_RENDERER_UNDEF_VALUE + 1)
660 		{
661 			if (fNewValue < pData->pMinMaxValues[2*i])
662 				pData->pMinMaxValues[2*i] = fNewValue;
663 			if (fNewValue > pData->pMinMaxValues[2*i+1])
664 				pData->pMinMaxValues[2*i+1] = MAX (fNewValue, pData->pMinMaxValues[2*i]+.1);
665 		}
666 		pData->pTabValues[pData->iCurrentIndex][i] = fNewValue;
667 	}
668 	pData->bHasValue = TRUE;
669 
670 	//\___________________ On met a jour le dessin de l'icone.
671 	if (CAIRO_DOCK_CONTAINER_IS_OPENGL (pContainer) && pRenderer->interface.render_opengl)
672 	{
673 		if (pRenderer->iLatencyTime > 0 && pData->bHasValue)
674 		{
675 			int iDeltaT = cairo_dock_get_slow_animation_delta_t (pContainer);
676 			int iNbIterations = MAX (1, pRenderer->iLatencyTime / iDeltaT);
677 			pRenderer->iSmoothAnimationStep = iNbIterations;
678 			cairo_dock_launch_animation (pContainer);
679 		}
680 		else
681 		{
682 			pRenderer->fLatency = 0;
683 			if (pContainer->iWidth == 1 && pContainer->iHeight == 1 && gldi_container_is_visible (pContainer))  // container not yet resized, delay the rendering (OpenGL only).
684 			{
685 				if (pRenderer->iSidRenderIdle == 0)
686 					pRenderer->iSidRenderIdle = g_timeout_add (250, (GSourceFunc)_render_delayed, pIcon);  // if pIcon is freed, the data-renderer will be freed too, so this signal will vanish. avoid using 'g_idle_add', it is heavy on CPU; a 250ms delay won't be noticeable.
687 			}
688 			else
689 			{
690 				_cairo_dock_render_to_texture (pRenderer, pIcon, pContainer);
691 			}
692 		}
693 	}
694 	else
695 	{
696 		_cairo_dock_render_to_context (pRenderer, pIcon, pContainer, pCairoContext);
697 	}
698 
699 	//\___________________ On met a jour l'info rapide si le renderer n'a pu ecrire les valeurs.
700 	if (! pRenderer->bCanRenderValueAsText && pRenderer->bWriteValues)  // on prend en charge l'ecriture des valeurs.
701 	{
702 		gchar *cBuffer = g_new0 (gchar, pData->iNbValues * (CAIRO_DOCK_DATA_FORMAT_MAX_LEN+1));
703 		char *str = cBuffer;
704 		for (i = 0; i < pData->iNbValues; i ++)
705 		{
706 			cairo_data_renderer_format_value_full (pRenderer, i, str);
707 
708 			if (i+1 < pData->iNbValues)
709 			{
710 				while (*str != '\0')
711 					str ++;
712 				*str = '\n';
713 				str ++;
714 			}
715 		}
716 		gldi_icon_set_quick_info (pIcon, cBuffer);
717 		g_free (cBuffer);
718 	}
719 
720 	cairo_dock_redraw_icon (pIcon);
721 }
722 
723 
724 
cairo_dock_free_data_renderer(CairoDataRenderer * pRenderer)725 void cairo_dock_free_data_renderer (CairoDataRenderer *pRenderer)
726 {
727 	if (pRenderer == NULL)
728 		return ;
729 
730 	if (pRenderer->iSidRenderIdle != 0)
731 		g_source_remove (pRenderer->iSidRenderIdle);
732 
733 	if (pRenderer->interface.unload)
734 		pRenderer->interface.unload (pRenderer);
735 
736 	g_free (pRenderer->data.pValuesBuffer);
737 	g_free (pRenderer->data.pTabValues);
738 	g_free (pRenderer->data.pMinMaxValues);
739 
740 	int iNbValues = cairo_data_renderer_get_nb_values (pRenderer);
741 	if (pRenderer->pEmblems != NULL)
742 	{
743 		CairoDataRendererEmblem *pEmblem;
744 		int i;
745 		for (i = 0; i < iNbValues; i ++)
746 		{
747 			pEmblem = &pRenderer->pEmblems[i];
748 			if (pEmblem->pSurface != NULL)
749 				cairo_surface_destroy (pEmblem->pSurface);
750 			if (pEmblem->iTexture != 0)
751 				_cairo_dock_delete_texture (pEmblem->iTexture);
752 		}
753 		g_free (pRenderer->pEmblems);
754 	}
755 
756 	if (pRenderer->pLabels != NULL)
757 	{
758 		CairoDataRendererText *pText;
759 		int i;
760 		for (i = 0; i < iNbValues; i ++)
761 		{
762 			pText = &pRenderer->pLabels[i];
763 			if (pText->pSurface != NULL)
764 				cairo_surface_destroy (pText->pSurface);
765 			if (pText->iTexture != 0)
766 				_cairo_dock_delete_texture (pText->iTexture);
767 		}
768 		g_free (pRenderer->pLabels);
769 	}
770 
771 	g_free (pRenderer->pValuesText);
772 
773 	gldi_object_unref (GLDI_OBJECT(pRenderer->pOverlay));
774 
775 	g_free (pRenderer);
776 }
777 
cairo_dock_remove_data_renderer_on_icon(Icon * pIcon)778 void cairo_dock_remove_data_renderer_on_icon (Icon *pIcon)
779 {
780 	CairoDataRenderer *pRenderer = cairo_dock_get_icon_data_renderer (pIcon);
781 	if (pRenderer != NULL)
782 	{
783 		gldi_object_remove_notification (pIcon, NOTIFICATION_UPDATE_ICON_SLOW, (GldiNotificationFunc) cairo_dock_update_icon_data_renderer_notification, NULL);
784 
785 		if (! pRenderer->bCanRenderValueAsText && pRenderer->bWriteValues)
786 			gldi_icon_set_quick_info (pIcon, NULL);
787 
788 		cairo_dock_free_data_renderer (pRenderer);
789 		cairo_dock_set_data_renderer_on_icon (pIcon, NULL);
790 	}
791 }
792 
793 
cairo_dock_reload_data_renderer_on_icon(Icon * pIcon,GldiContainer * pContainer)794 void cairo_dock_reload_data_renderer_on_icon (Icon *pIcon, GldiContainer *pContainer)
795 {
796 	cd_debug ("%s (%s)", __func__, pIcon->cName);
797 	//\_____________ update the renderer size.
798 	CairoDataRenderer *pRenderer = cairo_dock_get_icon_data_renderer (pIcon);
799 	g_return_if_fail (pRenderer != NULL && pRenderer->interface.reload != NULL);
800 
801 	cairo_dock_get_icon_extent (pIcon, &pRenderer->iWidth, &pRenderer->iHeight);
802 
803 	//\_____________ reload at the new size.
804 	pRenderer->interface.reload (pRenderer);
805 
806 	gboolean bLoadTextures = (CAIRO_DOCK_CONTAINER_IS_OPENGL (pContainer) && pRenderer->interface.render_opengl);
807 	_cairo_dock_finish_load_data_renderer (pRenderer, bLoadTextures, pIcon);
808 
809 	//\_____________ redraw.
810 	_refresh (pRenderer, pIcon, pContainer);
811 }
812 
813 
cairo_dock_resize_data_renderer_history(Icon * pIcon,int iNewMemorySize)814 void cairo_dock_resize_data_renderer_history (Icon *pIcon, int iNewMemorySize)
815 {
816 	CairoDataRenderer *pRenderer = cairo_dock_get_icon_data_renderer (pIcon);
817 	g_return_if_fail (pRenderer != NULL);
818 	CairoDataToRenderer *pData = cairo_data_renderer_get_data (pRenderer);
819 
820 	iNewMemorySize = MAX (2, iNewMemorySize);
821 	//g_print ("iMemorySize : %d -> %d\n", pData->iMemorySize, iNewMemorySize);
822 	if (pData->iMemorySize == iNewMemorySize)
823 		return ;
824 
825 	int iOldMemorySize = pData->iMemorySize;
826 	pData->iMemorySize = iNewMemorySize;
827 	pData->pValuesBuffer = g_realloc (pData->pValuesBuffer, pData->iMemorySize * pData->iNbValues * sizeof (gdouble));
828 	if (iNewMemorySize > iOldMemorySize)
829 	{
830 		memset (&pData->pValuesBuffer[iOldMemorySize * pData->iNbValues], 0, (iNewMemorySize - iOldMemorySize) * pData->iNbValues * sizeof (gdouble));
831 	}
832 
833 	g_free (pData->pTabValues);
834 	pData->pTabValues = g_new (gdouble *, pData->iMemorySize);
835 	int i;
836 	for (i = 0; i < pData->iMemorySize; i ++)
837 	{
838 		pData->pTabValues[i] = &pData->pValuesBuffer[i*pData->iNbValues];
839 	}
840 	if (pData->iCurrentIndex >= pData->iMemorySize)
841 		pData->iCurrentIndex = pData->iMemorySize - 1;
842 }
843 
cairo_dock_refresh_data_renderer(Icon * pIcon,GldiContainer * pContainer)844 void cairo_dock_refresh_data_renderer (Icon *pIcon, GldiContainer *pContainer)
845 {
846 	CairoDataRenderer *pRenderer = cairo_dock_get_icon_data_renderer (pIcon);
847 	g_return_if_fail (pRenderer != NULL);
848 
849 	_refresh (pRenderer, pIcon, pContainer);
850 }
851 
852 
cairo_dock_register_built_in_data_renderers(void)853 void cairo_dock_register_built_in_data_renderers (void)  /// merge with init.
854 {
855 	cairo_dock_register_data_renderer_graph ();
856 	cairo_dock_register_data_renderer_gauge ();
857 	cairo_dock_register_data_renderer_progressbar ();
858 }
859