Icon *cairo_dock_get_first_drawn_icon (CairoDock *pDock)
{
	if (pDock->pFirstDrawnElement != NULL)
		return pDock->pFirstDrawnElement->data;
	else
		return cairo_dock_get_first_icon (pDock->icons);
}
gboolean cd_do_check_icon_destroyed (gpointer pUserData, Icon *pIcon)
{
	if (pIcon == myData.pCurrentIcon && ! myData.bIgnoreIconState)
	{
		cd_debug ("notre icone vient de se faire detruire");
		Icon *pNextIcon = NULL;
		if (myData.pCurrentDock != NULL)
		{
			pNextIcon = cairo_dock_get_next_icon (myData.pCurrentDock->icons, pIcon);
			if (! pNextIcon || CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon))
			{
				pNextIcon = cairo_dock_get_previous_icon (myData.pCurrentDock->icons, pIcon);
				if (! pNextIcon || CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon))
					pNextIcon = cairo_dock_get_first_icon (myData.pCurrentDock->icons);
			}
		}
		if (pNextIcon != NULL)
			cd_do_change_current_icon (pNextIcon, myData.pCurrentDock);
		else
			cd_do_exit_session ();
	}
	
	return GLDI_NOTIFICATION_LET_PASS;
}
void cd_rendering_calculate_max_dock_size_3D_plane (CairoDock *pDock)
{
	pDock->pFirstDrawnElement = cairo_dock_calculate_icons_positions_at_rest_linear (pDock->icons, pDock->fFlatDockWidth, pDock->iScrollOffset);
	
	//pDock->iMaxDockHeight = (int) ((1 + g_fAmplitude) * pDock->iMaxIconHeight + myIcons.fReflectSize * pDock->fRatio) + myLabels.iLabelSize + myBackground.iDockLineWidth + myBackground.iFrameMargin;
	
	_define_parameters (hi, h0, H, l, r, gamma, h, w, dw);
	pDock->iMaxDockHeight = (int) (hi + h0max + l);
	// 1ere estimation.
	// w
	w = ceil (cairo_dock_calculate_max_dock_width (pDock, pDock->pFirstDrawnElement, pDock->fFlatDockWidth, 1., 2 * dw));  // pDock->iMaxDockWidth
	// -> gamma
	gamma = w / 2 / H;
	// -> h
	h = hi + h0 / (1 + gamma);  // en fait, sqrt (1 + gamma * gamma), mais on simplifie pour diminuer l'ordre de 2. pDock->iDecorationsHeight
	// -> dw
	dw = h * gamma + r + (l+(r==0)*2)*sqrt(1+gamma*gamma);  // en fait, h*gamma + r*(1-sin)/cos, or (1-sin)/cos <= 1, on majore pour simplifier. on aurait r + gamma * (h - 2 * r) si on utilisait des cercles au lieu de courbes de Bezier.
	
	double Ws = w+2*dw;
	double W = Ws - 2 * (r + (l+(r==0)*2)*sqrt(1+gamma*gamma));
	double a = H + hi;
	double b = H + hi + h0 - W / 2;
	double c = - W / 2;
	double g = (-b + sqrt (b * b - 4 * a * c)) / 2  / a;
	g_print ("gamma : %f (=) %f\n", gamma, g);
	
	if (cairo_dock_is_extended_dock (pDock))  // mode panel etendu.
	{
		double Ws = cairo_dock_get_max_authorized_dock_width (pDock);
		if (w + 2 * dw < Ws)  // alors on etend.
		{
			double extra = Ws - w;
			pDock->iMaxDockWidth = ceil (cairo_dock_calculate_max_dock_width (pDock, pDock->pFirstDrawnElement, pDock->fFlatDockWidth, 1., extra));  // on pourra optimiser, ce qui nous interesse ici c'est les fXMin/fXMax.
			double W = Ws - 2 * (r + (l+(r==0)*2)*sqrt(1+gamma*gamma));
			double a = H + hi;
			double b = H + hi + h0 - W / 2;
			double c = - W / 2;
			gamma = (-b + sqrt (b * b - 4 * a * c)) / 2  / a;
			g_print ("mode etendu : pDock->iMaxDockWidth : %d, gamma = %f\n", pDock->iMaxDockWidth, gamma);
			h = hi + h0 / (1 + gamma);
		}
	}
	else  // rien d'autre a faire
	{
		pDock->iMaxDockWidth = ceil (cairo_dock_calculate_max_dock_width (pDock, pDock->pFirstDrawnElement, pDock->fFlatDockWidth, 1., 2 * dw));  // on pourra optimiser, ce qui nous interesse ici c'est les fXMin/fXMax.
	}
	pDock->iDecorationsHeight = h;
	g_print ("h : %.2f -> %d\n", h, pDock->iDecorationsHeight);
	
	pDock->iDecorationsWidth = pDock->iMaxDockWidth;
	
	// taille min.
	pDock->iMinDockHeight = myBackground.iDockLineWidth + myBackground.iFrameMargin + myIcons.fReflectSize * pDock->fRatio + pDock->iMaxIconHeight;
	
	double gamma_min = pDock->fFlatDockWidth / 2 / H;
	double dw_min = h * gamma_min + r + (l+(r==0)*2)*sqrt(1+gamma_min*gamma_min);
	//cairo_dock_calculate_extra_width_for_trapeze (pDock->iDecorationsHeight, fInclination, myBackground.iDockRadius, myBackground.iDockLineWidth);
	
	if (cairo_dock_is_extended_dock (pDock))  // mode panel etendu.
	{
		pDock->iMinDockWidth = cairo_dock_get_max_authorized_dock_width (pDock);
	}
	else
	{
		pDock->iMinDockWidth = pDock->fFlatDockWidth + 2 * dw_min;
	}
	
	// on reboucle (sauf que on reboucle pas).
	//fInclination = 0.5 * pDock->iMinDockWidth / iVanishingPointY;
	//fExtraWidthMin = cairo_dock_calculate_extra_width_for_trapeze (pDock->iDecorationsHeight, fInclination, myBackground.iDockRadius, myBackground.iDockLineWidth);
	//pDock->iMinDockWidth = pDock->fFlatDockWidth + fExtraWidthMin;  // en commentaire depuis des lustres.
	
	pDock->iMinLeftMargin = dw;
	pDock->iMinRightMargin = dw;
	Icon *pFirstIcon = cairo_dock_get_first_icon (pDock->icons);
	if (pFirstIcon != NULL)
		pDock->iMaxRightMargin = dw + pFirstIcon->fWidth;
	Icon *pLastIcon = cairo_dock_get_last_icon (pDock->icons);
	if (pLastIcon != NULL)
		pDock->iMaxRightMargin = dw + pLastIcon->fWidth;
	
	pDock->inputArea.x = (pDock->iMinDockWidth - pDock->fFlatDockWidth) / 2;
	pDock->inputArea.y = 0;
	pDock->inputArea.width = pDock->fFlatDockWidth;
	pDock->inputArea.height = pDock->iMinDockHeight;
	g_print ("input area : %d + %d\n", pDock->inputArea.x, pDock->inputArea.width);
	
	// on charge les separateurs plat.
	if (my_pFlatSeparatorSurface[0] == NULL && my_iFlatSeparatorTexture == 0 && my_iDrawSeparator3D == CD_FLAT_SEPARATOR)
		cd_rendering_load_flat_separator (CAIRO_CONTAINER (g_pMainDock));
}
gboolean cd_do_key_pressed (gpointer pUserData, GldiContainer *pContainer, guint iKeyVal, guint iModifierType, const gchar *string, int iKeyCode)
{
	g_return_val_if_fail (cd_do_session_is_running (), GLDI_NOTIFICATION_LET_PASS);
	g_return_val_if_fail (myData.pCurrentDock != NULL, GLDI_NOTIFICATION_LET_PASS);
	
	const gchar *cKeyName = gdk_keyval_name (iKeyVal);
	guint32 iUnicodeChar = gdk_keyval_to_unicode (iKeyVal);
	cd_debug ("+ cKeyName : %s (%c, %s, %d)", cKeyName, iUnicodeChar, string, iKeyCode);
	
	if (myData.sCurrentText->len == 0)
	{
		GdkKeymapKey *keys = NULL;
		guint *keyvals = NULL;
		int i, n_entries = 0;
		int iKeyVal2;
		gdk_keymap_get_entries_for_keycode (gdk_keymap_get_default (),
			iKeyCode,
			&keys,
			&keyvals,
			&n_entries);
		for (i = 0; i < n_entries; i ++)
		{
			iKeyVal2 = keyvals[i];
			if ((iKeyVal2 >= GDK_KEY_0 && iKeyVal2 <= GDK_KEY_9) || (iKeyVal2 >= GDK_KEY_KP_0 && iKeyVal2 <= GDK_KEY_KP_9))
			{
				iKeyVal = iKeyVal2;
				break;
			}
		}
		g_free (keys);
		g_free (keyvals);
	}
	
	if (iKeyVal == GDK_KEY_Escape)  // on clot la session.
	{
		// give the focus back to the window that had it before the user opened this session.
		if (myData.pPreviouslyActiveWindow != NULL)
		{
			gldi_window_show (myData.pPreviouslyActiveWindow);
		}
		cd_do_close_session ();
	}
	else if (iKeyVal == GDK_KEY_space && myData.sCurrentText->len == 0)  // pas d'espace en debut de chaine.
	{
		// on rejette.
	}
	else if (iKeyVal >= GDK_KEY_Shift_L && iKeyVal <= GDK_KEY_Hyper_R)  // on n'ecrit pas les modificateurs.
	{
		// on rejette.
	}
	else if (iKeyVal == GDK_KEY_Menu)  // emulation du clic droit.
	{
		if (myData.pCurrentIcon != NULL)
		{
			myData.bIgnoreIconState = TRUE;
			gldi_icon_stop_animation (myData.pCurrentIcon);  // car on va perdre le focus.
			myData.bIgnoreIconState = FALSE;
			
			GtkWidget *menu = gldi_container_build_menu (CAIRO_CONTAINER (myData.pCurrentDock), myData.pCurrentIcon);
			gldi_menu_popup (menu);
		}
	}
	else if (iKeyVal == GDK_KEY_BackSpace)  // on efface la derniere lettre.
	{
		if (myData.sCurrentText->len > 0)
		{
			cd_debug ("we remove the last letter of %s (%d)", myData.sCurrentText->str, myData.sCurrentText->len);
			
			g_string_truncate (myData.sCurrentText, myData.sCurrentText->len-1);
			
			// on relance la recherche.
			if (myData.pCurrentIcon == NULL)  // sinon l'icone actuelle convient toujours.
				cd_do_search_current_icon (FALSE);
		}
	}
	else if (iKeyVal == GDK_KEY_Tab)  // jump to next icon.
	{
		if (myData.sCurrentText->len > 0)
		{
			//gboolean bPrevious = iModifierType & GDK_SHIFT_MASK;
			// on cherche l'icone suivante.
			cd_do_search_current_icon (TRUE);  // pCurrentIcon peut etre NULL si elle s'est faite detruire pendant la recherche, auquel cas on cherchera juste normalement.
		}
	}
	else if (iKeyVal == GDK_KEY_Return)
	{
		if (myData.pCurrentIcon != NULL)
		{
			cd_debug ("we click on the icon '%s' [%d, %d]", myData.pCurrentIcon->cName, iModifierType, GDK_SHIFT_MASK);
			
			myData.bIgnoreIconState = TRUE;
			if (iModifierType & GDK_MOD1_MASK)  // ALT
			{
				myData.bIgnoreIconState = TRUE;
				gldi_icon_stop_animation (myData.pCurrentIcon);  // car aucune animation ne va la remplacer.
				myData.bIgnoreIconState = FALSE;
				gldi_object_notify (CAIRO_CONTAINER (myData.pCurrentDock), NOTIFICATION_MIDDLE_CLICK_ICON, myData.pCurrentIcon, myData.pCurrentDock);
			}
			else if (iModifierType & GDK_CONTROL_MASK)  // CTRL
			{
				myData.bIgnoreIconState = TRUE;
				gldi_icon_stop_animation (myData.pCurrentIcon);  // car on va perdre le focus.
				myData.bIgnoreIconState = FALSE;
				
				GtkWidget *menu = gldi_container_build_menu (CAIRO_CONTAINER (myData.pCurrentDock), myData.pCurrentIcon);
				gldi_menu_popup (menu);
			}
			else
			{
				cd_do_simulate_click (CAIRO_CONTAINER (myData.pCurrentDock), myData.pCurrentIcon, iModifierType);
			}
			gldi_icon_start_animation (myData.pCurrentIcon);
			myData.bIgnoreIconState = FALSE;
			myData.pCurrentIcon = NULL;  // sinon on va interrompre l'animation en fermant la session.
		}
		cd_do_close_session ();
	}
	else if (iKeyVal == GDK_KEY_Left || iKeyVal == GDK_KEY_Right || iKeyVal == GDK_KEY_Up || iKeyVal == GDK_KEY_Down)
	{
		iKeyVal = _orient_arrow (pContainer, iKeyVal);
		if (iKeyVal == GDK_KEY_Up)
		{
			if (myData.pCurrentIcon != NULL && myData.pCurrentIcon->pSubDock != NULL)
			{
				cd_debug ("on monte dans le sous-dock %s", myData.pCurrentIcon->cName);
				Icon *pIcon = cairo_dock_get_first_icon (myData.pCurrentIcon->pSubDock->icons);
				cd_do_change_current_icon (pIcon, myData.pCurrentIcon->pSubDock);
			}
		}
		else if (iKeyVal == GDK_KEY_Down)
		{
			if (myData.pCurrentDock->iRefCount > 0)
			{
				CairoDock *pParentDock = NULL;
				Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (myData.pCurrentDock, &pParentDock);
				if (pPointingIcon != NULL)
				{
					cd_debug ("on redescend dans le dock parent via %s", pPointingIcon->cName);
					cd_do_change_current_icon (pPointingIcon, pParentDock);
				}
			}
		}
		else if (iKeyVal == GDK_KEY_Left)
		{
			if (myData.pCurrentDock->icons != NULL)
			{
				Icon *pPrevIcon = cairo_dock_get_previous_icon (myData.pCurrentDock->icons, myData.pCurrentIcon);
				if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pPrevIcon))
					pPrevIcon = cairo_dock_get_previous_icon (myData.pCurrentDock->icons, pPrevIcon);
				if (pPrevIcon == NULL)  // pas trouve ou bien 1ere icone.
				{
					pPrevIcon = cairo_dock_get_last_icon (myData.pCurrentDock->icons);
				}
				
				cd_debug ("on se deplace a gauche sur %s", pPrevIcon ? pPrevIcon->cName : "none");
				cd_do_change_current_icon (pPrevIcon, myData.pCurrentDock);
			}
		}
		else  // Gdk_Right.
		{
			if (myData.pCurrentDock->icons != NULL)
			{
				Icon *pNextIcon = cairo_dock_get_next_icon (myData.pCurrentDock->icons, myData.pCurrentIcon);
				if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon))
					pNextIcon = cairo_dock_get_next_icon (myData.pCurrentDock->icons, pNextIcon);
				if (pNextIcon == NULL)  // pas trouve ou bien 1ere icone.
				{
					pNextIcon = cairo_dock_get_first_icon (myData.pCurrentDock->icons);
				}
				
				cd_debug ("on se deplace a gauche sur %s", pNextIcon ? pNextIcon->cName : "none");
				cd_do_change_current_icon (pNextIcon, myData.pCurrentDock);
			}
		}
	}
	else if (iKeyVal == GDK_KEY_Page_Down || iKeyVal == GDK_KEY_Page_Up || iKeyVal == GDK_KEY_Home || iKeyVal == GDK_KEY_End)
	{
		if (iModifierType & GDK_CONTROL_MASK)  // changement de dock principal
		{
			gpointer data[4] = {myData.pCurrentDock, NULL, GINT_TO_POINTER (FALSE), NULL};
			gldi_docks_foreach_root ((GFunc) _find_next_dock, data);
			CairoDock *pNextDock = data[1];
			if (pNextDock == NULL)
				pNextDock = data[3];
			if (pNextDock != NULL)
			{
				Icon *pNextIcon = NULL;
				int n = g_list_length (pNextDock->icons);
				if (n > 0)
				{
					pNextIcon =  g_list_nth_data (pNextDock->icons, (n-1) / 2);
					if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon) && n > 1)
						pNextIcon = g_list_nth_data (pNextDock->icons, (n+1) / 2);
				}
				cd_do_change_current_icon (pNextIcon, pNextDock);
			}
		}
		
		Icon *pIcon = (iKeyVal == GDK_KEY_Page_Up || iKeyVal == GDK_KEY_Home ? cairo_dock_get_first_icon (myData.pCurrentDock->icons) : cairo_dock_get_last_icon (myData.pCurrentDock->icons));
		cd_debug ("on se deplace a l'extremite sur %s", pIcon ? pIcon->cName : "none");
		cd_do_change_current_icon (pIcon, myData.pCurrentDock);
	}
	else if ( ((iKeyVal >= GDK_KEY_0 && iKeyVal <= GDK_KEY_9) || (iKeyVal >= GDK_KEY_KP_0 && iKeyVal <= GDK_KEY_KP_9))
	&& myData.sCurrentText->len == 0)
	{
		_activate_nth_icon (iKeyVal, iModifierType);
	}
	else if (string)  /// utiliser l'unichar ...
	{
		cd_debug ("string:'%s'", string);
		g_string_append_c (myData.sCurrentText, *string);
		
		cd_do_search_current_icon (FALSE);
	}
	
	return GLDI_NOTIFICATION_INTERCEPT;
}
static void cd_render_optimized (cairo_t *pCairoContext, CairoDock *pDock, GdkRectangle *pArea)
{
	//g_print ("%s ((%d;%d) x (%d;%d) / (%dx%d))\n", __func__, pArea->x, pArea->y, pArea->width, pArea->height, pDock->container.iWidth, pDock->container.iHeight);
	double fLineWidth = myDocksParam.iDockLineWidth;
	double fMargin = myDocksParam.iFrameMargin;
	int iHeight = pDock->container.iHeight;

	//\____________________ On dessine les decorations du fond sur la portion de fenetre.
	cairo_save (pCairoContext);

	double fDockOffsetX, fDockOffsetY;
	if (pDock->container.bIsHorizontal)
	{
		fDockOffsetX = pArea->x;
		fDockOffsetY = (pDock->container.bDirectionUp ? iHeight - pDock->iDecorationsHeight - fLineWidth : fLineWidth);
	}
	else
	{
		fDockOffsetX = (pDock->container.bDirectionUp ? iHeight - pDock->iDecorationsHeight - fLineWidth : fLineWidth);
		fDockOffsetY = pArea->y;
	}

	if (pDock->container.bIsHorizontal)
		cairo_rectangle (pCairoContext, fDockOffsetX, fDockOffsetY, pArea->width, pDock->iDecorationsHeight);
	else
		cairo_rectangle (pCairoContext, fDockOffsetX, fDockOffsetY, pDock->iDecorationsHeight, pArea->height);

	fDockOffsetY = (pDock->container.bDirectionUp ? pDock->container.iHeight - pDock->iDecorationsHeight - fLineWidth : fLineWidth);
	
	double fRadius = MIN (myDocksParam.iDockRadius, (pDock->iDecorationsHeight + myDocksParam.iDockLineWidth) / 2 - 1);
	double fOffsetX;
	if (cairo_dock_is_extended_dock (pDock))  // mode panel etendu.
	{
		fOffsetX = fRadius + fLineWidth / 2;
	}
	else
	{
		Icon *pFirstIcon = cairo_dock_get_first_icon (pDock->icons);
		fOffsetX = (pFirstIcon != NULL ? pFirstIcon->fX - fMargin : fRadius + fLineWidth / 2);
	}
	double fDockWidth = cairo_dock_get_current_dock_width_linear (pDock);
	double fDeltaXTrapeze = fRadius;
	cairo_dock_render_decorations_in_frame (pCairoContext, pDock, fDockOffsetY, fOffsetX - fDeltaXTrapeze, fDockWidth + 2*fDeltaXTrapeze);
	
	//\____________________ On dessine la partie du cadre qui va bien.
	cairo_new_path (pCairoContext);
	if (myDocksParam.bUseDefaultColors)
		gldi_style_colors_set_line_color (pCairoContext);
	else
		gldi_color_set_cairo (pCairoContext, &myDocksParam.fLineColor);
	cairo_set_line_width (pCairoContext, fLineWidth);
	
	if (pDock->container.bIsHorizontal)
	{
		cairo_move_to (pCairoContext, fDockOffsetX, fDockOffsetY - fLineWidth / 2);
		cairo_rel_line_to (pCairoContext, pArea->width, 0);
		cairo_stroke (pCairoContext);

		cairo_new_path (pCairoContext);
		cairo_move_to (pCairoContext, fDockOffsetX, (pDock->container.bDirectionUp ? iHeight - fLineWidth / 2 : pDock->iDecorationsHeight + 1.5 * fLineWidth));
		cairo_rel_line_to (pCairoContext, pArea->width, 0);
	}
	else
	{
		cairo_move_to (pCairoContext, fDockOffsetX - fLineWidth / 2, fDockOffsetY);
		cairo_rel_line_to (pCairoContext, 0, pArea->height);
		cairo_stroke (pCairoContext);

		cairo_new_path (pCairoContext);
		cairo_move_to (pCairoContext, (pDock->container.bDirectionUp ? iHeight - fLineWidth / 2 : pDock->iDecorationsHeight + 1.5 * fLineWidth), fDockOffsetY);
		cairo_rel_line_to (pCairoContext, 0, pArea->height);
	}
	cairo_stroke (pCairoContext);

	cairo_restore (pCairoContext);

	//\____________________ On dessine les icones impactees.
	cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);

	GList *pFirstDrawnElement = pDock->icons;
	if (pFirstDrawnElement != NULL)
	{
		double fXMin = (pDock->container.bIsHorizontal ? pArea->x : pArea->y), fXMax = (pDock->container.bIsHorizontal ? pArea->x + pArea->width : pArea->y + pArea->height);
		double fDockMagnitude = cairo_dock_calculate_magnitude (pDock->iMagnitudeIndex);
		double fXLeft, fXRight;
		
		//g_print ("redraw [%d -> %d]\n", (int) fXMin, (int) fXMax);
		Icon *icon;
		GList *ic = pFirstDrawnElement;
		do
		{
			icon = ic->data;

			fXLeft = icon->fDrawX + icon->fScale + 1;
			fXRight = icon->fDrawX + (icon->fWidth - 1) * icon->fScale * icon->fWidthFactor - 1;

			if (fXLeft < fXMax && fXRight > fXMin && ! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (icon))
			{
				cairo_save (pCairoContext);
				//g_print ("dessin optimise de %s [%.2f -> %.2f]\n", icon->cName, fXLeft, fXRight);
				
				icon->fAlpha = 1;
				if (icon->iAnimationState == CAIRO_DOCK_STATE_AVOID_MOUSE)
				{
					icon->fAlpha = 0.7;
				}
				
				cairo_dock_render_one_icon (icon, pDock, pCairoContext, fDockMagnitude, icon->bPointed);
				cairo_restore (pCairoContext);
			}

			ic = cairo_dock_get_next_element (ic, pDock->icons);
		} while (ic != pFirstDrawnElement);
	}
}
static void cd_render (cairo_t *pCairoContext, CairoDock *pDock)
{
	//\____________________ On trace le cadre.
	double fLineWidth = myDocksParam.iDockLineWidth;
	double fMargin = myDocksParam.iFrameMargin;
	double fRadius = (pDock->iDecorationsHeight + fLineWidth - 2 * myDocksParam.iDockRadius > 0 ? myDocksParam.iDockRadius : (pDock->iDecorationsHeight + fLineWidth) / 2 - 1);
	double fExtraWidth = 2 * fRadius + fLineWidth;
	double fDockWidth;
	int sens;
	double fDockOffsetX, fDockOffsetY;  // Offset du coin haut gauche du cadre.
	if (cairo_dock_is_extended_dock (pDock))  // mode panel etendu.
	{
		fDockWidth = pDock->container.iWidth - fExtraWidth;
		fDockOffsetX = fExtraWidth / 2;
	}
	else
	{
		fDockWidth = cairo_dock_get_current_dock_width_linear (pDock);
		Icon *pFirstIcon = cairo_dock_get_first_icon (pDock->icons);
		fDockOffsetX = (pFirstIcon != NULL ? pFirstIcon->fX - fMargin : fExtraWidth / 2);
		if (fDockOffsetX < fExtraWidth / 2)
			fDockOffsetX = fExtraWidth / 2;
		if (fDockOffsetX + fDockWidth + fExtraWidth / 2 > pDock->container.iWidth)
			fDockWidth = pDock->container.iWidth - fDockOffsetX - fExtraWidth / 2;
	}
	if (pDock->container.bDirectionUp)
	{
		sens = 1;
		fDockOffsetY = pDock->container.iHeight - pDock->iDecorationsHeight - 1.5 * fLineWidth;
	}
	else
	{
		sens = -1;
		fDockOffsetY = pDock->iDecorationsHeight + 1.5 * fLineWidth;
	}

	cairo_save (pCairoContext);
	double fDeltaXTrapeze = cairo_dock_draw_frame (pCairoContext, fRadius, fLineWidth, fDockWidth, pDock->iDecorationsHeight, fDockOffsetX, fDockOffsetY, sens, 0., pDock->container.bIsHorizontal, FALSE);  // FALSE <=> ignore 'myDocksParam.bRoundedBottomCorner', as bottom rounded corners looks bad for a panel.

	//\____________________ On dessine les decorations dedans.
	fDockOffsetY = (pDock->container.bDirectionUp ? pDock->container.iHeight - pDock->iDecorationsHeight - fLineWidth : fLineWidth);
	cairo_dock_render_decorations_in_frame (pCairoContext, pDock, fDockOffsetY, fDockOffsetX - fDeltaXTrapeze, fDockWidth + 2*fDeltaXTrapeze);

	//\____________________ On dessine le cadre.
	if (fLineWidth > 0)
	{
		cairo_set_line_width (pCairoContext, fLineWidth);
		if (myDocksParam.bUseDefaultColors)
			gldi_style_colors_set_line_color (pCairoContext);
		else
			gldi_color_set_cairo (pCairoContext, &myDocksParam.fLineColor);
		cairo_stroke (pCairoContext);
	}
	else
		cairo_new_path (pCairoContext);
	cairo_restore (pCairoContext);
	
	//\____________________ On dessine les separateurs physiques.
	GList *ic;
	Icon *pIcon;
	if (my_bPanelPhysicalSeparator)
	{
		cairo_save (pCairoContext);
		if (pDock->container.bIsHorizontal)
		{
			if (! pDock->container.bDirectionUp)
			{
				cairo_translate (pCairoContext, 0., pDock->container.iHeight);
				cairo_scale (pCairoContext, 1., -1.);
			}
		}
		else
		{
			cairo_translate (pCairoContext, pDock->container.iHeight/2., pDock->container.iWidth/2.);
			cairo_rotate (pCairoContext, G_PI/2);
			if (pDock->container.bDirectionUp)
				cairo_scale (pCairoContext, 1., -1.);
			cairo_translate (pCairoContext, -pDock->container.iWidth/2., -pDock->container.iHeight/2.);
		}
		
		double x1, x2, dx, delta, h = pDock->iDecorationsHeight + 2*fLineWidth, h_ = h - fLineWidth;
		for (ic = pDock->icons; ic != NULL; ic = ic->next)
		{
			pIcon = ic->data;
			if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pIcon))
			{
				x1 = pIcon->fDrawX = pIcon->fX;
				
				pIcon = NULL;
				for (ic = ic->next; ic != NULL; ic = ic->next)
				{
					pIcon = ic->data;
					if (!CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pIcon))
						break;
				}
				if (ic != NULL)
				{
					pIcon = ic->data;
					x2 = pIcon->fDrawX;
				}
				else
					break;
				
				dx = MIN (my_fPanelRadius, (x2 - x1) / 2);
				delta = dx + h*tan(my_fPanelInclination)/2;
				if (delta > (x2 - x1) / 2)
					delta = (x2 - x1) / 2;
				
				cairo_move_to (pCairoContext, x1, pDock->iMaxDockHeight - h);
				cairo_rel_curve_to (pCairoContext,
					dx, 0.,
					delta - dx, h,
					delta, h);
				cairo_rel_line_to (pCairoContext,
					x2 - x1 - 2*delta, 0.);
				cairo_rel_curve_to (pCairoContext,
					dx, 0.,
					delta - dx, -h,
					delta, -h);
				cairo_close_path (pCairoContext);
				
				cairo_set_operator (pCairoContext, CAIRO_OPERATOR_DEST_OUT);
				cairo_set_source_rgba (pCairoContext, 0.0, 0.0, 0.0, 1.0);
				cairo_fill (pCairoContext);
				
				if (fLineWidth > 0)
				{
					cairo_move_to (pCairoContext, x1, pDock->iMaxDockHeight - h_ - fLineWidth/2);
					cairo_rel_curve_to (pCairoContext,
						dx, 0.,
						delta - dx, h_,
						delta, h_);
					cairo_rel_line_to (pCairoContext,
						x2 - x1 - 2*delta, 0.);
					cairo_rel_curve_to (pCairoContext,
						dx, 0.,
						delta - dx, -h_,
						delta, -h_);
					
					cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
					cairo_set_line_width (pCairoContext, fLineWidth);
					if (myDocksParam.bUseDefaultColors)
						gldi_style_colors_set_line_color (pCairoContext);
					else
						gldi_color_set_cairo (pCairoContext, &myDocksParam.fLineColor);
					cairo_stroke (pCairoContext);
				}
			}
		}
		cairo_restore (pCairoContext);
	}
	
	//\____________________ On dessine la ficelle qui les joint.
	if (myIconsParam.iStringLineWidth > 0)
		cairo_dock_draw_string (pCairoContext, pDock, myIconsParam.iStringLineWidth, FALSE, FALSE);

	//\____________________ On dessine les icones et les etiquettes, en tenant compte de l'ordre pour dessiner celles en arriere-plan avant celles en avant-plan.
	GList *pFirstDrawnElement = cairo_dock_get_first_drawn_element_linear (pDock->icons);
	if (pFirstDrawnElement == NULL)
		return;
	
	double fDockMagnitude = cairo_dock_calculate_magnitude (pDock->iMagnitudeIndex);  // * pDock->fMagnitudeMax
	ic = pFirstDrawnElement;
	do
	{
		pIcon = ic->data;
		
		if (! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pIcon))
		{
			cairo_save (pCairoContext);
			cairo_dock_render_one_icon (pIcon, pDock, pCairoContext, fDockMagnitude, pIcon->bPointed);
			cairo_restore (pCairoContext);
		}
		ic = cairo_dock_get_next_element (ic, pDock->icons);
	} while (ic != pFirstDrawnElement);
}
GList *vfs_backend_list_directory (const gchar *cBaseURI, CairoDockFMSortType iSortType, int iNewIconsType, gboolean bListHiddenFiles, gchar **cFullURI)
{
	g_return_val_if_fail (cBaseURI != NULL, NULL);
	cd_message ("%s (%s)", __func__, cBaseURI);
	
	gchar *cURI;
	gboolean bAddHome = FALSE;
	if (strcmp (cBaseURI, CAIRO_DOCK_FM_VFS_ROOT) == 0)
	{
		cURI = g_strdup ("computer://");
		bAddHome = TRUE;
		///*cFullURI = cURI;
		///return vfs_backend_list_volumes ();
		//vfs_backend_list_volumes ();
	}
	else if (strcmp (cBaseURI, CAIRO_DOCK_FM_NETWORK) == 0)
		cURI = g_strdup ("network://");
	else
		cURI = (*cBaseURI == '/' ? g_strconcat ("file://", cBaseURI, NULL) : g_strdup (cBaseURI));
	*cFullURI = cURI;
	
	GFile *pFile = g_file_new_for_uri (cURI);
	GError *erreur = NULL;
	const gchar *cAttributes = G_FILE_ATTRIBUTE_STANDARD_TYPE","
		G_FILE_ATTRIBUTE_STANDARD_SIZE","
		G_FILE_ATTRIBUTE_TIME_MODIFIED","
		G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE","
		G_FILE_ATTRIBUTE_STANDARD_NAME","
		G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN","
		G_FILE_ATTRIBUTE_STANDARD_ICON","
		G_FILE_ATTRIBUTE_STANDARD_TARGET_URI","
		G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE;
	GFileEnumerator *pFileEnum = g_file_enumerate_children (pFile,
		cAttributes,
		G_FILE_QUERY_INFO_NONE,  /// G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS
		NULL,
		&erreur);
	//g_object_unref (pFile);
	if (erreur != NULL)
	{
		cd_warning ("gnome_integration : %s", erreur->message);
		g_error_free (erreur);
		return NULL;
	}
	
	int iOrder = 0;
	GList *pIconList = NULL;
	Icon *icon;
	GFileInfo *pFileInfo;
	do
	{
		pFileInfo = g_file_enumerator_next_file (pFileEnum, NULL, &erreur);
		if (erreur != NULL)
		{
			cd_warning ("gnome_integration : %s", erreur->message);
			g_error_free (erreur);
			erreur = NULL;
			continue;
		}
		if (pFileInfo == NULL)
			break ;
		
		gboolean bIsHidden = g_file_info_get_is_hidden (pFileInfo);
		if (bListHiddenFiles || ! bIsHidden)
		{
			GFileType iFileType = g_file_info_get_file_type (pFileInfo);
			GIcon *pFileIcon = g_file_info_get_icon (pFileInfo);
			if (pFileIcon == NULL)
			{
				cd_message ("AUCUNE ICONE");
				continue;
			}
			const gchar *cFileName = g_file_info_get_name (pFileInfo);
			const gchar *cMimeType = g_file_info_get_content_type (pFileInfo);
			gchar *cName = NULL;
			
			icon = g_new0 (Icon, 1);
			icon->iType = iNewIconsType;
			icon->cBaseURI = g_strconcat (*cFullURI, "/", cFileName, NULL);
			cd_message ("+ %s (mime:%s)", icon->cBaseURI, cMimeType);
			
			if (iFileType == G_FILE_TYPE_MOUNTABLE)
			{
				const gchar *cTargetURI = g_file_info_get_attribute_string (pFileInfo, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
				cd_message ("  c'est un point de montage correspondant a %s", cTargetURI);
				
				GMount *pMount = NULL;
				if (cTargetURI != NULL)
				{
					icon->acCommand = g_strdup (cTargetURI);
					GFile *file = g_file_new_for_uri (cTargetURI);
					pMount = g_file_find_enclosing_mount (file, NULL, NULL);
					//g_object_unref (file);
				}
				if (pMount != NULL)
				{
					cName = g_mount_get_name (pMount);
					cd_message ("un GMount existe (%s)", cName);
					
					GVolume *volume = g_mount_get_volume (pMount);
					if (volume)
						cd_message ("  volume associe : %s", g_volume_get_name (volume));
					GDrive *drive = g_mount_get_drive (pMount);
					if (drive)
						cd_message ("  disque associe : %s", g_drive_get_name (drive));
					
					///pFileIcon = g_mount_get_icon (pMount);
				}
				else
				{
					cName = g_strdup (cFileName);
					gchar *str = strrchr (cName, '.');  // on vire l'extension ".volume" ou ".drive".
					if (str != NULL)
					{
						*str = '\0';
						if (strcmp (str+1, "link") == 0)
						{
							if (strcmp (cName, "root") == 0)
							{
								g_free (cName);
								cName = g_strdup ("/");
							}
						}
						else if (strcmp (str+1, "drive") == 0)  // on cherche un nom plus parlant si possible.
						{
							gchar *cVolumeName = _cd_find_volume_name_from_drive_name (cName);
							if (cVolumeName != NULL)
							{
								g_free (cName);
								g_free (cVolumeName);
								continue;  /// apparemment il n'est plus necessaire d'afficher les .drives qui ont 1 (ou plusieurs ?) volumes, car ces derniers sont dans la liste, donc ca fait redondant.
								/**if (strcmp (cVolumeName, "discard") == 0)
									continue;
								g_free (cName);
								cName = cVolumeName;*/
							}
						}
					}
				}
				icon->iVolumeID = 1;
				cd_message ("le nom de ce volume est : %s", cName);
			}
			else
				cName = g_strdup (cFileName);
			
			if (icon->acCommand == NULL)
				icon->acCommand = g_strdup (icon->cBaseURI);
			icon->acName = cName;
			icon->acFileName = NULL;
			if (cMimeType != NULL && strncmp (cMimeType, "image", 5) == 0)
			{
				gchar *cHostname = NULL;
				gchar *cFilePath = g_filename_from_uri (icon->cBaseURI, &cHostname, &erreur);
				if (erreur != NULL)
				{
					g_error_free (erreur);
					erreur = NULL;
				}
				else if (cHostname == NULL || strcmp (cHostname, "localhost") == 0)  // on ne recupere la vignette que sur les fichiers locaux.
				{
					icon->acFileName = g_strdup (cFilePath);
					cairo_dock_remove_html_spaces (icon->acFileName);
				}
				g_free (cHostname);
				g_free (cFilePath);
			}
			if (icon->acFileName == NULL)
			{
				icon->acFileName = _cd_get_icon_path (pFileIcon);
				cd_message ("icon->acFileName : %s", icon->acFileName);
			}
			
			if (iSortType == CAIRO_DOCK_FM_SORT_BY_SIZE)
				icon->fOrder = g_file_info_get_size (pFileInfo);
			else if (iSortType == CAIRO_DOCK_FM_SORT_BY_DATE)
			{
				GTimeVal t;
				g_file_info_get_modification_time (pFileInfo, &t);
				icon->fOrder = t.tv_sec;
			}
			else if (iSortType == CAIRO_DOCK_FM_SORT_BY_TYPE)
				icon->fOrder = (cMimeType != NULL ? *((int *) cMimeType) : 0);
			if (icon->fOrder == 0)  // un peu moyen mais mieux que rien non ?
				icon->fOrder = iOrder;
			pIconList = g_list_insert_sorted (pIconList,
				icon,
				(GCompareFunc) cairo_dock_compare_icons_order);
			//g_list_prepend (pIconList, icon);
			iOrder ++;
		}
	} while (TRUE);  // 'g_file_enumerator_close' est appelee lors du dernier 'g_file_enumerator_next_file'.
	
	if (bAddHome && pIconList != NULL)
	{
		icon = g_new0 (Icon, 1);
		icon->iType = iNewIconsType;
		icon->cBaseURI = g_strdup_printf ("file://%s", "/home");
		icon->acCommand = g_strdup ("/home");
		//icon->acCommand = g_strdup (icon->cBaseURI);
		icon->iVolumeID = 0;
		icon->acName = g_strdup ("home");
		Icon *pRootIcon = cairo_dock_get_icon_with_name (pIconList, "/");
		if (pRootIcon == NULL)
		{
			pRootIcon = cairo_dock_get_first_icon (pIconList);
			g_print ("domage ! (%s:%s)\n", pRootIcon->acCommand, pRootIcon->acName);
		}
		icon->acFileName = g_strdup (pRootIcon->acFileName);
		icon->fOrder = iOrder++;
		pIconList = g_list_insert_sorted (pIconList,
			icon,
			(GCompareFunc) cairo_dock_compare_icons_order);
	}
	
	if (iSortType == CAIRO_DOCK_FM_SORT_BY_NAME)
		pIconList = cairo_dock_sort_icons_by_name (pIconList);
	else
		pIconList = cairo_dock_sort_icons_by_order (pIconList);
	
	return pIconList;
}