static gboolean _render_step_opengl (Icon *pIcon, GldiModuleInstance *myApplet)
{
    g_return_val_if_fail (myData.pCurrentImage != NULL, FALSE);
    CD_APPLET_ENTER;
    double f = CD_APPLET_GET_TRANSITION_FRACTION ();

    int iWidth, iHeight;
    CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);

    _cairo_dock_enable_texture ();
    _cairo_dock_set_blend_alpha ();

    // image precedente.
    if (myData.pOldImage != NULL)
    {
        _cairo_dock_set_alpha (1. - f);
        cairo_dock_apply_image_buffer_texture_with_offset (myData.pOldImage, 0, 0);
    }

    // image courante.
    if (myData.pCurrentImage != NULL)
    {
        _cairo_dock_set_alpha (f);
        cairo_dock_apply_image_buffer_texture_with_offset (myData.pCurrentImage, 0, 0);
    }

    _cairo_dock_disable_texture ();

    CD_APPLET_LEAVE (TRUE);
}
static gboolean _render_step_cairo (Icon *pIcon, GldiModuleInstance *myApplet)
{
    CD_APPLET_ENTER;
    double f = CD_APPLET_GET_TRANSITION_FRACTION ();

    int iWidth, iHeight;
    CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
    CD_APPLET_LEAVE_IF_FAIL (iHeight != 0, TRUE);

    CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN_CAIRO (FALSE);

    // image precedente.
    if (myData.pOldImage != NULL)
    {
        cairo_dock_apply_image_buffer_surface_with_offset (myData.pOldImage, myDrawContext, 0, 0, 1. - f);
    }

    // image courante.
    if (myData.pCurrentImage != NULL)
    {
        int x = (iWidth - myData.pCurrentImage->iWidth) / 2;
        int y = (iHeight - myData.pCurrentImage->iHeight) / 2;
        cairo_dock_apply_image_buffer_surface_with_offset (myData.pCurrentImage, myDrawContext, x, y, f);
    }

    CD_APPLET_FINISH_DRAWING_MY_ICON_CAIRO;
    CD_APPLET_LEAVE (TRUE);
}
void cd_opengl_render_to_texture (CairoDockModuleInstance *myApplet)
{
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
	
	CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN ();
	
	cd_opengl_scene (myApplet, iWidth, iHeight);
	
	CD_APPLET_FINISH_DRAWING_MY_ICON;
}
void cd_clock_load_textures (CairoDockModuleInstance *myApplet)
{
    if (myData.pBackgroundSurface != NULL)
        myData.iBgTexture = cairo_dock_create_texture_from_surface (myData.pBackgroundSurface);
    if (myData.pForegroundSurface != NULL)
        myData.iFgTexture = cairo_dock_create_texture_from_surface (myData.pForegroundSurface);

    int iWidth, iHeight;
    CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);

    int iSize = MIN (iWidth, iHeight);
    myData.fNeedleScale = (double) iSize / (double) myData.needleDimension.width;  // car l'aiguille est a l'horizontale dans le fichier svg.
    myData.iNeedleWidth = (double) myData.iNeedleRealWidth * myData.fNeedleScale;
    myData.iNeedleHeight = (double) myData.iNeedleRealHeight * myData.fNeedleScale;

    cairo_surface_t *pNeedleSurface = create_needle_surface (myApplet,
                                      myDrawContext,
                                      KIND_HOUR);
    if (pNeedleSurface != NULL)
    {
        myData.iHourNeedleTexture = cairo_dock_create_texture_from_surface (pNeedleSurface);
        cairo_surface_destroy (pNeedleSurface);
    }

    pNeedleSurface = create_needle_surface (myApplet,
                                            myDrawContext,
                                            KIND_MINUTE);
    if (pNeedleSurface != NULL)
    {
        myData.iMinuteNeedleTexture = cairo_dock_create_texture_from_surface (pNeedleSurface);
        cairo_surface_destroy (pNeedleSurface);
    }

    pNeedleSurface = create_needle_surface (myApplet,
                                            myDrawContext,
                                            KIND_SECOND);
    if (pNeedleSurface != NULL)
    {
        myData.iSecondNeedleTexture = cairo_dock_create_texture_from_surface (pNeedleSurface);
        cairo_surface_destroy (pNeedleSurface);
    }
}
void cd_clock_load_back_and_fore_ground (GldiModuleInstance *myApplet)
{
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);

	//\_______________ On construit les surfaces d'arriere-plan et d'avant-plan une bonne fois pour toutes.
	if (myConfig.bOldStyle)
	{
		myData.pBackgroundSurface = cd_clock_create_bg_surface (myApplet,
			iWidth,
			iHeight,
			KIND_BACKGROUND);
		myData.pForegroundSurface = cd_clock_create_bg_surface (myApplet,
			iWidth,
			iHeight,
			KIND_FOREGROUND);
	}
	else if (myConfig.cNumericBackgroundImage != NULL)
	{
		myData.pNumericBgSurface = CD_APPLET_LOAD_SURFACE_FOR_MY_APPLET (myConfig.cNumericBackgroundImage);
	}
}
void cd_switcher_draw_main_icon_expanded_mode (void)
{
	// definition des parametres de dessin.
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
	//double fRatio = (myDock ? myDock->fRatio : 1.);
	//double fMaxScale = cairo_dock_get_max_scale (myContainer); //coefficient Max icone Width
	myData.switcher.fOneViewportHeight = (iHeight - 2 * myConfig.iLineSize - (myData.switcher.iNbLines - 1) * myConfig.iInLineSize) / myData.switcher.iNbLines; //hauteur d'un bureau/viewport sans compter les lignes exterieures et interieures.
	myData.switcher.fOneViewportWidth = (iWidth - 2 * myConfig.iLineSize - (myData.switcher.iNbColumns - 1) * myConfig.iInLineSize) / myData.switcher.iNbColumns; //largeur d'un bureau/viewport sans compter les lignes exterieures et interieures.

	cairo_surface_t *pSurface = NULL;
	double fZoomX, fZoomY;
	if (myConfig.bMapWallpaper)
	{
		cairo_dock_erase_cairo_context (myDrawContext);
		
		pSurface = cairo_dock_get_desktop_bg_surface ();
		fZoomX = 1. * iWidth / g_iXScreenWidth[CAIRO_DOCK_HORIZONTAL];
		fZoomY= 1. * iHeight / g_iXScreenHeight[CAIRO_DOCK_HORIZONTAL];
		cairo_translate (myDrawContext,
			0.,
			0.);

		cairo_save (myDrawContext);
		cairo_scale (myDrawContext,
			fZoomX ,
			fZoomY );
		cairo_set_source_surface (myDrawContext,
			pSurface,
			0.,
			0.);
		cairo_paint(myDrawContext);
		cairo_restore (myDrawContext);
		
		if (CD_APPLET_MY_CONTAINER_IS_OPENGL)
			cairo_dock_update_icon_texture (myIcon);
		else
			CD_APPLET_UPDATE_REFLECT_ON_MY_ICON;
	}
	else
	{
		CD_APPLET_SET_LOCAL_IMAGE_ON_MY_ICON (MY_APPLET_ICON_FILE);
	}

	if (myConfig.bDrawWindows)
	{
		GList *pWindowList = cairo_dock_get_current_applis_list ();
		pWindowList = g_list_sort (pWindowList, (GCompareFunc) _compare_icons_stack_order);
		
		//fMaxScale = (myIcon->pSubDock != NULL ? cairo_dock_get_max_scale (myIcon->pSubDock) : 1);
		//fRatio = (myIcon->pSubDock != NULL ? myIcon->pSubDock->fRatio : 1);
		gint data[6];
		int iNumDesktop=0, iNumViewportX=0, iNumViewportY=0;
		cairo_t *pCairoContext;
		Icon *pIcon;
		CairoContainer *pContainer = CD_APPLET_MY_ICONS_LIST_CONTAINER;
		GList *pIconsList = CD_APPLET_MY_ICONS_LIST;
		GList *ic;
		for (ic = pIconsList; ic != NULL; ic = ic->next)
		{
			pIcon = ic->data;
			cairo_dock_get_icon_extent (pIcon, pContainer, &iWidth, &iHeight);
			
			data[0] = iNumDesktop;
			data[1] = iNumViewportX;
			data[2] = iNumViewportY;
			data[3] = iWidth;
			data[4] = iHeight;
			pCairoContext = cairo_create (pIcon->pIconBuffer);
			data[5] = GPOINTER_TO_INT (pCairoContext);
			cairo_set_line_width (pCairoContext, 1.);
			cairo_set_source_rgba (pCairoContext, myConfig.RGBWLineColors[0], myConfig.RGBWLineColors[1], myConfig.RGBWLineColors[2], myConfig.RGBWLineColors[3]);
		
			g_list_foreach (pWindowList, (GFunc) _cd_switcher_draw_windows_on_viewport, data);
			
			iNumViewportX ++;
			if (iNumViewportX == g_iNbViewportX)
			{
				iNumViewportY ++;
				if (iNumViewportY == g_iNbViewportY)
					iNumDesktop ++;
			}
			cairo_destroy (pCairoContext);
		}
		g_list_free (pWindowList);  // le contenu appartient a la hash table, mais pas la liste.
	}
}
void cd_switcher_draw_main_icon_compact_mode (void)
{
	//cd_debug ("%s (%d;%d)", __func__, myData.switcher.iCurrentLine, myData.switcher.iCurrentColumn);
	// On efface l'icone.
	cairo_dock_erase_cairo_context (myDrawContext);
	
	// definition des parametres de dessin.
	//double fRatio = (myDock ? myDock->fRatio : 1.);
	//double fMaxScale = cairo_dock_get_max_scale (myContainer); //coefficient Max icone Width
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
	myData.switcher.fOneViewportHeight = (iHeight - 2 * myConfig.iLineSize - (myData.switcher.iNbLines - 1) * myConfig.iInLineSize) / myData.switcher.iNbLines; //hauteur d'un bureau/viewport sans compter les lignes exterieures et interieures.
	myData.switcher.fOneViewportWidth = (iWidth - 2 * myConfig.iLineSize - (myData.switcher.iNbColumns - 1) * myConfig.iInLineSize) / myData.switcher.iNbColumns; //largeur d'un bureau/viewport sans compter les lignes exterieures et interieures.
	
	cairo_surface_t *pSurface = NULL;
	double fZoomX, fZoomY;
	if (myConfig.bMapWallpaper)
	{
		pSurface = cairo_dock_get_desktop_bg_surface ();
		fZoomX = (double) myData.switcher.fOneViewportWidth / g_iXScreenWidth[CAIRO_DOCK_HORIZONTAL];
		fZoomY= (double) myData.switcher.fOneViewportHeight / g_iXScreenHeight[CAIRO_DOCK_HORIZONTAL];
	}
	if (pSurface == NULL)
	{
		pSurface = myData.pDefaultMapSurface;
		fZoomX = (double) myData.switcher.fOneViewportWidth / iWidth;
		fZoomY = (double) myData.switcher.fOneViewportHeight / iHeight;
	}
	
	// cadre exterieur.
	cairo_set_line_width (myDrawContext,myConfig.iLineSize);
	cairo_set_source_rgba(myDrawContext,myConfig.RGBLineColors[0],myConfig.RGBLineColors[1],myConfig.RGBLineColors[2],myConfig.RGBLineColors[3]);
	cairo_rectangle(myDrawContext,
		.5*myConfig.iLineSize,
		.5*myConfig.iLineSize,
		iWidth - myConfig.iLineSize,
		iHeight - myConfig.iLineSize);

	cairo_stroke (myDrawContext);
	
	// lignes interieures.
	cairo_set_line_width (myDrawContext,myConfig.iInLineSize);
	cairo_set_source_rgba(myDrawContext,myConfig.RGBInLineColors[0],myConfig.RGBInLineColors[1],myConfig.RGBInLineColors[2],myConfig.RGBInLineColors[3]);
	double xi, yj;
	int i, j;
	for (i = 1; i < myData.switcher.iNbColumns; i ++)  // lignes verticales.
	{
		xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
		cairo_move_to (myDrawContext, xi, myConfig.iLineSize);
		cairo_rel_line_to (myDrawContext, 0, iHeight - 2*myConfig.iLineSize);
		cairo_stroke (myDrawContext);
	}
	for (j = 1; j < myData.switcher.iNbLines; j ++)  // lignes horizontales.
	{
		yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
		cairo_move_to (myDrawContext, myConfig.iLineSize, yj);
		cairo_rel_line_to (myDrawContext, iWidth - 2*myConfig.iLineSize, 0);
		cairo_stroke (myDrawContext);
	}
	
	GList *pWindowList = NULL;
	if (myConfig.bDrawWindows)
	{
		pWindowList = cairo_dock_get_current_applis_list ();
		pWindowList = g_list_sort (pWindowList, (GCompareFunc) _compare_icons_stack_order);
	}
	
	// chaque bureau/viewport.
	int iNumDesktop=0, iNumViewportX=0, iNumViewportY=0;
	int k = 0, N = g_iNbDesktops * g_iNbViewportX * g_iNbViewportY;
	for (j = 0; j < myData.switcher.iNbLines; j ++)
	{
		for (i = 0; i < myData.switcher.iNbColumns; i ++)
		{
			cairo_save (myDrawContext);

			xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize);
			yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize);

			cairo_translate (myDrawContext,
				xi,
				yj);

			cairo_scale (myDrawContext,
				fZoomX,
				fZoomY);
			cairo_set_source_surface (myDrawContext,
				pSurface,
				0.,
				0.);
			cairo_paint(myDrawContext);
			
			cairo_restore (myDrawContext);
			
			if (myConfig.iDrawCurrentDesktopMode == SWICTHER_FILL_INVERTED && (i != myData.switcher.iCurrentColumn || j != myData.switcher.iCurrentLine))
			{
				cairo_save (myDrawContext);
				
				cairo_set_source_rgba (myDrawContext, myConfig.RGBIndColors[0], myConfig.RGBIndColors[1], myConfig.RGBIndColors[2], myConfig.RGBIndColors[3]);
				cairo_rectangle(myDrawContext,
					xi - .5*myConfig.iLineSize,
					yj - .5*myConfig.iLineSize,
					myData.switcher.fOneViewportWidth + myConfig.iLineSize,
					myData.switcher.fOneViewportHeight + myConfig.iLineSize);
				cairo_fill (myDrawContext);
				
				cairo_restore (myDrawContext);
			}
			
			if (myConfig.bDrawWindows)
			{
				cairo_save (myDrawContext);
				
				cairo_translate (myDrawContext,
					xi,
					yj);
				cairo_set_line_width (myDrawContext, 1.);
				cairo_rectangle (myDrawContext,
					0.,
					0.,
					myData.switcher.fOneViewportWidth,
					myData.switcher.fOneViewportHeight);
				cairo_clip (myDrawContext);
				
				//g_print (" dessin des fenetres du bureau (%d;%d;%d) ...\n", iNumDesktop, iNumViewportX, iNumViewportY);
				gint data[6] = {iNumDesktop, iNumViewportX, iNumViewportY, (int) myData.switcher.fOneViewportWidth, (int) myData.switcher.fOneViewportHeight, GPOINTER_TO_INT (myDrawContext)};
				g_list_foreach (pWindowList, (GFunc) _cd_switcher_draw_windows_on_viewport, data);
				
				cairo_restore (myDrawContext);
			}
			
			iNumViewportX ++;
			if (iNumViewportX == g_iNbViewportX)
			{
				iNumViewportY ++;
				if (iNumViewportY == g_iNbViewportY)
					iNumDesktop ++;
			}
			k ++;
			if (k == N)
				break ;
		}
	}
	
	// dessin de l'indicateur sur le bureau courant (on le fait maintenant car dans le cas ou la ligne interieure est plus petite que la ligne de l'indicateur, les surfaces suivantes recouvreraient en partie la ligne.
	if (myConfig.iDrawCurrentDesktopMode != SWICTHER_FILL_INVERTED)
	{
		i = myData.switcher.iCurrentColumn;
		j = myData.switcher.iCurrentLine;
		xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize);
		yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize);
		
		cairo_set_line_width (myDrawContext,myConfig.iLineSize);
		cairo_set_source_rgba (myDrawContext,myConfig.RGBIndColors[0],myConfig.RGBIndColors[1],myConfig.RGBIndColors[2],myConfig.RGBIndColors[3]);
		cairo_rectangle(myDrawContext,
			xi - .5*myConfig.iLineSize,
			yj - .5*myConfig.iLineSize,
			myData.switcher.fOneViewportWidth + myConfig.iLineSize,
			myData.switcher.fOneViewportHeight + myConfig.iLineSize);
		
		if (myConfig.iDrawCurrentDesktopMode == SWICTHER_FILL)
			cairo_fill (myDrawContext);
		else
			cairo_stroke(myDrawContext);
	}
	
	g_list_free (pWindowList);  // le contenu appartient a la hash table, mais pas la liste.
	
	if (CD_APPLET_MY_CONTAINER_IS_OPENGL)
		cairo_dock_update_icon_texture (myIcon);
	else
		CD_APPLET_UPDATE_REFLECT_ON_MY_ICON;
}
static gchar *_make_screenshot (gboolean bActiveWindow, const gchar *cFolder, const gchar *cFileName)
{
    // create a surface that points on the root window.
    Display *display = gdk_x11_get_default_xdisplay ();
    Screen *screen = XDefaultScreenOfDisplay (display);
    Visual *visual = DefaultVisualOfScreen (screen);
    int w, h;
    Window Xid;
    if (bActiveWindow)
    {
        GldiWindowActor *pActiveWindow = gldi_windows_get_active ();
        Xid = gldi_window_get_id (pActiveWindow);  // cairo_dock_get_active_xwindow ()
        Window root_return;
        int x_return=1, y_return=1;
        unsigned int width_return, height_return, border_width_return, depth_return;
        XGetGeometry (display, Xid,
                      &root_return,
                      &x_return, &y_return,
                      &width_return, &height_return,
                      &border_width_return, &depth_return);  // we can't use the data from the WindowActor, because it takes into account the window border.
        w = width_return;
        h = height_return;
    }
    else
    {
        Xid = DefaultRootWindow (display);
        w = g_desktopGeometry.Xscreen.width;
        h = g_desktopGeometry.Xscreen.height;
    }
    cairo_surface_t *s = cairo_xlib_surface_create (display,
                         Xid,
                         visual,
                         w, h);

    gchar *cName = NULL;
    if (s)
    {
        // save the surface on the disk
        cName = _make_image_name (cFolder, cFileName);
        cairo_surface_write_to_png (s, cName);

        // apply the surface on the icon, with a transition.
        int iWidth, iHeight;
        CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);

        cairo_dock_free_image_buffer (myData.pCurrentImage);
        myData.pCurrentImage = g_new0 (CairoDockImageBuffer, 1);
        double ratio = MIN ((double)iWidth / w, (double)iHeight / h);  // keep ratio.
        int w0 = w * ratio;
        int h0 = h * ratio;
        cairo_surface_t *pSurface = cairo_dock_duplicate_surface (s,
                                    w, h,
                                    w0, h0);  // we must duplicate the surface, because it's an Xlib surface, not a data surface (plus it's way too large anyway).
        cairo_dock_load_image_buffer_from_surface (myData.pCurrentImage, pSurface, w0, h0);

        cairo_dock_free_image_buffer (myData.pOldImage);
        myData.pOldImage = cairo_dock_create_image_buffer (myIcon->cFileName, iWidth, iHeight, 0);  // maybe we could use the current icon image ...

        CD_APPLET_SET_TRANSITION_ON_MY_ICON (_render_step_cairo,
                                             _render_step_opengl,
                                             g_bUseOpenGL,  // bFastPace : vite si opengl, lent si cairo.
                                             2000,  // 2s transition
                                             TRUE);  // bRemoveWhenFinished

        cairo_surface_destroy (s);
    }
    return cName;
}
void cd_xkbd_update_icon (const gchar *cGroupName, const gchar *cShortGroupName, gboolean bRedrawSurface)
{
	//g_print ("%s (%s;%s;%d)\n", __func__, cGroupName, cShortGroupName, bRedrawSurface);
	
	if (bRedrawSurface)  // group has changed -> update the icon and label
	{
		if (! cShortGroupName)
		{
			cShortGroupName = myData.cShortGroupName;
		}
		else
		{
			g_free (myData.cShortGroupName);
			myData.cShortGroupName = g_strdup (cShortGroupName);
		}
		if (! cGroupName)
		{
			cGroupName = myData.cGroupName;
		}
		else
		{
			g_free (myData.cGroupName);
			myData.cGroupName = g_strdup (cGroupName);
		}
		
		//\__________________ On sauvegarde l'ancienne surface/texture.
		cairo_dock_free_image_buffer (myData.pOldImage);
		myData.pOldImage = myData.pCurrentImage;
		myData.pCurrentImage = NULL;
		
		//\__________________ On cree la nouvelle surface (la taille du texte peut avoir change).
		int iWidth, iHeight;
		CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
		if (iWidth <= 1 && iHeight <= 1)  // peut arriver au lancement en mode desklet.
		{
			return;
		}
		int w, h;
		cairo_surface_t *pSurface = cairo_dock_create_surface_from_text_full (cShortGroupName,
			&myConfig.textDescription,
			1.,
			0,  /// iWidth
			&w, &h);
		myData.pCurrentImage = g_new0 (CairoDockImageBuffer, 1);
		cairo_dock_load_image_buffer_from_surface (myData.pCurrentImage, pSurface, w, h);
		
		//\__________________ On lance une transition entre ancienne et nouvelle surface/texture, ou on dessine direct.
		if (myConfig.iTransitionDuration != 0 && myData.pOldImage != NULL)
		{
			CD_APPLET_SET_TRANSITION_ON_MY_ICON (cd_xkbd_render_step_cairo,
				cd_xkbd_render_step_opengl,
				g_bUseOpenGL,  // bFastPace : vite si opengl, lent si cairo.
				myConfig.iTransitionDuration,
				TRUE);  // bRemoveWhenFinished
		}
		else
		{
			if (CD_APPLET_MY_CONTAINER_IS_OPENGL)
			{
				CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN ();
				cd_xkbd_render_step_opengl (myIcon, myApplet);	
				CD_APPLET_FINISH_DRAWING_MY_ICON;
			}
			else
			{
				cd_xkbd_render_step_cairo (myIcon, myApplet);
			}
			CD_APPLET_REDRAW_MY_ICON;
		}
		
		//\__________________ update the label.
		CD_APPLET_SET_NAME_FOR_MY_ICON (cGroupName);
	}
	else  // only the indicators have changed -> trigger a redraw event only (overlay update).
	{
		CD_APPLET_REDRAW_MY_ICON;
	}
	
	//\__________________ lock indicators
	if (myConfig.bShowKbdIndicator)
	{
		cd_debug ("XKBD: caps-lock: %d; num-lock: %d", myData.iCurrentIndic & 1, myData.iCurrentIndic & 2);
		if (myData.iCurrentIndic & 1)  // caps-lock
		{
			if (! (myData.iPreviousIndic & 1)) // TODO: cairo_dock_search_icon_s_path in init? or here the first time (save to data) and reset in reload?
			{
				if (myConfig.cEmblemCapsLock && (myData.cEmblemCapsLock ||
					(myData.cEmblemCapsLock = cairo_dock_search_icon_s_path (myConfig.cEmblemCapsLock, // search for an icon only the first time
						MAX (myIcon->image.iWidth/2, myIcon->image.iHeight/2)))))
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (myData.cEmblemCapsLock, CAIRO_OVERLAY_UPPER_RIGHT);
				else
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/caps-lock.png", CAIRO_OVERLAY_UPPER_RIGHT);
			}
		}
		else
		{
			if (myData.iPreviousIndic & 1)
				CD_APPLET_REMOVE_OVERLAY_ON_MY_ICON (CAIRO_OVERLAY_UPPER_RIGHT);
		}

		if (myData.iCurrentIndic & 2)  // num-lock
		{
			if (! (myData.iPreviousIndic & 2))
			{
				if (myConfig.cEmblemNumLock &&(myData.cEmblemNumLock ||
					(myData.cEmblemNumLock = cairo_dock_search_icon_s_path (myConfig.cEmblemNumLock,
						MAX (myIcon->image.iWidth/2, myIcon->image.iHeight/2)))))
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (myData.cEmblemNumLock, CAIRO_OVERLAY_UPPER_LEFT);
				else
					CD_APPLET_ADD_OVERLAY_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/num-lock.png", CAIRO_OVERLAY_UPPER_LEFT);
			}
		}
		else
		{
			if (myData.iPreviousIndic & 2)
				CD_APPLET_REMOVE_OVERLAY_ON_MY_ICON (CAIRO_OVERLAY_UPPER_LEFT);
		}
		myData.iPreviousIndic = myData.iCurrentIndic;
	}
}
gboolean cd_xkbd_render_step_cairo (Icon *pIcon, GldiModuleInstance *myApplet)
{
	CD_APPLET_ENTER;
	double f = CD_APPLET_GET_TRANSITION_FRACTION ();
	
	//g_print ("%s (%.2f)\n", __func__, f);
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
	CD_APPLET_LEAVE_IF_FAIL (iHeight != 0, TRUE);
	
	///cairo_dock_erase_cairo_context (myDrawContext);
	CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN_CAIRO (FALSE);

	if (myData.bgImage.pSurface != NULL)
	{
		cairo_set_source_surface (
			myDrawContext,
			myData.bgImage.pSurface,
			0.,
			0.);
		cairo_paint (myDrawContext);
	}
	
	double dx, dy, fScale;
	if (myData.pOldImage != NULL && 1-f > .01)
	{
		fScale = (double)iWidth / myData.pOldImage->iWidth;  // scale to fill the icon horizontally
		if (fScale * myData.pOldImage->iHeight > iHeight)  // if the text is too height, scale down
		{
			fScale = (double)iHeight / myData.pOldImage->iHeight;  // that's smaller than the previous value.
		}
		dx = (iWidth - fScale * myData.pOldImage->iWidth)/2;  // center horizontally
		dy = iHeight - fScale * myData.pOldImage->iHeight;  // bottom (we draw the caps/num lock on top).
		
		cairo_save (myDrawContext);
		cairo_translate (myDrawContext, dx, dy);
		cairo_scale (myDrawContext, fScale, fScale);  // keep ratio
		cairo_set_source_surface (
			myDrawContext,
			myData.pOldImage->pSurface,
			0,
			0);
		cairo_paint_with_alpha (myDrawContext, 1-f);
		cairo_restore (myDrawContext);
	}
	
	if (myData.pCurrentImage != NULL)
	{
		fScale = (double)iWidth / myData.pCurrentImage->iWidth;  // scale to fill the icon horizontally
		if (fScale * myData.pCurrentImage->iHeight > iHeight)  // if the text is too height, scale down
		{
			fScale = (double)iHeight / myData.pCurrentImage->iHeight;  // that's smaller than the previous value.
		}
		dx = (iWidth - fScale * myData.pCurrentImage->iWidth)/2;  // center horizontally
		dy = iHeight - fScale * myData.pCurrentImage->iHeight;  // bottom (we draw the caps/num lock on top).
		
		cairo_save (myDrawContext);
		cairo_translate (myDrawContext, dx, dy);
		cairo_scale (myDrawContext, fScale, fScale);  // keep ratio
		cairo_set_source_surface (
			myDrawContext,
			myData.pCurrentImage->pSurface,
			0,
			0);
		cairo_paint_with_alpha (myDrawContext, f);
		cairo_restore (myDrawContext);
	}
	
	CD_APPLET_FINISH_DRAWING_MY_ICON_CAIRO;
	CD_APPLET_LEAVE (TRUE);
}
gboolean cd_xkbd_render_step_opengl (Icon *pIcon, GldiModuleInstance *myApplet)
{
	g_return_val_if_fail (myData.pCurrentImage != NULL, FALSE);
	CD_APPLET_ENTER;
	double f = CD_APPLET_GET_TRANSITION_FRACTION ();
	cd_debug ("%s (%.2f; %.2fx%.2f)", __func__, f, myIcon->fWidth, myIcon->fHeight);
	
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
	
	gldi_gl_container_set_perspective_view_for_icon (myIcon);
	glScalef (1., -1., 1.);
	
	_cairo_dock_enable_texture ();
	_cairo_dock_set_blend_alpha ();
	_cairo_dock_set_alpha (1.);
	
	// fond
	if (myData.bgImage.iTexture != 0)
		cairo_dock_apply_texture_at_size (myData.bgImage.iTexture, iWidth, iHeight);
	
	double fTheta = - 45. + f * 90.;  // -45 -> 45
	glTranslatef (0., 0., - iWidth * sqrt(2)/2 * cos (fTheta/180.*G_PI));  // pour faire tenir le cube dans la fenetre.
	glEnable (GL_DEPTH_TEST);
	
	// image precedente.
	int w=0, h;
	if (fTheta < 25 && myData.pOldImage != NULL)  // inutile de dessiner si elle est derriere l'image courante, par l'effet de perspective (en fait 22.5, mais bizarrement ca a l'air un peu trop tot).
	{
		w = iWidth * myConfig.fTextRatio;  // fill horizontally
		h = myData.pOldImage->iHeight * (double)w/myData.pOldImage->iWidth;  // keep ratio
		if (h > iHeight * myConfig.fTextRatio)
		{
			w *= iHeight * myConfig.fTextRatio / h;
			h = iHeight * myConfig.fTextRatio;
		}
		
		glPushMatrix ();
		glRotatef (45. + fTheta, 0., 1., 0.);  // 0 -> 90
		glTranslatef (0., (-iHeight + h)/2, w/2);  // H center, V bottom
		cairo_dock_apply_texture_at_size (myData.pOldImage->iTexture, w, h);
		glPopMatrix ();
	}
	
	// image courante a 90deg.
	w = iWidth * myConfig.fTextRatio;  // fill horizontally
	h = myData.pCurrentImage->iHeight * (double)w/myData.pCurrentImage->iWidth;  // keep ratio
	if (h > iHeight * myConfig.fTextRatio)
	{
		w *= iHeight * myConfig.fTextRatio / h;
		h = iHeight * myConfig.fTextRatio;
	}

	/**glRotatef (45. + fTheta, 0., 1., 0.);  // 0 -> 90
	glTranslatef (- (w ? w : iWidth)/2, 0., 0.);
	glRotatef (-90., 0., 1., 0.);*/
	glRotatef (-45. + fTheta, 0., 1., 0.);  // -90 -> 0
	glTranslatef (0., (-iHeight + h)/2, w/2);  // H center, V bottom
	cairo_dock_apply_texture_at_size (myData.pCurrentImage->iTexture, w, h);
	
	glDisable (GL_DEPTH_TEST);
	_cairo_dock_disable_texture ();
	
	if (myDock)
	{
		gldi_gl_container_set_ortho_view (myContainer);
	}
	
	CD_APPLET_LEAVE (TRUE);
}
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);
}
gboolean cd_opengl_load_3D_theme (CairoDockModuleInstance *myApplet, gchar *cThemePath)
{
	gchar *cImageName;
	cairo_surface_t *pSurface;
	gchar *cConfFilePath = g_strdup_printf ("%s/%s", cThemePath, "theme.conf");
	GKeyFile *pKeyFile = cairo_dock_open_key_file (cConfFilePath);
	g_free (cConfFilePath);
	if (pKeyFile == NULL)
		return FALSE;
	
	gchar *cThemePathUpToDate = NULL;
	gint iVersion = g_key_file_get_integer (pKeyFile, "Description", "Version", NULL);
	if (iVersion != 2)
	{
		/// effacer le theme et le recuperer sur le serveur...
		g_print ("theme en version inferieure => sera mis a jour...\n");
		// on ferme la config de l'actuel theme.
		g_key_file_free (pKeyFile);
		pKeyFile = NULL;
		
		// on supprime le theme.
		g_return_val_if_fail (cThemePath && *cThemePath == '/', FALSE);
		gchar *cCommand = g_strdup_printf ("rm -rf '%s'", cThemePath);
		int r = system (cCommand);
		g_free (cCommand);
		
		// on recupere le theme distant.
		pKeyFile = cairo_dock_open_key_file (myApplet->cConfFilePath);
		if (pKeyFile != NULL)
		{
			gboolean bFlushConfFileNeeded = FALSE;
			cThemePathUpToDate = CD_CONFIG_GET_THEME_PATH ("Configuration", "theme", "themes", "cd_box_simple");
			cThemePath = cThemePathUpToDate;
			g_key_file_free (pKeyFile);
			pKeyFile = NULL;
			
			// on ouvre la config du nouveau theme.
			cConfFilePath = g_strdup_printf ("%s/%s", cThemePath, "theme.conf");
			pKeyFile = cairo_dock_open_key_file (cConfFilePath);
			g_free (cConfFilePath);
			if (pKeyFile == NULL)
				return FALSE;
		}
		g_return_val_if_fail (pKeyFile != NULL, FALSE);
	}
	
	GError *erreur = NULL;
	GString *sImagePath = g_string_new ("");	
	
	//\_______________ les images d'avant et arriere plan.
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
	double fImageWidth, fImageHeight;  // dimensions de la surface generee.
	double fZoomX=1, fZoomY=1;  // facteur de zoom qui lui a ete applique.
	
	cImageName = g_key_file_get_string (pKeyFile, "Pictures", "frame", &erreur);
	_check_error(erreur);
	if (cImageName != NULL)
	{
		g_string_printf (sImagePath, "%s/%s", cThemePath, cImageName);
		pSurface = cairo_dock_create_surface_from_image (sImagePath->str,
			myDrawContext,
			1.,
			iWidth, iHeight,
			CAIRO_DOCK_FILL_SPACE,
			&fImageWidth, &fImageHeight,
			&fZoomX, &fZoomY);
		
		myData.TextureFrame = cairo_dock_create_texture_from_surface (pSurface);
		cairo_surface_destroy (pSurface);
		g_free (cImageName);
	}
	
	cImageName = g_key_file_get_string (pKeyFile, "Pictures", "reflect", &erreur);
	_check_error(erreur);
	if (cImageName != NULL)
	{
		g_string_printf (sImagePath, "%s/%s", cThemePath, cImageName);
		pSurface = cairo_dock_create_surface_from_image (sImagePath->str,
			myDrawContext,
			1.,
			iWidth, iHeight,
			CAIRO_DOCK_FILL_SPACE,
			&fImageWidth, &fImageHeight,
			NULL, NULL);
		
		myData.TextureReflect = cairo_dock_create_texture_from_surface (pSurface);
		cairo_surface_destroy (pSurface);
		g_free (cImageName);
	}
	
	//\_______________ les coordonnees des 4 coins de la pochette
	// dans le referentiel du cadre (directement obtenues avec Gimp) => dans le referentiel de l'icone iWidth x iHeight.
	myData.itopleftX = g_key_file_get_integer (pKeyFile, "Configuration", "topleftX", &erreur) * fZoomX;
	_check_error(erreur);
	myData.itopleftY = g_key_file_get_integer (pKeyFile, "Configuration", "topleftY", &erreur) * fZoomY;
	_check_error(erreur);
	
	myData.ibottomleftX = g_key_file_get_integer (pKeyFile, "Configuration", "bottomleftX", &erreur) * fZoomX;
	_check_error(erreur);
	myData.ibottomleftY = g_key_file_get_integer (pKeyFile, "Configuration", "bottomleftY", &erreur) * fZoomY;
	_check_error(erreur);
	
	myData.ibottomrightX = g_key_file_get_integer (pKeyFile, "Configuration", "bottomrightX", &erreur) * fZoomX;
	_check_error(erreur);
	myData.ibottomrightY = g_key_file_get_integer (pKeyFile, "Configuration", "bottomrightY", &erreur) * fZoomY;
	_check_error(erreur);
	
	myData.itoprightX = g_key_file_get_integer (pKeyFile, "Configuration", "toprightX", &erreur) * fZoomX;
	_check_error(erreur);
	myData.itoprightY = g_key_file_get_integer (pKeyFile, "Configuration", "toprightY", &erreur) * fZoomY;
	_check_error(erreur);			
	
	//\_______________ On definit la calllist qui déforme la pochette.
	myData.draw_cover = glGenLists(1);
	glNewList(myData.draw_cover , GL_COMPILE);
	glBegin(GL_QUADS);
	glTexCoord2d (0,0);
	glVertex3f (-.5 + myData.itopleftX / iWidth,		+.5 - myData.itopleftY / iHeight,		0);
	glTexCoord2d (0,1);
	glVertex3f (-.5 + myData.ibottomleftX / iWidth,		+.5 - myData.ibottomleftY /iHeight,		0.);
	glTexCoord2d (1,1);
	glVertex3f (-.5 + myData.ibottomrightX / iWidth,	+.5 - myData.ibottomrightY / iHeight,	0.);
	glTexCoord2d (1,0);
	glVertex3f (-.5 + myData.itoprightX / iWidth,		+.5 - myData.itoprightY / iHeight,		0.);
	glEnd();
	glEndList();
	
	//\_______________ les zones cliquables et l'OSD.
	myData.numberButtons = g_key_file_get_integer (pKeyFile, "Buttons", "number", NULL);
	if (myData.numberButtons != 0)
	{
		myData.osd = g_key_file_get_boolean (pKeyFile, "Buttons", "osd", &erreur);
		_check_error(erreur);
		
		// Bouton 1
		myData.button1sizeX = g_key_file_get_integer (pKeyFile, "Button1", "sizeX", &erreur) * fZoomX;
		_check_error(erreur);
		myData.button1sizeY = g_key_file_get_integer (pKeyFile, "Button1", "sizeY", &erreur) * fZoomY;
		_check_error(erreur);
		myData.button1coordX = g_key_file_get_integer (pKeyFile, "Button1", "X", &erreur) * fZoomX + myData.button1sizeX/2;  // on se ramene au centre.
		_check_error(erreur);
		myData.button1coordY = g_key_file_get_integer (pKeyFile, "Button1", "Y", &erreur) * fZoomY + myData.button1sizeY/2;  // on se ramene au centre.
		_check_error(erreur);
		
		_make_texture_at_size (myData.TextureButton1, "Button1", "picture", myData.button1sizeX, myData.button1sizeY);
		
		if (myData.osd)
		{
			myData.osdPlaysizeX = g_key_file_get_integer (pKeyFile, "Button1", "osd play sizeX", &erreur) * fZoomX;
			_check_error(erreur);
			myData.osdPlaysizeY = g_key_file_get_integer (pKeyFile, "Button1", "osd play sizeY", &erreur) * fZoomY;
			_check_error(erreur);
			myData.osdPlaycoordX = g_key_file_get_integer (pKeyFile, "Button1", "osd play X", &erreur) * fZoomX + myData.osdPlaysizeX/2;
			_check_error(erreur);
			myData.osdPlaycoordY = g_key_file_get_integer (pKeyFile, "Button1", "osd play Y", &erreur) * fZoomY + myData.osdPlaysizeY/2;
			_check_error(erreur);
			_make_texture_at_size (myData.TextureOsdPlay, "Button1", "osd_play", myData.osdPlaysizeX, myData.osdPlaysizeY);

			myData.osdPausesizeX = g_key_file_get_integer (pKeyFile, "Button1", "osd pause sizeX", &erreur) * fZoomX;
			_check_error(erreur);
			myData.osdPausesizeY = g_key_file_get_integer (pKeyFile, "Button1", "osd pause sizeY", &erreur) * fZoomY;
			_check_error(erreur);
			myData.osdPausecoordX = g_key_file_get_integer (pKeyFile, "Button1", "osd pause X", &erreur) * fZoomX + myData.osdPausesizeX/2;
			_check_error(erreur);
			myData.osdPausecoordY = g_key_file_get_integer (pKeyFile, "Button1", "osd pause Y", &erreur) * fZoomY + myData.osdPausesizeY/2;
			_check_error(erreur);
			_make_texture_at_size (myData.TextureOsdPause, "Button1", "osd_pause", myData.osdPausesizeX, myData.osdPausesizeY);			
		}
		
		// Bouton 4
		if (myData.numberButtons > 3)
		{
			_check_error(erreur);
			myData.button4sizeX = g_key_file_get_integer (pKeyFile, "Button4", "sizeX", &erreur) * fZoomX;
			_check_error(erreur);
			myData.button4sizeY = g_key_file_get_integer (pKeyFile, "Button4", "sizeY", &erreur) * fZoomY;
			_check_error(erreur);
			myData.button4coordX = g_key_file_get_integer (pKeyFile, "Button4", "X", &erreur) * fZoomX + myData.button4sizeX/2;
			_check_error(erreur);
			myData.button4coordY = g_key_file_get_integer (pKeyFile, "Button4", "Y", &erreur) * fZoomY + myData.button4sizeY/2;
			
			_make_texture_at_size (myData.TextureButton4, "Button4", "picture", myData.button4sizeX, myData.button4sizeY);
			
			if (myData.osd)
			{
				myData.osdHomesizeX = g_key_file_get_integer (pKeyFile, "Button4", "osd sizeX", &erreur) * fZoomX;
				_check_error(erreur);
				myData.osdHomesizeY = g_key_file_get_integer (pKeyFile, "Button4", "osd sizeY", &erreur) * fZoomY;
				_check_error(erreur);
				myData.osdHomecoordX = g_key_file_get_integer (pKeyFile, "Button4", "osd X", &erreur) * fZoomX + myData.osdHomesizeX/2;
				_check_error(erreur);
				myData.osdHomecoordY = g_key_file_get_integer (pKeyFile, "Button4", "osd Y", &erreur) * fZoomY + myData.osdHomesizeY/2;
				_check_error(erreur);
				_make_texture_at_size (myData.TextureOsdHome, "Button4", "osd", myData.osdHomesizeX, myData.osdHomesizeY);
			}
		}
		
		// Bouton 3
		if (myData.numberButtons > 2)
		{
			myData.button3sizeX = g_key_file_get_integer (pKeyFile, "Button3", "sizeX", &erreur) * fZoomX;
			_check_error(erreur);
			myData.button3sizeY = g_key_file_get_integer (pKeyFile, "Button3", "sizeY", &erreur) * fZoomY;
			_check_error(erreur);
			myData.button3coordX = g_key_file_get_integer (pKeyFile, "Button3", "X", &erreur) * fZoomX + myData.button3sizeX/2;
			_check_error(erreur);
			myData.button3coordY = g_key_file_get_integer (pKeyFile, "Button3", "Y", &erreur) * fZoomY + myData.button3sizeY/2;
			_check_error(erreur);
			
			_make_texture_at_size (myData.TextureButton3, "Button3", "picture", myData.button3sizeX, myData.button3sizeY);
			
			if (myData.osd)
			{
				myData.osdNextsizeX = g_key_file_get_integer (pKeyFile, "Button3", "osd sizeX", &erreur) * fZoomX;
				_check_error(erreur);
				myData.osdNextsizeY = g_key_file_get_integer (pKeyFile, "Button3", "osd sizeY", &erreur) * fZoomY;
				_check_error(erreur);
				myData.osdNextcoordX = g_key_file_get_integer (pKeyFile, "Button3", "osd X", &erreur) * fZoomX + myData.osdNextsizeX/2;
				_check_error(erreur);
				myData.osdNextcoordY = g_key_file_get_integer (pKeyFile, "Button3", "osd Y", &erreur) * fZoomY + myData.osdNextsizeY/2;
				_check_error(erreur);
				_make_texture_at_size (myData.TextureOsdNext, "Button3", "osd", myData.osdNextsizeX, myData.osdNextsizeY);
			}
		}
		
		// Bouton 2
		if (myData.numberButtons > 1)
		{
			myData.button2sizeX = g_key_file_get_integer (pKeyFile, "Button2", "sizeX", &erreur) * fZoomX;
			_check_error(erreur);
			myData.button2sizeY = g_key_file_get_integer (pKeyFile, "Button2", "sizeY", &erreur) * fZoomY;
			_check_error(erreur);
			myData.button2coordX = g_key_file_get_integer (pKeyFile, "Button2", "X", &erreur) * fZoomX + myData.button2sizeX/2;
			_check_error(erreur);
			myData.button2coordY = g_key_file_get_integer (pKeyFile, "Button2", "Y", &erreur) * fZoomY + myData.button2sizeY/2;
			_check_error(erreur);
			
			_make_texture_at_size (myData.TextureButton2, "Button2", "picture", myData.button2sizeX, myData.button2sizeY);
			
			if (myData.osd)
			{
				myData.osdPrevsizeX = g_key_file_get_integer (pKeyFile, "Button2", "osd sizeX", &erreur) * fZoomX;
				_check_error(erreur);
				myData.osdPrevsizeY = g_key_file_get_integer (pKeyFile, "Button2", "osd sizeY", &erreur) * fZoomY;
				_check_error(erreur);
				myData.osdPrevcoordX = g_key_file_get_integer (pKeyFile, "Button2", "osd X", &erreur) * fZoomX + myData.osdPrevsizeX/2;
				_check_error(erreur);
				myData.osdPrevcoordY = g_key_file_get_integer (pKeyFile, "Button2", "osd Y", &erreur) * fZoomY + myData.osdPrevsizeY/2;
				_check_error(erreur);
				_make_texture_at_size (myData.TextureOsdPrev, "Button2", "osd", myData.osdPrevsizeX, myData.osdPrevsizeY);
			}
		}
	}
	g_key_file_free (pKeyFile);
	g_free (cThemePathUpToDate);
	return TRUE;
}
static void _set_data_renderer (GldiModuleInstance *myApplet)
{
	if (myConfig.iDisplayType == CD_SYSMONITOR_BAR)
		return; /// TODO

	CairoDataRendererAttribute *pRenderAttr = NULL;  // attributes for the global data-renderer.
	CairoGaugeAttribute aGaugeAttr;  // gauge attributes.
	CairoGraphAttribute aGraphAttr;  // graph attributes.
	double fHighColor[CD_SYSMONITOR_NB_MAX_VALUES*3]; // attributes for the graph
	double fLowColor[CD_SYSMONITOR_NB_MAX_VALUES*3];  // (but have to be declared here to force GCC to keep data)
	int iNbValues = myConfig.bShowCpu + myConfig.bShowRam + myConfig.bShowSwap + myConfig.bShowNvidia + myConfig.bShowCpuTemp + myConfig.bShowFanSpeed;
	if (myConfig.iDisplayType == CD_SYSMONITOR_GAUGE)
	{
		memset (&aGaugeAttr, 0, sizeof (CairoGaugeAttribute));
		pRenderAttr = CAIRO_DATA_RENDERER_ATTRIBUTE (&aGaugeAttr);
		pRenderAttr->cModelName = "gauge";
		pRenderAttr->iRotateTheme = myConfig.iRotateTheme;
		aGaugeAttr.cThemePath = myConfig.cGThemePath;
	}
	else if (myConfig.iDisplayType == CD_SYSMONITOR_GRAPH)
	{
		memset (&aGraphAttr, 0, sizeof (CairoGraphAttribute));
		pRenderAttr = CAIRO_DATA_RENDERER_ATTRIBUTE (&aGraphAttr);
		pRenderAttr->cModelName = "graph";
		int w, h;
		CD_APPLET_GET_MY_ICON_EXTENT (&w, &h);
		pRenderAttr->iMemorySize = (w > 1 ? w : 32);  // fWidth peut etre <= 1 en mode desklet au chargement.
		aGraphAttr.iType = myConfig.iGraphType;
		aGraphAttr.bMixGraphs = myConfig.bMixGraph;
		int i;
		for (i = 0; i < iNbValues; i ++)
		{
			memcpy (&fHighColor[3*i], myConfig.fHigholor, 3*sizeof (double));
			memcpy (&fLowColor[3*i], myConfig.fLowColor, 3*sizeof (double));
		}
		aGraphAttr.fHighColor = fHighColor;
		aGraphAttr.fLowColor = fLowColor;
		memcpy (aGraphAttr.fBackGroundColor, myConfig.fBgColor, 4*sizeof (double));
	}

	pRenderAttr->iLatencyTime = myConfig.iCheckInterval * 1000 * myConfig.fSmoothFactor;
	pRenderAttr->iNbValues = iNbValues;
	if (myConfig.iInfoDisplay == CAIRO_DOCK_INFO_ON_ICON)
	{
		pRenderAttr->bWriteValues = TRUE;
		pRenderAttr->format_value = (CairoDataRendererFormatValueFunc)cd_sysmonitor_format_value;
		pRenderAttr->pFormatData = myApplet;
	}
	const gchar *labels[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
	int i = 0;
	if (myConfig.bShowCpu)
		labels[i++] = "CPU";
	if (myConfig.bShowRam)
		labels[i++] = "RAM";
	if (myConfig.bShowSwap)
		labels[i++] = "SWAP";
	if (myConfig.bShowNvidia)
		labels[i++] = "GPU";
	if (myConfig.bShowCpuTemp)
		labels[i++] = "TEMP";
	if (myConfig.bShowFanSpeed)
		labels[i++] = "FAN";
	pRenderAttr->cLabels = (gchar **)labels;
	CD_APPLET_ADD_DATA_RENDERER_ON_MY_ICON (pRenderAttr);
}
void cd_switcher_draw_main_icon_expanded_mode (void)
{
	// apply the desktop bg or the user image on the main icon, in dock mode
	int iWidth, iHeight;
	
	if (myDock)
	{
		CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
		myData.switcher.fOneViewportHeight = (iHeight - 2 * myConfig.iLineSize - (myData.switcher.iNbLines - 1) * myConfig.iInLineSize) / myData.switcher.iNbLines; //hauteur d'un bureau/viewport sans compter les lignes exterieures et interieures.
		myData.switcher.fOneViewportWidth = (iWidth - 2 * myConfig.iLineSize - (myData.switcher.iNbColumns - 1) * myConfig.iInLineSize) / myData.switcher.iNbColumns; //largeur d'un bureau/viewport sans compter les lignes exterieures et interieures.

		cairo_surface_t *pSurface = NULL;
		double fZoomX, fZoomY;
		if (myConfig.iIconDrawing == SWICTHER_MAP_WALLPAPER)
		{
			cairo_dock_erase_cairo_context (myDrawContext);

			pSurface = myData.pDesktopBgMapSurface;
			fZoomX = 1. * iWidth / myData.iSurfaceWidth;
			fZoomY= 1. * iHeight / myData.iSurfaceHeight;
			cairo_translate (myDrawContext,
				0.,
				0.);

			cairo_save (myDrawContext);
			cairo_scale (myDrawContext,
				fZoomX ,
				fZoomY );
			cairo_set_source_surface (myDrawContext,
				pSurface,
				0.,
				0.);
			cairo_paint(myDrawContext);
			cairo_restore (myDrawContext);

			if (CD_APPLET_MY_CONTAINER_IS_OPENGL)
				cairo_dock_update_icon_texture (myIcon);
		}
		else
		{
			CD_APPLET_SET_IMAGE_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
		}
	}
	
	if (myConfig.bDrawWindows)
	{
		GList *pWindowList = cairo_dock_get_current_applis_list ();
		pWindowList = g_list_sort (pWindowList, (GCompareFunc) _compare_icons_stack_order);
		
		CDSwitcherDesktop data;
		int iNumDesktop=0, iNumViewportX=0, iNumViewportY=0;
		cairo_t *pCairoContext;
		Icon *pIcon;
		GList *pIconsList = CD_APPLET_MY_ICONS_LIST;
		GList *ic;
		for (ic = pIconsList; ic != NULL; ic = ic->next)
		{
			pIcon = ic->data;
			cairo_dock_get_icon_extent (pIcon, &iWidth, &iHeight);
			
			pCairoContext = cairo_create (pIcon->image.pSurface);
			cairo_set_line_width (pCairoContext, 1.);
			if (myConfig.bUseDefaultColors)
				gldi_style_colors_set_line_color (myDrawContext);
			else
				cairo_set_source_rgba (pCairoContext, myConfig.RGBWLineColors[0], myConfig.RGBWLineColors[1], myConfig.RGBWLineColors[2], myConfig.RGBWLineColors[3]);
			
			data.iNumDesktop = iNumDesktop;
			data.iNumViewportX = iNumViewportX;
			data.iNumViewportY = iNumViewportY;
			data.iOneViewportWidth = iWidth;
			data.iOneViewportHeight = iHeight;
			data.pCairoContext = pCairoContext;
			g_list_foreach (pWindowList, (GFunc) _cd_switcher_draw_windows_on_viewport, &data);
			
			iNumViewportX ++;
			if (iNumViewportX == g_desktopGeometry.iNbViewportX)
			{
				iNumViewportY ++;
				if (iNumViewportY == g_desktopGeometry.iNbViewportY)
					iNumDesktop ++;
			}
			cairo_destroy (pCairoContext);
		}
		g_list_free (pWindowList);  // le contenu appartient a la hash table, mais pas la liste.
	}
}
void cd_switcher_draw_main_icon_compact_mode (void)
{
	if (myData.switcher.iNbColumns == 0 || myData.switcher.iNbLines == 0)  // may happen in desklet mode with a cube desktop, when the desklet is still 0x0.
		return;
	CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN_CAIRO ();
	///g_return_if_fail (myDrawContext != NULL);
	//g_print ("%s (%d;%d)\n", __func__, myData.switcher.iCurrentLine, myData.switcher.iCurrentColumn);
	// On efface l'icone.
	///cairo_dock_erase_cairo_context (myDrawContext);
	
	// definition des parametres de dessin.
	int iWidth, iHeight;
	CD_APPLET_GET_MY_ICON_EXTENT (&iWidth, &iHeight);
	
	myData.switcher.fOneViewportHeight = (double) (iHeight - 2 * myConfig.iLineSize - (myData.switcher.iNbLines - 1) * myConfig.iInLineSize) / myData.switcher.iNbLines; //hauteur d'un bureau/viewport sans compter les lignes exterieures et interieures.
	myData.switcher.fOneViewportWidth = (double) (iWidth - 2 * myConfig.iLineSize - (myData.switcher.iNbColumns - 1) * myConfig.iInLineSize) / myData.switcher.iNbColumns; //largeur d'un bureau/viewport sans compter les lignes exterieures et interieures.
	double dx=0, dy=0;
	double w = iWidth, h = iHeight;
	if (myConfig.bPreserveScreenRatio)
	{
		double r = (double) g_desktopGeometry.Xscreen.width / g_desktopGeometry.Xscreen.height;
		double r_ = myData.switcher.fOneViewportWidth / myData.switcher.fOneViewportHeight;
		if (r_ > r)  // on etire trop en largeur.
		{
			myData.switcher.fOneViewportWidth /= r_ / r;
			w = myData.switcher.fOneViewportWidth * myData.switcher.iNbColumns + 2 * myConfig.iLineSize + (myData.switcher.iNbColumns - 1) * myConfig.iInLineSize;
			dx = (double) (iWidth - w) / 2;
		}
		else
		{
			myData.switcher.fOneViewportHeight /= r / r_;
			h = myData.switcher.fOneViewportHeight * myData.switcher.iNbLines + 2 * myConfig.iLineSize + (myData.switcher.iNbLines - 1) * myConfig.iInLineSize;
			dy = (iHeight - h) / 2;
		}
	}
	myData.switcher.fOffsetX = dx;
	myData.switcher.fOffsetY = dy;
	
	cairo_save (myDrawContext);
	cairo_translate (myDrawContext, dx, dy);
	
	cairo_surface_t *pSurface = NULL;
	double fZoomX, fZoomY;
	if (myConfig.iIconDrawing == SWICTHER_MAP_WALLPAPER)
	{
		pSurface = myData.pDesktopBgMapSurface;
	}
	if (pSurface == NULL)
	{
		pSurface = myData.pDefaultMapSurface;
	}
	fZoomX = (double) myData.switcher.fOneViewportWidth / myData.iSurfaceWidth;  // both surfaces are loaded at the same size.
	fZoomY= (double) myData.switcher.fOneViewportHeight / myData.iSurfaceHeight;
	
	// cadre exterieur.
	cairo_set_line_width (myDrawContext,myConfig.iLineSize);
	if (myConfig.bUseDefaultColors)
		gldi_style_colors_set_line_color (myDrawContext);
	else
		cairo_set_source_rgba(myDrawContext,myConfig.RGBLineColors[0],myConfig.RGBLineColors[1],myConfig.RGBLineColors[2],myConfig.RGBLineColors[3]);
	cairo_rectangle(myDrawContext,
		.5*myConfig.iLineSize,
		.5*myConfig.iLineSize,
		w - myConfig.iLineSize,
		h - myConfig.iLineSize);

	cairo_stroke (myDrawContext);
	
	// lignes interieures.
	cairo_set_line_width (myDrawContext,myConfig.iInLineSize);
	if (myConfig.bUseDefaultColors)
		gldi_style_colors_set_line_color (myDrawContext);
	else
		cairo_set_source_rgba (myDrawContext,myConfig.RGBInLineColors[0],myConfig.RGBInLineColors[1],myConfig.RGBInLineColors[2],myConfig.RGBInLineColors[3]);
	double xi, yj;
	int i, j;
	for (i = 1; i < myData.switcher.iNbColumns; i ++)  // lignes verticales.
	{
		xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
		cairo_move_to (myDrawContext, xi, myConfig.iLineSize);
		cairo_rel_line_to (myDrawContext, 0, h - 2*myConfig.iLineSize);
		cairo_stroke (myDrawContext);
	}
	for (j = 1; j < myData.switcher.iNbLines; j ++)  // lignes horizontales.
	{
		yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize) - .5*myConfig.iInLineSize;
		cairo_move_to (myDrawContext, myConfig.iLineSize, yj);
		cairo_rel_line_to (myDrawContext, w - 2*myConfig.iLineSize, 0);
		cairo_stroke (myDrawContext);
	}
	
	GList *pWindowList = NULL;
	if (myConfig.bDrawWindows)
	{
		pWindowList = cairo_dock_get_current_applis_list ();
		pWindowList = g_list_sort (pWindowList, (GCompareFunc) _compare_icons_stack_order);
	}
	
	// chaque bureau/viewport.
	int iNumDesktop=0, iNumViewportX=0, iNumViewportY=0;
	int k = 0, N = g_desktopGeometry.iNbDesktops * g_desktopGeometry.iNbViewportX * g_desktopGeometry.iNbViewportY;
	for (j = 0; j < myData.switcher.iNbLines && k < N; j ++)
	{
		for (i = 0; i < myData.switcher.iNbColumns && k < N; i ++)
		{
			cairo_save (myDrawContext);

			xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize);
			yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize);

			cairo_translate (myDrawContext,
				xi,
				yj);

			cairo_scale (myDrawContext,
				fZoomX,
				fZoomY);
			cairo_set_source_surface (myDrawContext,
				pSurface,
				0.,
				0.);
			cairo_paint(myDrawContext);
			
			cairo_restore (myDrawContext);
			
			if ((myConfig.iDrawCurrentDesktopMode == SWICTHER_FILL_INVERTED && (i != myData.switcher.iCurrentColumn || j != myData.switcher.iCurrentLine))
			|| (myConfig.iDrawCurrentDesktopMode == SWICTHER_FILL && (i == myData.switcher.iCurrentColumn && j == myData.switcher.iCurrentLine)))
			{
				cairo_save (myDrawContext);
				
				if (myConfig.bUseDefaultColors)
					gldi_style_colors_set_selected_bg_color (myDrawContext);
				else
					cairo_set_source_rgba (myDrawContext, myConfig.RGBIndColors[0], myConfig.RGBIndColors[1], myConfig.RGBIndColors[2], myConfig.RGBIndColors[3]);
				cairo_rectangle(myDrawContext,
					xi - .5*myConfig.iLineSize,
					yj - .5*myConfig.iLineSize,
					myData.switcher.fOneViewportWidth + myConfig.iLineSize,
					myData.switcher.fOneViewportHeight + myConfig.iLineSize);
				cairo_fill (myDrawContext);
				
				cairo_restore (myDrawContext);
			}
			
			if (myConfig.bDrawWindows)
			{
				cairo_save (myDrawContext);
				
				cairo_translate (myDrawContext,
					xi,
					yj);
				cairo_set_line_width (myDrawContext, 1.);
				cairo_rectangle (myDrawContext,
					0.,
					0.,
					myData.switcher.fOneViewportWidth,
					myData.switcher.fOneViewportHeight);
				cairo_clip (myDrawContext);
				
				//g_print (" dessin des fenetres du bureau (%d;%d;%d) ...\n", iNumDesktop, iNumViewportX, iNumViewportY);
				CDSwitcherDesktop data = {iNumDesktop, iNumViewportX, iNumViewportY, (int) myData.switcher.fOneViewportWidth, (int) myData.switcher.fOneViewportHeight, myDrawContext};
				g_list_foreach (pWindowList, (GFunc) _cd_switcher_draw_windows_on_viewport, &data);
				
				cairo_restore (myDrawContext);
			}
			
			iNumViewportX ++;
			if (iNumViewportX == g_desktopGeometry.iNbViewportX)
			{
				iNumViewportX = 0;
				iNumViewportY ++;
				if (iNumViewportY == g_desktopGeometry.iNbViewportY)
				{
					iNumViewportY = 0;
					iNumDesktop ++;
				}
			}
			k ++;
		}
	}
	
	// dessin de l'indicateur sur le bureau courant (on le fait maintenant car dans le cas ou la ligne interieure est plus petite que la ligne de l'indicateur, les surfaces suivantes recouvreraient en partie la ligne.
	if (myConfig.iDrawCurrentDesktopMode == SWICTHER_DRAW_FRAME)
	{
		i = myData.switcher.iCurrentColumn;
		j = myData.switcher.iCurrentLine;
		xi = myConfig.iLineSize + i * (myData.switcher.fOneViewportWidth + myConfig.iInLineSize);
		yj = myConfig.iLineSize + j * (myData.switcher.fOneViewportHeight + myConfig.iInLineSize);
		
		cairo_set_line_width (myDrawContext,myConfig.iLineSize);
		if (myConfig.bUseDefaultColors)
			gldi_style_colors_set_selected_bg_color (myDrawContext);
		else
			cairo_set_source_rgba (myDrawContext,myConfig.RGBIndColors[0],myConfig.RGBIndColors[1],myConfig.RGBIndColors[2],myConfig.RGBIndColors[3]);
		cairo_rectangle(myDrawContext,
			xi - .5*myConfig.iLineSize,
			yj - .5*myConfig.iLineSize,
			myData.switcher.fOneViewportWidth + myConfig.iLineSize,
			myData.switcher.fOneViewportHeight + myConfig.iLineSize);
		
		if (myConfig.iDrawCurrentDesktopMode == SWICTHER_FILL)
			cairo_fill (myDrawContext);  // maybe we need to fill it with an alpha pattern in case we use the global style color ?...
		else
		{
			cairo_set_line_width (myDrawContext, MIN (4, 2*myConfig.iLineSize));
			cairo_stroke(myDrawContext);
		}
	}
	
	cairo_restore (myDrawContext);
	g_list_free (pWindowList);  // le contenu appartient a la hash table, mais pas la liste.
	
	CD_APPLET_FINISH_DRAWING_MY_ICON_CAIRO;
}