void cairo_dock_free_icon_buffers (Icon *icon)
{
	if (icon == NULL)
		return ;
	
	g_free (icon->acDesktopFileName);
	g_free (icon->acFileName);
	g_free (icon->acName);
	g_free (icon->cInitialName);
	g_free (icon->acCommand);
	g_free (icon->cWorkingDirectory);
	g_free (icon->cBaseURI);
	g_free (icon->cParentDockName);  // on ne liberera pas le sous-dock ici sous peine de se mordre la queue, donc il faut l'avoir fait avant.
	g_free (icon->cClass);
	g_free (icon->cQuickInfo);

	cairo_surface_destroy (icon->pIconBuffer);
	cairo_surface_destroy (icon->pReflectionBuffer);
	cairo_surface_destroy (icon->pTextBuffer);
	cairo_surface_destroy (icon->pQuickInfoBuffer);
	
	if (icon->iIconTexture != 0)
		_cairo_dock_delete_texture (icon->iIconTexture);
	if (icon->iLabelTexture != 0)
		_cairo_dock_delete_texture (icon->iLabelTexture);
	if (icon->iQuickInfoTexture != 0)
		_cairo_dock_delete_texture (icon->iQuickInfoTexture);
}
CD_APPLET_RESET_CONFIG_END


static void _penguin_reset_one_animation (PenguinAnimation *pAnimation)
{
	if (pAnimation->pSurfaces != NULL)
	{
		int i, j;
		for (i = 0; i < pAnimation->iNbDirections; i ++)
		{
			for (j = 0; j < pAnimation->iNbFrames; j ++)
			{
				cairo_surface_destroy (pAnimation->pSurfaces[i][j]);
			}
			g_free (pAnimation->pSurfaces[i]);
			pAnimation->pSurfaces[i] = NULL;
		}
		g_free (pAnimation->pSurfaces);
		pAnimation->pSurfaces = NULL;
	}
	if (pAnimation->iTexture != 0)
	{
		_cairo_dock_delete_texture (pAnimation->iTexture);
		pAnimation->iTexture = 0;
	}
}
static void _set_text_surface (CairoDialog *pDialog, cairo_surface_t *pNewTextSurface, int iNewTextWidth, int iNewTextHeight)
{
	int iPrevMessageWidth = pDialog->iMessageWidth;
	int iPrevMessageHeight = pDialog->iMessageHeight;

	cairo_surface_destroy (pDialog->pTextBuffer);
	pDialog->pTextBuffer = pNewTextSurface;
	if (pDialog->iTextTexture != 0)
		_cairo_dock_delete_texture (pDialog->iTextTexture);
	///pDialog->iTextTexture = cairo_dock_create_texture_from_surface (pNewTextSurface);
	
	pDialog->iTextWidth = iNewTextWidth;
	pDialog->iTextHeight = iNewTextHeight;
	_compute_dialog_sizes (pDialog);

	if (pDialog->iMessageWidth != iPrevMessageWidth || pDialog->iMessageHeight != iPrevMessageHeight)
	{
		g_object_set (pDialog->pMessageWidget, "width-request", pDialog->iMessageWidth, "height-request", pDialog->iMessageHeight, NULL);  // inutile de replacer le dialogue puisque sa gravite fera le boulot.
		
		gtk_widget_queue_draw (pDialog->container.pWidget);
		
		gboolean bInside = pDialog->container.bInside;
		pDialog->container.bInside = FALSE;  // unfortunately the gravity is really badly handled by many WMs, so we have to replace he dialog ourselves :-/
		gldi_dialogs_replace_all ();
		pDialog->container.bInside = bInside;
	}
	else
	{
		_redraw_text_surface (pDialog);
	}
}
void cd_musiplayer_apply_cover (void)
{
	cd_debug ("%s (%s)", __func__, myData.cCoverPath);
	g_return_if_fail (myData.cCoverPath != NULL);
	
	if (CD_APPLET_MY_CONTAINER_IS_OPENGL && myConfig.bOpenglThemes)
	{
		if (myData.iPrevTextureCover != 0)
			_cairo_dock_delete_texture (myData.iPrevTextureCover);
		myData.iPrevTextureCover = myData.TextureCover;
		myData.TextureCover = cairo_dock_create_texture_from_image (myData.cCoverPath);
		if (myData.iPrevTextureCover != 0)
		{
			myData.iCoverTransition = NB_TRANSITION_STEP;
			cairo_dock_launch_animation (myContainer);
		}
		else
		{
			cd_opengl_render_to_texture (myApplet);
			CD_APPLET_REDRAW_MY_ICON;
		}
	}
	else
	{
		CD_APPLET_SET_IMAGE_ON_MY_ICON (myData.cCoverPath);
		CD_APPLET_REDRAW_MY_ICON;
	}
}
static void _set_icon_surface (CairoDialog *pDialog, cairo_surface_t *pNewIconSurface, int iNewIconSize)
{
	int iPrevMessageWidth = pDialog->iMessageWidth;
	int iPrevMessageHeight = pDialog->iMessageHeight;
	
	cairo_surface_destroy (pDialog->pIconBuffer);
	if (pDialog->iIconTexture != 0)
		_cairo_dock_delete_texture (pDialog->iIconTexture);
	
	pDialog->pIconBuffer = pNewIconSurface;
	if (! pNewIconSurface)
		iNewIconSize = 0;
	
	if (pDialog->iIconSize != iNewIconSize)  // can happen if the dialog didn't have an icon before, or if the new one is NULL
	{
		pDialog->iIconSize = iNewIconSize;
		_compute_dialog_sizes (pDialog);
	}
	
	// redraw
	if (pDialog->iMessageWidth != iPrevMessageWidth || pDialog->iMessageHeight != iPrevMessageHeight)
	{
		g_object_set (pDialog->pMessageWidget, "width-request", pDialog->iMessageWidth, "height-request", pDialog->iMessageHeight, NULL);  // inutile de replacer le dialogue puisque sa gravite fera le boulot.
		
		gtk_widget_queue_draw (pDialog->container.pWidget);
	}
	else
	{
		_redraw_icon_surface (pDialog);
	}
}
static void _on_next_missed_task (int iClickedButton, GtkWidget *pInteractiveWidget, GldiModuleInstance *myApplet, CairoDialog *pDialog)
{
	g_return_if_fail (myData.pMissedTasks != NULL);
	//g_print ("%s ()\n", __func__);
	
	// acknowledge this task
	CDClockTask *pTask = myData.pMissedTasks->data;
	pTask->bAcknowledged = TRUE;
	myData.pBackend->update_task (pTask, myApplet);
	
	// jump to next task.
	if (iClickedButton == -1 || iClickedButton == 1)  // 'enter' or 2nd button
	{
		myData.pMissedTasks = g_list_delete_link (myData.pMissedTasks, myData.pMissedTasks);
		if (myData.pMissedTasks != NULL)
		{
			// display next task.
			pTask = myData.pMissedTasks->data;
			//g_print ("display task '%s'\n", pTask->cID);
			gchar *cMessage = _make_missed_task_message (pTask, myApplet);
			gldi_dialog_set_message (pDialog, cMessage);
			g_free (cMessage);
			
			// remove 'next' button if no more task will follow.
			if (myData.pMissedTasks->next == NULL && pDialog->pButtons != NULL && pDialog->iNbButtons > 1)
			{
				// remove 'next' button
				cairo_surface_t *pSurface;
				GLuint iTexture;
				int i = 1;
				pSurface = pDialog->pButtons[i].pSurface;
				if (pSurface != NULL)
				{
					cairo_surface_destroy (pSurface);
					pDialog->pButtons[i].pSurface = NULL;
				}
				iTexture = pDialog->pButtons[i].iTexture;
				if (iTexture != 0)
				{
					_cairo_dock_delete_texture (iTexture);
					pDialog->pButtons[i].iTexture = 0;
				}
				pDialog->iNbButtons = 1;  // only the 'ok' button will stay.
				
				// transform 'cancel' into 'ok'
				i = 0;
				pDialog->pButtons[i].iDefaultType = 1;
			}
			gldi_object_ref (GLDI_OBJECT(pDialog));  // keep the dialog alive.
		}
	}
	else  // dismiss next missed tasks and let the dialog close itself.
	{
		g_list_free (myData.pMissedTasks);
		myData.pMissedTasks = NULL;
	}
}
static void unload (ProgressBar *pProgressBar)
{
	cd_debug("");
	if (pProgressBar->pBarSurface)
		cairo_surface_destroy (pProgressBar->pBarSurface);
	if (pProgressBar->iBarTexture)
		_cairo_dock_delete_texture (pProgressBar->iBarTexture);
	g_free (pProgressBar->cImageGradation);
}
/* Applique la surface correspondant a un etat sur l'icone.
 */
void cd_musicplayer_apply_status_surface (MyPlayerStatus iStatus)
{
	cd_debug ("%s (%d)", __func__, iStatus);
	g_return_if_fail (iStatus < PLAYER_NB_STATUS);
	gboolean bUse3DTheme = (CD_APPLET_MY_CONTAINER_IS_OPENGL && myConfig.bOpenglThemes);
	cairo_surface_t *pSurface = myData.pSurfaces[iStatus];
	
	// load the surface if not already in cache
	if (pSurface == NULL)
	{
		gchar *cUserIcon = myConfig.cUserImage[iStatus];
		if (cUserIcon != NULL)  // l'utilisateur a defini une icone perso pour ce statut => on essaye de la charger.
		{
			gchar *cUserImagePath = cairo_dock_search_icon_s_path (cUserIcon, MAX (myIcon->image.iWidth, myIcon->image.iHeight));
			myData.pSurfaces[iStatus] = CD_APPLET_LOAD_SURFACE_FOR_MY_APPLET (cUserImagePath ? cUserImagePath : cUserIcon);  // si on a trouve une icone, on la prend, sinon on considere le fichier comme une image.
			g_free (cUserImagePath);
		}
		if (myData.pSurfaces[iStatus] == NULL)  // pas d'icone perso pour ce statut, ou l'icone specifiee n'a pas ete trouvee ou pas ete chargee => on prend l'icone par defaut.
		{
			const gchar **cIconName = (bUse3DTheme ? s_cDefaultIconName3D : s_cDefaultIconName);
			gchar *cImagePath = g_strdup_printf (MY_APPLET_SHARE_DATA_DIR"/%s", cIconName[iStatus]);
			myData.pSurfaces[iStatus] = CD_APPLET_LOAD_SURFACE_FOR_MY_APPLET (cImagePath);
			g_free (cImagePath);
		}
		pSurface = myData.pSurfaces[iStatus];
		g_return_if_fail (pSurface != NULL);
	}
	
	// apply the surface
	if (bUse3DTheme)  // 3D theme -> make a transition
	{
		if (myData.iPrevTextureCover != 0)
			_cairo_dock_delete_texture (myData.iPrevTextureCover);
		myData.iPrevTextureCover = myData.TextureCover;
		myData.TextureCover = cairo_dock_create_texture_from_surface (pSurface);
		if (myData.iPrevTextureCover != 0)
		{
			myData.iCoverTransition = NB_TRANSITION_STEP;
			cairo_dock_launch_animation (myContainer);
		}
		else
		{
			cd_opengl_render_to_texture (myApplet);
			CD_APPLET_REDRAW_MY_ICON;
		}
	}
	else  // just apply the surface (we could make a transition too ...)
	{
		CD_APPLET_SET_SURFACE_ON_MY_ICON (pSurface);
	}
}
static void reload (ProgressBar *pProgressBar)
{
	g_return_if_fail (pProgressBar != NULL);
	
	CairoDataRenderer *pRenderer = CAIRO_DATA_RENDERER (pProgressBar);
	int iWidth = pRenderer->iWidth, iHeight = pRenderer->iHeight;
	cd_debug ("%s (%dx%d)", __func__, iWidth, iHeight);
	
	// since we take our parameters from the config, reset them
	double fBarThickness;
	fBarThickness = MAX (myIndicatorsParam.iBarThickness, CD_MIN_BAR_THICKNESS);
	fBarThickness *= pProgressBar->fScale;  // the given size is therefore reached when the icon is at rest.
	pProgressBar->iBarThickness = ceil (fBarThickness);
	if (!pProgressBar->bCustomColors)
	{
		if (!pProgressBar->bInverted)
		{
			memcpy (pProgressBar->fColorGradation, &myIndicatorsParam.fBarColorStart.rgba, 4*sizeof (gdouble));
			memcpy (&pProgressBar->fColorGradation[4], &myIndicatorsParam.fBarColorStop.rgba, 4*sizeof (gdouble));
		}
		else
		{
			memcpy (pProgressBar->fColorGradation, &myIndicatorsParam.fBarColorStop.rgba, 4*sizeof (gdouble));
			memcpy (&pProgressBar->fColorGradation[4], &myIndicatorsParam.fBarColorStart.rgba, 4*sizeof (gdouble));
		}
	}
	
	// reload the bar surface
	if (pProgressBar->pBarSurface)
	{
		cairo_surface_destroy (pProgressBar->pBarSurface);
		pProgressBar->pBarSurface = NULL;
	}
	if (pProgressBar->iBarTexture != 0)
	{
		_cairo_dock_delete_texture (pProgressBar->iBarTexture);
		pProgressBar->iBarTexture = 0;
	}
	_make_bar_surface (pProgressBar);
	
	// set the size for the overlay.
	pRenderer->iHeight = pRenderer->iRank * pProgressBar->iBarThickness + 1;
}
void cd_clock_clear_theme (CairoDockModuleInstance *myApplet, gboolean bClearAll)
{
    if (myData.pBackgroundSurface != NULL)
    {
        cairo_surface_destroy (myData.pBackgroundSurface);
        myData.pBackgroundSurface = NULL;
    }
    if (myData.pForegroundSurface != NULL)
    {
        cairo_surface_destroy (myData.pForegroundSurface);
        myData.pForegroundSurface = NULL;
    }
    if (myData.iBgTexture != 0)
    {
        _cairo_dock_delete_texture (myData.iBgTexture);
        myData.iBgTexture = 0;
    }
    if (myData.iFgTexture != 0)
    {
        _cairo_dock_delete_texture (myData.iFgTexture);
        myData.iFgTexture = 0;
    }
    if (myData.iHourNeedleTexture != 0)
    {
        _cairo_dock_delete_texture (myData.iHourNeedleTexture);
        myData.iHourNeedleTexture = 0;
    }
    if (myData.iMinuteNeedleTexture != 0)
    {
        _cairo_dock_delete_texture (myData.iMinuteNeedleTexture);
        myData.iMinuteNeedleTexture = 0;
    }
    if (myData.iSecondNeedleTexture != 0)
    {
        _cairo_dock_delete_texture (myData.iSecondNeedleTexture);
        myData.iSecondNeedleTexture = 0;
    }
    if (myData.iDateTexture != 0)
    {
        _cairo_dock_delete_texture (myData.iDateTexture);
        myData.iDateTexture = 0;
    }

    if (myData.pNumericBgSurface != NULL)
    {
        cairo_surface_destroy (myData.pNumericBgSurface);
        myData.pNumericBgSurface = NULL;
    }

    if (bClearAll)
    {
        int i;
        for (i = 0; i < CLOCK_ELEMENTS; i ++)
        {
            if (myData.pSvgHandles[i] != NULL)
            {
                rsvg_handle_free (myData.pSvgHandles[i]);
                myData.pSvgHandles[i] = NULL;
            }
        }
    }
}
gboolean cd_clock_update_with_time (GldiModuleInstance *myApplet)
{
	CD_APPLET_ENTER;
	//\________________ On recupere l'heure courante.
	time_t epoch = (time_t) time (NULL);
	_get_current_time (epoch, myApplet);
	
	//\________________ On change la date si necessaire.
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
	gboolean bNewDate = (myData.currentTime.tm_mday != myData.iLastCheckedDay || myData.currentTime.tm_mon != myData.iLastCheckedMonth || myData.currentTime.tm_year != myData.iLastCheckedYear);
	if (bNewDate)
	{
		strftime (s_cDateBuffer, CD_CLOCK_DATE_BUFFER_LENGTH, "%a %d %b", &myData.currentTime);
		myData.iLastCheckedDay = myData.currentTime.tm_mday;
		myData.iLastCheckedMonth = myData.currentTime.tm_mon;
		myData.iLastCheckedYear = myData.currentTime.tm_year;
	}
	if (CD_APPLET_MY_CONTAINER_IS_OPENGL && myConfig.bOldStyle && myConfig.iShowDate == CAIRO_DOCK_INFO_ON_ICON)
	{
		if (bNewDate || myData.iDateTexture == 0)
		{
			if (myData.iDateTexture != 0)
				_cairo_dock_delete_texture (myData.iDateTexture);
			
			double fScale = (double) iWidth / (double) myData.DimensionData.width;
			GldiTextDescription labelDescription;
			memset (&labelDescription, 0, sizeof (GldiTextDescription));
			gldi_text_description_set_font (&labelDescription, (gchar*)"Sans 8");  // casted and then set to null
			labelDescription.fColorStart.rgba.red = myConfig.fDateColor[0];
			labelDescription.fColorStart.rgba.green = myConfig.fDateColor[1];
			labelDescription.fColorStart.rgba.blue = myConfig.fDateColor[2];
			labelDescription.fColorStart.rgba.alpha = 1.;
			labelDescription.bNoDecorations = TRUE;
			cairo_surface_t *pDateSurface = cairo_dock_create_surface_from_text_full (s_cDateBuffer,
				&labelDescription,
				fScale,
				iWidth,
				&myData.iDateWidth, &myData.iDateHeight);
			//g_print ("date : %dx%d\n", myData.iDateWidth, myData.iDateHeight);
			myData.iDateTexture = cairo_dock_create_texture_from_surface (pDateSurface);
			cairo_surface_destroy (pDateSurface);
			labelDescription.cFont = NULL;
			gldi_text_description_reset (&labelDescription);
		}
	}
	if (bNewDate && myConfig.iShowDate == CAIRO_DOCK_INFO_ON_LABEL)
	{
		CD_APPLET_SET_NAME_FOR_MY_ICON (s_cDateBuffer);
	}
	
	//\________________ On dessine avec cette heure.
	myData.iSmoothAnimationStep = 0;
	if (myConfig.bOldStyle)
	{
		if (CD_APPLET_MY_CONTAINER_IS_OPENGL)
			cd_clock_render_analogic_to_texture (myApplet, iWidth, iHeight, &myData.currentTime, 0.);
		else
			cd_clock_draw_analogic (myApplet, iWidth, iHeight, &myData.currentTime);
	}
	else
	{
		cd_clock_draw_text (myApplet, iWidth, iHeight, &myData.currentTime);
		///if (CD_APPLET_MY_CONTAINER_IS_OPENGL)  // on ne sait pas bien dessiner du texte, donc on le fait en cairo, et on transfere tout sur notre texture.
		///	cairo_dock_update_icon_texture (myIcon);
	}
	
	///CD_APPLET_REDRAW_MY_ICON;
	
	//\________________ On teste les alarmes et les taches.
	if (!myConfig.bShowSeconds || myData.currentTime.tm_min != myData.iLastCheckedMinute)  // un g_timeout de 1min ne s'effectue pas forcement a exectement 1 minute d'intervalle, et donc pourrait "sauter" la minute de l'alarme, d'ou le test sur bShowSeconds dans le cas ou l'applet ne verifie que chaque minute.
	{
		myData.iLastCheckedMinute = myData.currentTime.tm_min;
		
		// les alarmes.
		CDClockAlarm *pAlarm;
		guint i;
		for (i = 0; i < myConfig.pAlarms->len; i ++)
		{
			pAlarm = g_ptr_array_index (myConfig.pAlarms, i);
			
			if (myData.currentTime.tm_hour == pAlarm->iHour && myData.currentTime.tm_min == pAlarm->iMinute)
			{
				gboolean bShowAlarm = FALSE, bRemoveAlarm = FALSE;
				if (pAlarm->iDayOfWeek > 0)
				{
					if (pAlarm->iDayOfWeek == 1)
						bShowAlarm = TRUE;
					else if (pAlarm->iDayOfWeek - 1 == myData.currentTime.tm_wday)
						bShowAlarm = TRUE;
					else if (myData.currentTime.tm_wday == 0 || myData.currentTime.tm_wday == 6)  // week-end
					{
						if (pAlarm->iDayOfWeek == 9)
							bShowAlarm = TRUE;
					}
					else if (pAlarm->iDayOfWeek == 8)
						bShowAlarm = TRUE;
				}
				else if (pAlarm->iDayOfMonth > 0)
					bShowAlarm = (pAlarm->iDayOfMonth - 1 == myData.currentTime.tm_mday);
				else  // c'est une alarme qui ne se repete pas.
				{
					bShowAlarm = TRUE;
					bRemoveAlarm = TRUE;
				}
				
				if (bShowAlarm)
				{
					cd_message ("Dring ! %s", pAlarm->cMessage);
					gldi_dialog_show_temporary (pAlarm->cMessage, myIcon, myContainer, 60e3);
					if (pAlarm->cCommand != NULL)
					{
						if (myData.iAlarmPID > 0)
						{
							kill (myData.iAlarmPID, 1);
							myData.iAlarmPID = 0;
						}
						GError *erreur = NULL;
						gchar **argv = g_strsplit (pAlarm->cCommand, " ", -1);
						g_spawn_async (NULL,
							argv,
							NULL,
							0,
							NULL,
							NULL,
							&myData.iAlarmPID,
							&erreur);
						if (erreur != NULL)
						{
							cd_warning ("clock : when trying to execute '%s' : %s", pAlarm->cCommand, erreur->message);
							g_error_free (erreur);
							myData.iAlarmPID = 0;
						}
						g_strfreev (argv);
						cd_message (" --> child_pid : %d", myData.iAlarmPID);
					}
				}
				
				if (bRemoveAlarm)
				{
					cd_message ("Cette alarme ne sera pas repetee");
					g_ptr_array_remove_index (myConfig.pAlarms, i);
					cd_clock_free_alarm (pAlarm);
					/// A FAIRE : effacer l'heure dans le fichier de conf pour cette alarme.
				}
			}
		}
		
		// display missed tasks.
		if (!myData.bTaskCheckedOnce)
		{
			myData.bTaskCheckedOnce = TRUE;
			myData.pMissedTasks = cd_clock_get_missed_tasks (myApplet);
		}
		if (myData.pMissedTasks != NULL)  // so if the dialog was closed before we could acknowledge all the tasks, it will re-open.
		{
			CDClockTask *pTask = myData.pMissedTasks->data;
			gchar *cMessage = _make_missed_task_message (pTask, myApplet);
			CairoDialogAttr attr;
			memset (&attr, 0, sizeof (CairoDialogAttr));
			attr.cText = cMessage;
			attr.bUseMarkup = TRUE;
			attr.cImageFilePath = (gchar *)MY_APPLET_SHARE_DATA_DIR"/icon-task.png";
			const gchar *cButtonsImage[3] = {"ok", NULL, NULL};
			if (myData.pMissedTasks->next != NULL)
			{
				cButtonsImage[0] = "cancel";
				cButtonsImage[1] = "next.png";
			}
			attr.cButtonsImage = cButtonsImage;
			attr.pActionFunc = (CairoDockActionOnAnswerFunc)_on_next_missed_task;
			attr.pUserData = myApplet;
			attr.pFreeDataFunc = NULL;
			attr.iTimeLength = 0;
			attr.pIcon = myIcon;
			attr.pContainer = myContainer;
			gldi_dialog_new (&attr);
			
			g_free (cMessage);
		}
		
		// display next task.
		if (myData.pNextTask != NULL)
		{
			//g_print ("next task : %s\n", myData.pNextTask->cTitle);
			struct tm st;
			st.tm_min = myData.pNextTask->iMinute;
			st.tm_hour = myData.pNextTask->iHour;
			st.tm_mday = myData.pNextTask->iDay;
			st.tm_mon = myData.pNextTask->iMonth;
			st.tm_year = myData.pNextTask->iYear - 1900;
			st.tm_sec = 0;
			st.tm_isdst = myData.currentTime.tm_isdst;
			time_t t = mktime (&st);
			//g_print ("time : %ld, task : %ld\n", epoch, t);
			if (t < epoch)  // la tache est depassee.
			{
				// acknowledge this task
				myData.pNextTask->bAcknowledged = TRUE;
				myData.pBackend->update_task (myData.pNextTask, myApplet);
				
				// look for next task.
				myData.pNextTask = cd_clock_get_next_scheduled_task (myApplet);
			}
			else if (t < epoch + 15*60 && t >= epoch)
			{
				if (t < epoch + 60)
				{
					if (! myData.pNextTask->bFirstWarning)
					{
						//g_print ("first warning\n");
						myData.pNextTask->bFirstWarning = TRUE;
						gchar *cText = g_strdup_printf ("%s\n<b>%s</b>\n %s\n\n%s",
							D_("It's time for the following task:"),
							myData.pNextTask->cTitle?myData.pNextTask->cTitle:D_("No title"),
							myData.pNextTask->cText?myData.pNextTask->cText:"",
							D_("Repeat this message every:"));
						_task_warning (myData.pNextTask, cText);
						g_free (cText);
					}
				}
				else if (! myData.pNextTask->b15mnWarning)
				{
					//g_print ("15 mn warning\n");
					myData.pNextTask->b15mnWarning = TRUE;
					
					gchar *cText = g_strdup_printf ("%s\n<b>%s</b>\n %s",
						D_("This task will begin in 15 minutes:"),
						myData.pNextTask->cTitle?myData.pNextTask->cTitle:D_("No title"),
						myData.pNextTask->cText?myData.pNextTask->cText:"");
					
					CairoDialogAttr attr;
					memset (&attr, 0, sizeof (CairoDialogAttr));
					attr.cText = (gchar *)cText;
					attr.cImageFilePath = (gchar *)MY_APPLET_SHARE_DATA_DIR"/icon-task.png";
					attr.iTimeLength = 60e3;
					attr.bUseMarkup = TRUE;
					attr.pIcon = myIcon;
					attr.pContainer = myContainer;
					gldi_dialog_new (&attr);
					CD_APPLET_DEMANDS_ATTENTION (NULL, 60);
				}
			}
			
			// display next anniversary if it is scheduled in less than 1 day, because anniversary require time to prepare.
			if (myData.pNextAnniversary != NULL)
			{
				if (!myData.pNextAnniversary->b1DayWarning && ! myData.pNextAnniversary->bFirstWarning && ! myData.pNextAnniversary->b15mnWarning)
				{
					GDate* pCurrentDate = g_date_new_dmy (myData.currentTime.tm_mday, myData.currentTime.tm_mon + 1, myData.currentTime.tm_year+1900);
					GDate* pAnnivDate = g_date_new_dmy (myData.pNextAnniversary->iDay, myData.pNextAnniversary->iMonth + 1, myData.currentTime.tm_year+1900);
					gint iDaysToNextAnniversary = g_date_days_between (pCurrentDate, pAnnivDate);
					if (iDaysToNextAnniversary >= 0 && iDaysToNextAnniversary <= 1)
					{
						myData.pNextAnniversary->b1DayWarning = TRUE;
						gchar *cText = g_strdup_printf ("%s\n<b>%s</b>\n %s\n\n%s",
							iDaysToNextAnniversary == 0 ? D_("Today is the following anniversary:") : D_("Tomorrow is the following anniversary:"),
							myData.pNextTask->cTitle?myData.pNextTask->cTitle:D_("No title"),
							myData.pNextTask->cText?myData.pNextTask->cText:"",
							D_("Repeat this message every:"));
						_task_warning (myData.pNextTask, cText);
						g_free (cText);
						myData.pNextAnniversary = cd_clock_get_next_anniversary (myApplet);
					}
					g_date_free (pCurrentDate);
					g_date_free (pAnnivDate);
				}
			}
		}
	}
	
	CD_APPLET_LEAVE(TRUE);
}
void cd_opengl_reset_opengl_datas (CairoDockModuleInstance *myApplet)
{
	if (myData.draw_cover != 0)
	{
		glDeleteLists (myData.draw_cover, 1);
		myData.draw_cover = 0;
	}
	if(myData.TextureFrame != 0)
	{
		_cairo_dock_delete_texture (myData.TextureFrame);
		myData.TextureFrame = 0;
	}
	if(myData.iPrevTextureCover != 0)
	{	
		_cairo_dock_delete_texture (myData.iPrevTextureCover);
		myData.iPrevTextureCover = 0;
	}
	if(myData.TextureCover != 0)
	{	
		_cairo_dock_delete_texture (myData.TextureCover);
		myData.TextureCover = 0;
	}
	if(myData.TextureReflect != 0)
	{
		_cairo_dock_delete_texture (myData.TextureReflect);
		myData.TextureReflect = 0;
	}
	if(myData.TextureButton1 != 0)
	{
		_cairo_dock_delete_texture (myData.TextureButton1);
		myData.TextureButton1 = 0;
	}
	if(myData.TextureButton2 != 0)
	{
		_cairo_dock_delete_texture (myData.TextureButton2);
		myData.TextureButton2 = 0;
	}
	if(myData.TextureButton3 != 0)
	{
		_cairo_dock_delete_texture (myData.TextureButton3);
		myData.TextureButton3 = 0;
	}
	if(myData.TextureButton4 != 0)
	{
		_cairo_dock_delete_texture (myData.TextureButton4);
		myData.TextureButton4 = 0;
	}
	if(myData.TextureOsdPlay != 0)
	{
		_cairo_dock_delete_texture (myData.TextureOsdPlay);
		myData.TextureOsdPlay = 0;
	}
	if(myData.TextureOsdPause != 0)
	{
		_cairo_dock_delete_texture (myData.TextureOsdPause);
		myData.TextureOsdPause = 0;
	}
	if(myData.TextureOsdPrev != 0)
	{
		_cairo_dock_delete_texture (myData.TextureOsdPrev);
		myData.TextureOsdPrev = 0;
	}
	if(myData.TextureOsdNext != 0)
	{
		_cairo_dock_delete_texture (myData.TextureOsdNext);
		myData.TextureOsdNext = 0;
	}
	if(myData.TextureOsdHome != 0)
	{
		_cairo_dock_delete_texture (myData.TextureOsdHome);
		myData.TextureOsdHome = 0;
	}
	myData.mouseOnButton1 = myData.mouseOnButton2 = myData.mouseOnButton3 = myData.mouseOnButton4 = 0;
	myData.iButton1Count = myData.iButton2Count = myData.iButton3Count = myData.iButton4Count = 0;
	myData.iButtonState = 0;
	myData.iCoverTransition = 0;
}
static void _load_theme (CairoDockModuleInstance *myApplet, GError **erreur)
{
	//\_______________ On charge le theme si necessaire, avec en priorite les images utilisateur.
	if (myConfig.cThemePath != NULL && (myConfig.cNoMailUserImage == NULL || myConfig.cHasMailUserImage == NULL))
	{
		GError *tmp_erreur = NULL;
		GDir *dir = g_dir_open (myConfig.cThemePath, 0, &tmp_erreur);
		if (tmp_erreur != NULL)
		{
			g_propagate_error (erreur, tmp_erreur);
			return ;
		}
		
		const gchar *cElementName;
		gchar *cElementPath;
		while ((cElementName = g_dir_read_name (dir)) != NULL)
		{
			cElementPath = g_strdup_printf ("%s/%s", myConfig.cThemePath, cElementName);
			cd_debug ("  Mail theme item: %s", cElementPath);
			if (strncmp (cElementName, "no_mail", 7) == 0 && myConfig.cNoMailUserImage == NULL)
			{
				myConfig.cNoMailUserImage = cElementPath;
			}
			else if (strncmp (cElementName, "has_mail", 8) == 0 && myConfig.cHasMailUserImage == NULL)
			{
				myConfig.cHasMailUserImage = cElementPath;
			}
			else if (strncmp (cElementName, "new_mail_sound", 14) == 0 && myConfig.cNewMailUserSound == NULL)
			{
				myConfig.cNewMailUserSound = cElementPath;
			}
			else
			{
				g_free (cElementPath);
			}
		}
		g_dir_close (dir);
	}
	if (myConfig.cNoMailUserImage == NULL || myConfig.cHasMailUserImage == NULL || myConfig.cNewMailUserSound == NULL)
	{
		cd_warning ("mail : couldn't find images, this theme is not valid");
	}
	
	// textures et calllist.
	if (myData.iNoMailTexture != 0)
	{
		_cairo_dock_delete_texture (myData.iNoMailTexture);
		myData.iNoMailTexture = 0;
	}
	if (myData.iHasMailTexture != 0)
	{
		_cairo_dock_delete_texture (myData.iHasMailTexture);
		myData.iHasMailTexture = 0;
	}
	if (CD_APPLET_MY_CONTAINER_IS_OPENGL && myDesklet)
	{
		if (myConfig.cNoMailUserImage != NULL)
			myData.iNoMailTexture = cairo_dock_create_texture_from_image(myConfig.cNoMailUserImage);
		if (myConfig.cHasMailUserImage != NULL)
			myData.iHasMailTexture = cairo_dock_create_texture_from_image(myConfig.cHasMailUserImage);

		if (myData.iCubeCallList == 0)
			myData.iCubeCallList = cd_mail_load_cube_calllist();
	}

	// on cree le repertoire de l'historique si necessaire.
	myData.cWorkingDirPath = g_strdup_printf ("%s/mail", g_cCairoDockDataDir);
	if (! g_file_test (myData.cWorkingDirPath, G_FILE_TEST_EXISTS))
	{
		cd_debug ("Plugin Mail : le dossier '%s' n'existe pas encore -> On le cree", myData.cWorkingDirPath);
		if (g_mkdir (myData.cWorkingDirPath, 7*8*8+7*8+0) != 0)
		{
			cd_warning ("couldn't create directory '%s' !\nNo read history will be available.", myData.cWorkingDirPath);
		}
	}
}
void cairo_dock_load_icon_image (Icon *icon, G_GNUC_UNUSED GldiContainer *pContainer)
{
	if (icon->pContainer == NULL)
	{
		cd_warning ("/!\\ Icon %s is not inside a container !!!", icon->cName);  // it's ok if this happens, but it should be rare, and I'd like to know when, so be noisy.
		return;
	}
	GldiModuleInstance *pInstance = icon->pModuleInstance;  // this is the only function where we destroy/create the icon's surface, so we must handle the cairo-context here.
	if (pInstance && pInstance->pDrawContext != NULL)
	{
		cairo_destroy (pInstance->pDrawContext);
		pInstance->pDrawContext = NULL;
	}
	
	//g_print ("%s (%s, %dx%d)\n", __func__, icon->cName, (int)icon->fWidth, (int)icon->fHeight);
	// the renderer of the container must have set the size beforehand, when the icon has been inserted into the container.
	if (cairo_dock_icon_get_allocated_width (icon) <= 0 || cairo_dock_icon_get_allocated_height (icon) <= 0)  // we don't want a surface/texture.
	{
		cairo_dock_unload_image_buffer (&icon->image);
		return;
	}
	g_return_if_fail (icon->fWidth > 0); // should never happen; if it does, it's an error, so be noisy.
	
	//\______________ keep the current buffer on the icon so that the 'load' can use it (for instance, applis may draw emblems).
	cairo_surface_t *pPrevSurface = icon->image.pSurface;
	GLuint iPrevTexture = icon->image.iTexture;
	
	//\______________ load the image buffer (surface + texture).
	if (icon->iface.load_image)
		icon->iface.load_image (icon);
	
	//\______________ if nothing has changed or no image was loaded, set a default image.
	if ((icon->image.pSurface == pPrevSurface || icon->image.pSurface == NULL)
	&& (icon->image.iTexture == iPrevTexture || icon->image.iTexture == 0))
	{
		gchar *cIconPath = cairo_dock_search_image_s_path (CAIRO_DOCK_DEFAULT_ICON_NAME);
		if (cIconPath == NULL)  // fichier non trouve.
		{
			cIconPath = g_strdup (GLDI_SHARE_DATA_DIR"/icons/"CAIRO_DOCK_DEFAULT_ICON_NAME);
		}
		int w = cairo_dock_icon_get_allocated_width (icon);
		int h = cairo_dock_icon_get_allocated_height (icon);
		cairo_surface_t *pSurface = cairo_dock_create_surface_from_image_simple (cIconPath,
			w,
			h);
		cairo_dock_load_image_buffer_from_surface (&icon->image, pSurface, w, h);
		g_free (cIconPath);
	}
	
	//\_____________ set the background if needed.
	icon->bNeedApplyBackground = FALSE;
	if (g_pIconBackgroundBuffer.pSurface != NULL && ! GLDI_OBJECT_IS_SEPARATOR_ICON (icon))
	{
		if (icon->image.iTexture != 0 && g_pIconBackgroundBuffer.iTexture != 0)
		{
			if (! cairo_dock_apply_icon_background_opengl (icon))  // couldn't draw on the texture
			{
				icon->bDamaged = FALSE;  // it's not a big deal, since we can draw under the existing image easily; so we don't need to damage the icon (it's expensive especially if it's an applet).
				icon->bNeedApplyBackground = TRUE;  // just postpone it until drawing is possible.
			}
		}
		else if (icon->image.pSurface != NULL)
		{
			cairo_t *pCairoIconBGContext = cairo_create (icon->image.pSurface);
			cairo_set_operator (pCairoIconBGContext, CAIRO_OPERATOR_DEST_OVER);
			cairo_dock_apply_image_buffer_surface_at_size (&g_pIconBackgroundBuffer, pCairoIconBGContext,
				icon->image.iWidth, icon->image.iHeight,
				0, 0, 1);
			cairo_destroy (pCairoIconBGContext);
		}
	}
	
	//\______________ free the previous buffers.
	if (pPrevSurface != NULL)
		cairo_surface_destroy (pPrevSurface);
	if (iPrevTexture != 0)
		_cairo_dock_delete_texture (iPrevTexture);
	
	if (pInstance && icon->image.pSurface != NULL)
	{
		pInstance->pDrawContext = cairo_create (icon->image.pSurface);
		if (!pInstance->pDrawContext || cairo_status (pInstance->pDrawContext) != CAIRO_STATUS_SUCCESS)
		{
			cd_warning ("couldn't initialize drawing context, applet won't be able to draw itself !");
			pInstance->pDrawContext = NULL;
		}
	}
}
static void _cairo_dock_finish_load_data_renderer (CairoDataRenderer *pRenderer, gboolean bLoadTextures, Icon *pIcon)
{
	int iNbValues = cairo_data_renderer_get_nb_values (pRenderer);
	//\___________________ On charge les emblemes si l'implementation les a valides.
	if (pRenderer->pEmblems != NULL)
	{
		CairoDataRendererEmblem *pEmblem;
		cairo_surface_t *pSurface;
		int i;
		for (i = 0; i < iNbValues; i ++)
		{
			pEmblem = &pRenderer->pEmblems[i];
			if (pEmblem->pSurface != NULL)
			{
				cairo_surface_destroy (pEmblem->pSurface);
				pEmblem->pSurface = NULL;
			}
			if (pEmblem->iTexture != 0)
			{
				_cairo_dock_delete_texture (pEmblem->iTexture);
				pEmblem->iTexture = 0;
			}
			if (pEmblem->param.fWidth != 0 && pEmblem->param.fHeight != 0 && pEmblem->cImagePath != NULL)
			{
				pSurface = cairo_dock_create_surface_from_image_simple (pEmblem->cImagePath,
					pEmblem->param.fWidth * pRenderer->iWidth,
					pEmblem->param.fHeight * pRenderer->iHeight);
				if (bLoadTextures)
				{
					pEmblem->iTexture = cairo_dock_create_texture_from_surface (pSurface);
					cairo_surface_destroy (pSurface);
				}
				else
					pEmblem->pSurface = pSurface;
			}
		}
	}
	
	//\___________________ On charge les labels si l'implementation les a valides.
	if (pRenderer->pLabels != NULL)
	{
		GldiTextDescription textDescription;
		gldi_text_description_copy (&textDescription, &myIconsParam.quickInfoTextDescription);
		
		CairoDataRendererText *pLabel;
		cairo_surface_t *pSurface;
		int i;
		for (i = 0; i < iNbValues; i ++)
		{
			pLabel = &pRenderer->pLabels[i];
			if (pLabel->pSurface != NULL)
			{
				cairo_surface_destroy (pLabel->pSurface);
				pLabel->pSurface = NULL;
			}
			if (pLabel->iTexture != 0)
			{
				_cairo_dock_delete_texture (pLabel->iTexture);
				pLabel->iTexture = 0;
			}
			if (pLabel->param.fWidth != 0 && pLabel->param.fHeight != 0 && pLabel->cText != NULL)
			{
				textDescription.bNoDecorations = TRUE;
				textDescription.bUseDefaultColors = FALSE;
				textDescription.iMargin = 0;
				textDescription.bOutlined = TRUE;  /// tester avec et sans ...
				textDescription.fColorStart.rgba.red = pLabel->param.pColor[0];
				textDescription.fColorStart.rgba.green = pLabel->param.pColor[1];
				textDescription.fColorStart.rgba.blue = pLabel->param.pColor[2];
				textDescription.fColorStart.rgba.alpha = 1.;
				pSurface = cairo_dock_create_surface_from_text (pLabel->cText,
					&textDescription,
					&pLabel->iTextWidth, &pLabel->iTextHeight);
				if (bLoadTextures)
				{
					pLabel->iTexture = cairo_dock_create_texture_from_surface (pSurface);
					cairo_surface_destroy (pSurface);
				}
				else
					pLabel->pSurface = pSurface;
			}
		}
	}
	
	//\___________________ On regarde si le texte dessine sur l'icone sera suffisamment lisible.
	if (pRenderer->pValuesText != NULL)
	{
		CairoDataRendererTextParam *pText = &pRenderer->pValuesText[0];
		//g_print ("+++++++pText->fWidth * pRenderer->iWidth : %.2f\n", pText->fWidth * pRenderer->iWidth);
		pRenderer->bCanRenderValueAsText = (pText->fWidth * pRenderer->iWidth >= CD_MIN_TEXT_WITH);
	}
	
	if (pRenderer->bCanRenderValueAsText && pRenderer->bWriteValues)
		gldi_icon_set_quick_info (pIcon, NULL);
	
	//\___________________ Build an overlay if the renderer will use some.
	if (pRenderer->bUseOverlay)
	{
		//g_print ("+ overlay %dx%d\n", pRenderer->iWidth, pRenderer->iHeight);
		cairo_surface_t *pSurface = cairo_dock_create_blank_surface (pRenderer->iWidth, pRenderer->iHeight);
		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.
		cairo_dock_set_overlay_scale (pRenderer->pOverlay, 0);  // keep the original size of the image
	}
}