void cd_update_icon (void)
{
	gboolean bNeedRedraw = FALSE;
	
	// update the volume info
	switch (myConfig.iVolumeDisplay)
	{
		case VOLUME_ON_LABEL :
			CD_APPLET_SET_NAME_FOR_MY_ICON_PRINTF ("%s: %d%%", myData.mixer_card_name?myData.mixer_card_name:D_("Volume"), myData.iCurrentVolume);
		break;
		
		case VOLUME_ON_ICON :
			CD_APPLET_SET_QUICK_INFO_ON_MY_ICON_PRINTF ("%d%%", myData.iCurrentVolume);
			bNeedRedraw = TRUE;
		break;
		
		default :
		break;
	}
	
	// update the icon representation
	switch (myConfig.iVolumeEffect)  // set the icon if needed
	{
		case VOLUME_EFFECT_NONE :
		case VOLUME_EFFECT_BAR :
			if (myData.bMuteImage < 0 || (myData.bIsMute != myData.bMuteImage))
			{
				if (myData.bIsMute)
					CD_APPLET_SET_USER_IMAGE_ON_MY_ICON (myConfig.cMuteIcon, "mute.svg");
				else
					CD_APPLET_SET_USER_IMAGE_ON_MY_ICON (myConfig.cDefaultIcon, "default.svg");
				myData.bMuteImage = myData.bIsMute;
				bNeedRedraw = FALSE;
			}
		break;
		
		default :
		break;
	}
	switch (myConfig.iVolumeEffect)  // render the value
	{
		case VOLUME_EFFECT_BAR :
		case VOLUME_EFFECT_GAUGE :
		{
			double fPercent;
			if (myData.bIsMute)
				fPercent = CAIRO_DATA_RENDERER_UNDEF_VALUE;
			else
				fPercent = (double) myData.iCurrentVolume / 100.;
			CD_APPLET_RENDER_NEW_DATA_ON_MY_ICON (&fPercent);
			bNeedRedraw = FALSE;
		}
		break;
		
		default :
		break;
	}
	
	if (bNeedRedraw)
		CD_APPLET_REDRAW_MY_ICON;
	
	if (myData.pScale)
	{
		cd_mixer_set_volume_with_no_callback (myData.pScale, myData.iCurrentVolume);
	}
}
void update_icon (void)
{
	cd_debug ("%s (on battery: %d -> %d; time:%.1f -> %.1f ; charge:%.1f -> %.1f)", __func__, myData.bPrevOnBattery, myData.bOnBattery, (double)myData.iPrevTime, (double)myData.iTime, (double)myData.iPrevPercentage, (double)myData.iPercentage);
	
	// hide the icon when not on battery or no information available (e.g. with a desktop)
	if (myConfig.bHideNotOnBattery && myDock && (! myData.bOnBattery))
	{
		if (! myData.bIsHidden)
		{ // we remove the icon
			gldi_icon_detach (myIcon);
			myData.bIsHidden = TRUE;
		}
		return; // no need any redraw if the icon is hidden, and can't display the dialog properly without the icon.
	}
	else if (myData.bIsHidden && myData.bOnBattery && myDock) // if the icon is hidden but we are now on battery, we (re-)insert the icon.
	{
		cd_debug ("Re-insert the icon");
		gldi_icon_insert_in_container (myIcon, myContainer, CAIRO_DOCK_ANIMATE_ICON);
		myData.bIsHidden = FALSE;
	}

	// no information available or no battery, draw a default icon.
	if (! myData.bBatteryPresent)
	{
		CD_APPLET_REMOVE_MY_DATA_RENDERER;
		CD_APPLET_SET_IMAGE_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/sector.svg");
		CD_APPLET_REDRAW_MY_ICON;
		return;
	}

	gboolean bInit = (cairo_dock_get_icon_data_renderer (myIcon) == NULL);
	if (bInit) // first time: init or reload
		_set_data_renderer (myApplet);
	
	gboolean bChanged = (myData.bPrevOnBattery != myData.bOnBattery
	                     || myData.iPrevPercentage != myData.iPercentage
	                     || myData.iTime != myData.iPrevTime
	                     || bInit); // just to be sure
	
	if (bChanged || myConfig.iDisplayType == CD_POWERMANAGER_GRAPH)  // graphs need to be updated each time, even if there is no change.
	{
		// update the icon representation
		if (myConfig.iDisplayType == CD_POWERMANAGER_ICONS)  // set the icon if needed
		{
			if (myData.iOnBatteryImage != myData.bOnBattery)
			{
				if (myData.bOnBattery)
					CD_APPLET_SET_USER_IMAGE_ON_MY_ICON (myConfig.cUserBatteryIconName, "default-battery.svg");
				else
					CD_APPLET_SET_USER_IMAGE_ON_MY_ICON (myConfig.cUserChargeIconName, "default-charge.svg");
				myData.iOnBatteryImage = myData.bOnBattery;
			}
		}
		// render the value
		double fPercent;
		if (! myData.bBatteryPresent)
			fPercent = CAIRO_DATA_RENDERER_UNDEF_VALUE;
		else
			fPercent = (double) myData.iPercentage / 100.;
		CD_APPLET_RENDER_NEW_DATA_ON_MY_ICON (&fPercent);
		
		if (bChanged)
		{
			// add or remove the charge overlay if the 'on_battery' status has changed.
			if (myData.bPrevOnBattery != myData.bOnBattery || bInit)
			{
				if (! myData.bOnBattery)
				{
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (myConfig.cEmblemIconName ? myConfig.cEmblemIconName : MY_APPLET_SHARE_DATA_DIR"/charge.svg", CAIRO_OVERLAY_MIDDLE);
				}
				else
				{
					CD_APPLET_REMOVE_OVERLAY_ON_MY_ICON (CAIRO_OVERLAY_MIDDLE);
				}
			}
			
			// trigger alarms.
			if (myData.bOnBattery)
			{
				// Alert when battery charge goes under a configured value in %
				if (myData.iPrevPercentage > myConfig.lowBatteryValue && myData.iPercentage <= myConfig.lowBatteryValue)
				{
					cd_powermanager_alert(POWER_MANAGER_CHARGE_LOW);
					if (myConfig.cSoundPath[POWER_MANAGER_CHARGE_LOW] != NULL)
						cairo_dock_play_sound (myConfig.cSoundPath[POWER_MANAGER_CHARGE_LOW]);
				}
				// Alert when battery charge is under 4%
				if (myData.iPrevPercentage > 4 && myData.iPercentage <= 4)
				{
					cd_powermanager_alert (POWER_MANAGER_CHARGE_CRITICAL);
					if (myConfig.cSoundPath[POWER_MANAGER_CHARGE_CRITICAL] != NULL)
						cairo_dock_play_sound (myConfig.cSoundPath[POWER_MANAGER_CHARGE_CRITICAL]);
				}
			}
			else
			{
				// Alert when battery is charged
				if(myData.iPrevPercentage > 0 && myData.iPrevPercentage < 100 && myData.iPercentage == 100)  // the first condition is to prevent the dialog on startup.
					cd_powermanager_alert (POWER_MANAGER_CHARGE_FULL);
			}
			
			// update the icon's label.
			if (myConfig.defaultTitle == NULL || *myConfig.defaultTitle == '\0')
			{
				if (! myData.bOnBattery && myData.iPercentage > 99.9)
				{
					CD_APPLET_SET_NAME_FOR_MY_ICON_PRINTF ("%d%% - %s",
						(int)myData.iPercentage,
						D_("Battery charged"));
				}
				else
				{
					gchar cFormatBuffer[21];
					int iBufferLength = 20;
					if (myData.iTime != 0)
					{
						int time = myData.iTime;
						int hours = time / 3600;
						int minutes = (time % 3600) / 60;
						if (hours != 0)
							snprintf (cFormatBuffer, iBufferLength, "%d%s%02d", hours, D_("h"), abs (minutes));
						else
							snprintf (cFormatBuffer, iBufferLength, "%d%s", minutes, D_("mn"));
					}
					else
					{
						strncpy (cFormatBuffer, "-:--", iBufferLength);
					}
					CD_APPLET_SET_NAME_FOR_MY_ICON_PRINTF ("%d%% - %s %s",
						(int)myData.iPercentage,
						cFormatBuffer,
						myData.bOnBattery ? D_("remaining") : D_("until charged"));
				}
			}
			
			myData.bPrevOnBattery = myData.bOnBattery;
			myData.iPrevPercentage = myData.iPercentage;
			myData.iPrevTime = myData.iTime;
		}
	}
}
void update_icon(void)
{
    gboolean bNeedRedraw = FALSE;
    cd_message ("%s (time:%.2f -> %.2f ; charge:%.2f -> %.2f)", __func__, myData.previous_battery_time, myData.battery_time, myData.previous_battery_charge, myData.battery_charge);
    if(myData.battery_present)
    {
        if (myData.previous_battery_time != myData.battery_time)
        {
            if(myConfig.quickInfoType == POWER_MANAGER_TIME)
            {
                if (myData.battery_time != 0) {
                    CD_APPLET_SET_HOURS_MINUTES_AS_QUICK_INFO (myData.battery_time);
                }
                else {
                    CD_APPLET_SET_QUICK_INFO_ON_MY_ICON ("-:--");
                }
            }
            else if(myConfig.quickInfoType == POWER_MANAGER_CHARGE)
            {
                CD_APPLET_SET_QUICK_INFO_ON_MY_ICON_PRINTF ("%d%%", (int)myData.battery_charge);
            }
            else
            {
                CD_APPLET_SET_QUICK_INFO_ON_MY_ICON (NULL);
            }

            bNeedRedraw = TRUE;
            myData.previous_battery_time = myData.battery_time;
        }

        if (myData.previously_on_battery != myData.on_battery || myData.previous_battery_charge != myData.battery_charge)
        {
            if (myData.previously_on_battery != myData.on_battery)
            {
                myData.previously_on_battery = myData.on_battery;
                myData.alerted = FALSE;  //On a changé de statut, donc on réinitialise les alertes
                myData.bCritical = FALSE;
            }

            if (myConfig.iDisplayType == CD_POWERMANAGER_GAUGE || myConfig.iDisplayType == CD_POWERMANAGER_GRAPH)
            {
                double fPercent = (double) myData.battery_charge / 100.;
                CD_APPLET_RENDER_NEW_DATA_ON_MY_ICON (&fPercent);
                bNeedRedraw = FALSE;
            }
            else if (myConfig.iDisplayType == CD_POWERMANAGER_ICONS)
            {
                cd_powermanager_draw_icon_with_effect (myData.on_battery);
                bNeedRedraw = FALSE;
            }

            if(myData.on_battery)
            {
                //Alert when battery charge is under a configured value in %
                if (myData.battery_charge <= myConfig.lowBatteryValue && ! myData.alerted)
                {
                    cd_powermanager_alert(POWER_MANAGER_CHARGE_LOW);
                    if (myConfig.cSoundPath[POWER_MANAGER_CHARGE_LOW] != NULL)
                        cairo_dock_play_sound (myConfig.cSoundPath[POWER_MANAGER_CHARGE_LOW]);
                }
                //Alert when battery charge is under 4%
                if (myData.battery_charge <= 4 && ! myData.bCritical)
                {
                    myData.bCritical = TRUE;
                    cd_powermanager_alert (POWER_MANAGER_CHARGE_CRITICAL);
                    if (myConfig.cSoundPath[POWER_MANAGER_CHARGE_CRITICAL] != NULL)
                        cairo_dock_play_sound (myConfig.cSoundPath[POWER_MANAGER_CHARGE_CRITICAL]);
                }
                //Embleme sur notre icône
                CD_APPLET_DRAW_EMBLEM (CAIRO_DOCK_EMBLEM_BLANK, CAIRO_DOCK_EMBLEM_MIDDLE);
            }
            else
            {
                //Alert when battery is charged
                if(myData.battery_charge == 100 && ! myData.alerted)
                    cd_powermanager_alert (POWER_MANAGER_CHARGE_FULL);

                CD_APPLET_DRAW_EMBLEM (CAIRO_DOCK_EMBLEM_CHARGE, CAIRO_DOCK_EMBLEM_MIDDLE);
            }

            myData.previously_on_battery = myData.on_battery;
            myData.previous_battery_charge = myData.battery_charge;
        }
    }
    else
    {
        CD_APPLET_SET_LOCAL_IMAGE_ON_MY_ICON ("sector.svg");
        bNeedRedraw = TRUE;
    }

    if (bNeedRedraw)
        CD_APPLET_REDRAW_MY_ICON;
}
gboolean cd_sysmonitor_update_from_data (CairoDockModuleInstance *myApplet)
{
	static double s_fValues[CD_SYSMONITOR_NB_MAX_VALUES];
	
	if ( ! myData.bAcquisitionOK)
	{
		cd_warning ("One or more datas couldn't be retrieved");
		CD_APPLET_SET_QUICK_INFO_ON_MY_ICON ("N/A");  // plus discret qu'une bulle de dialogue.
		if (myConfig.iInfoDisplay == CAIRO_DOCK_INFO_ON_LABEL)
			CD_APPLET_SET_NAME_FOR_MY_ICON (myConfig.defaultTitle);
		memset (s_fValues, 0, sizeof (s_fValues));
		CD_APPLET_RENDER_NEW_DATA_ON_MY_ICON (s_fValues);
	}
	else
	{
		if (! myData.bInitialized)
		{
			if (myConfig.iInfoDisplay == CAIRO_DOCK_INFO_ON_ICON)
				CD_APPLET_SET_QUICK_INFO_ON_MY_ICON (myDock ? "..." : D_("Loading"));
			memset (s_fValues, 0, sizeof (s_fValues));
			CD_APPLET_RENDER_NEW_DATA_ON_MY_ICON (s_fValues);
		}
		else
		{
			// Copier les donnes en memoire partagee...
			
			if (myConfig.iInfoDisplay == CAIRO_DOCK_INFO_ON_ICON || (myDock && myConfig.iInfoDisplay == CAIRO_DOCK_INFO_ON_LABEL))  // on affiche les valeurs soit en info-rapide, soit sur l'etiquette en mode dock.
			{
				gboolean bOneLine = (myConfig.iInfoDisplay == CAIRO_DOCK_INFO_ON_LABEL);
				GString *sInfo = g_string_new ("");
				if (myConfig.bShowCpu)
				{
					g_string_printf (sInfo, (myData.fCpuPercent < 10 ? "%s%.1f%%%s" : "%s%.0f%%%s"),
						(myDesklet ? "CPU:" : ""),
						myData.fCpuPercent,
						(bOneLine ? " - " : "\n"));
				}
				if (myConfig.bShowRam)
				{
					g_string_append_printf (sInfo, (myData.fRamPercent < 10 ? "%s%.1f%%%s" : "%s%.0f%%%s"),
						(myDesklet ? "RAM:" : ""),
						myData.fRamPercent,
						(bOneLine ? " - " : "\n"));
				}
				if (myConfig.bShowSwap)
				{
					g_string_append_printf (sInfo, (myData.fSwapPercent < 10 ? "%s%.1f%%%s" : "%s%.0f%%%s"),
						(myDesklet ? "SWAP:" : ""),
						myData.fSwapPercent,
						(bOneLine ? " - " : "\n"));
				}
				if (myConfig.bShowNvidia)
				{
					g_string_append_printf (sInfo, "%s%d°C%s",
						(myDesklet ? "GPU:" : ""),
						myData.iGPUTemp,
						(bOneLine ? " - " : "\n"));
				}
				sInfo->str[sInfo->len-(bOneLine?3:1)] = '\0';
				if (bOneLine)
					CD_APPLET_SET_NAME_FOR_MY_ICON (sInfo->str);
				else
					CD_APPLET_SET_QUICK_INFO_ON_MY_ICON (sInfo->str);
				g_string_free (sInfo, TRUE);
			}
			
			if (myData.bNeedsUpdate || myConfig.iDisplayType == CD_SYSMONITOR_GRAPH)
			{
				int i = 0;
				if (myConfig.bShowCpu)
				{
					s_fValues[i++] = (double) myData.fCpuPercent / 100;
				}
				if (myConfig.bShowRam)
				{
					s_fValues[i++] = myData.fRamPercent / 100;
				}
				if (myConfig.bShowSwap)
				{
					s_fValues[i++] = (double) (myData.swapTotal ? (myConfig.bShowFreeMemory ? myData.swapFree : myData.swapUsed) / myData.swapTotal : 0.);
				}
				if (myConfig.bShowNvidia)
				{
					s_fValues[i++] = myData.fGpuTempPercent / 100;
					if (myData.bAlerted && myData.iGPUTemp < myConfig.iAlertLimit)
						myData.bAlerted = FALSE; //On réinitialise l'alerte quand la température descend en dessou de la limite.
					
					if (!myData.bAlerted && myData.iGPUTemp >= myConfig.iAlertLimit)
						cd_nvidia_alert (myApplet);
				}
				CD_APPLET_RENDER_NEW_DATA_ON_MY_ICON (s_fValues);
			}
		}
	}
	return myData.bAcquisitionOK;
}