static void _apply_desktop_background (GldiContainer *pContainer)
{
	if (! g_pFakeTransparencyDesktopBg || g_pFakeTransparencyDesktopBg->iTexture == 0)
		return ;
	
	glPushMatrix ();
	gboolean bSetPerspective = pContainer->bPerspectiveView;
	if (bSetPerspective)
		gldi_gl_container_set_ortho_view (pContainer);
	glLoadIdentity ();
	_cairo_dock_enable_texture ();
	_cairo_dock_set_blend_source ();
	_cairo_dock_set_alpha (1.);
	glBindTexture (GL_TEXTURE_2D, g_pFakeTransparencyDesktopBg->iTexture);
	
	double x, y, w, h, W, H;
	W = gldi_desktop_get_width();
	H = gldi_desktop_get_height();
	if (pContainer->bIsHorizontal)
	{
		w = pContainer->iWidth;
		h = pContainer->iHeight;
		x = pContainer->iWindowPositionX;
		y = pContainer->iWindowPositionY;
	}
	else
	{
		h = pContainer->iWidth;
		w = pContainer->iHeight;
		y = pContainer->iWindowPositionX;
		x = pContainer->iWindowPositionY;
	}
	
	glBegin(GL_QUADS);
	glTexCoord2f ((x + 0) / W, (y + 0) / H);
	glVertex3f (0., h, 0.);  // Top Left.
	
	glTexCoord2f ((x + w) / W, (y + 0) / H);
	glVertex3f (w, h, 0.);  // Top Right
	
	glTexCoord2f ((x + w) / W, (y + h) / H);
	glVertex3f (w, 0., 0.);  // Bottom Right
	
	glTexCoord2f ((x + 0.) / W, (y + h) / H);
	glVertex3f (0., 0., 0.);  // Bottom Left
	glEnd();
	
	_cairo_dock_disable_texture ();
	if (bSetPerspective)
		gldi_gl_container_set_perspective_view (pContainer);
	glPopMatrix ();
}
void cd_opengl_scene (CairoDockModuleInstance *myApplet, int iWidth, int iHeight)
{
	//g_print ("%s (%d)\n", __func__, myData.iCoverTransition);
	_cairo_dock_enable_texture ();
	_cairo_dock_set_blend_source ();
	
	// on dessine le cadre.
	_cairo_dock_apply_texture_at_size_with_alpha (myData.TextureFrame, iWidth, iHeight, 1.);
	
	// on dessine la couverture.
	glPushMatrix ();
	glScalef (iWidth, iHeight, 1.);
	if (myData.iPrevTextureCover != 0 && myData.iCoverTransition != 0)
	{
		_cairo_dock_set_blend_over ();
		_cairo_dock_set_alpha ((double)myData.iCoverTransition/NB_TRANSITION_STEP);
		glBindTexture(GL_TEXTURE_2D, myData.iPrevTextureCover);
		glCallList(myData.draw_cover);
	}
	if (myData.TextureCover != 0)
	{
		_cairo_dock_set_blend_over ();
		_cairo_dock_set_alpha (1.-(double)myData.iCoverTransition/NB_TRANSITION_STEP);
		glBindTexture(GL_TEXTURE_2D, myData.TextureCover);
		glCallList(myData.draw_cover);
	}
	glPopMatrix ();
	_cairo_dock_set_blend_over ();
	
	
	// on dessine les boutons qui sont allumes.
	if (myData.iButton1Count)
	{
		glPushMatrix ();
		glTranslatef (-iWidth/2 + myData.button1coordX, +iHeight/2 - myData.button1coordY, 0.);
		_cairo_dock_apply_texture_at_size_with_alpha (myData.TextureButton1, myData.button1sizeX, myData.button1sizeY, (double)myData.iButton1Count/NB_TRANSITION_STEP);
		glPopMatrix ();
	}
	if (myData.iButton2Count)
	{
		glPushMatrix ();
		glTranslatef (-iWidth/2 + myData.button2coordX, +iHeight/2 - myData.button2coordY, 0.);
		_cairo_dock_apply_texture_at_size_with_alpha (myData.TextureButton2, myData.button2sizeX, myData.button2sizeY, (double)myData.iButton2Count/NB_TRANSITION_STEP);
		glPopMatrix ();
	}
	if (myData.iButton3Count)
	{
		glPushMatrix ();
		glTranslatef (-iWidth/2 + myData.button3coordX, +iHeight/2 - myData.button3coordY, 0.);
		_cairo_dock_apply_texture_at_size_with_alpha (myData.TextureButton3, myData.button3sizeX, myData.button3sizeY, (double)myData.iButton3Count/NB_TRANSITION_STEP);
		glPopMatrix ();
	}
	if (myData.iButton4Count)
	{
		glPushMatrix ();
		glTranslatef (-iWidth/2 + myData.button4coordX, +iHeight/2 - myData.button4coordY, 0.);
		_cairo_dock_apply_texture_at_size_with_alpha (myData.TextureButton4, myData.button4sizeX, myData.button4sizeY, (double)myData.iButton4Count/NB_TRANSITION_STEP);
		glPopMatrix ();
	}
	
	// on determine la transformation pour les OSD.
	// en majuscule : coordonees initiales.
	double W = iWidth, H = iHeight;
	double X1 = 0, Y1 = 0;
	double X2 = W, Y2 = 0;
	double X3 = W, Y3 = H;
	double X4 = 0, Y4 = H;
	// translation du point P1(0;0)
	double x1 = myData.ibottomleftX, y1 = myData.ibottomleftY;
	double t1x = x1 - X1;
	double t1y = y1 - X1;
	// translation du point P2(500;0)
	double x2 = myData.ibottomrightX, y2 = myData.ibottomrightY;
	double t2x = x2 - X2;
	double t2y = y2 - Y2;
	// translation du point P2(500;500)
	double x3 = myData.itoprightX, y3 = myData.itoprightY;
	double t3x = x3 - X3;
	double t3y = y3 - Y3;
	// translation du point P2(0;500)
	double x4 = myData.itopleftX, y4 = myData.itopleftY;
	double t4x = x4 - X4;
	double t4y = y4 - Y4;
	
	double dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4;  // ponderations.
	double X, Y;  // coordonnees initiales d'un coin de l'OSD.
	double u1, v1, u2, v2, u3, v3, u4, v4;  // coordonnees finales des coins de l'OSD.
	
	// on dessine les OSD.
	//if(myData.bIsRunning && myData.iState != 0)
	{
		_cairo_dock_set_alpha (1.);
		if (myData.mouseOnButton1)
		{
			if (myData.iPlayingStatus == PLAYER_PLAYING)
			{
				_draw_osd (myData.TextureOsdPause, myData.osdPausecoordX, myData.osdPausecoordY, myData.osdPausesizeX, myData.osdPausesizeY);
				//g_print ("%.1f;%.1f ; %.1f;%.1f ;%.1f;%.1f ;%.1f;%.1f\n", u1, v1, u2, v2,u3,v3,u4,v4);
			}
			else
			{
				_draw_osd (myData.TextureOsdPlay, myData.osdPlaycoordX, myData.osdPlaycoordY, myData.osdPlaysizeX, myData.osdPlaysizeY);
				//g_print ("%.1f;%.1f ; %.1f;%.1f ;%.1f;%.1f ;%.1f;%.1f\n", u1, v1, u2, v2,u3,v3,u4,v4);
			}
		}
		else if (myData.mouseOnButton2)
		{
			_draw_osd (myData.TextureOsdPrev, myData.osdPrevcoordX, myData.osdPrevcoordY, myData.osdPrevsizeX, myData.osdPrevsizeY);
		}
		else if (myData.mouseOnButton3)
		{
			_draw_osd (myData.TextureOsdNext, myData.osdNextcoordX, myData.osdNextcoordY, myData.osdNextsizeX, myData.osdNextsizeY);
		}
		else if (myData.mouseOnButton4)
		{
			_draw_osd (myData.TextureOsdHome, myData.osdHomecoordX, myData.osdHomecoordY, myData.osdHomesizeX, myData.osdHomesizeY);
		}
		else if (myData.iPlayingStatus != PLAYER_PLAYING)
		{
			if (myData.bIsRunning)  // on verifie que le lecteur est bien ouvert (il se peut qu'il ne nous previenne pas lorsqu'il quitte).
			{
				cd_musicplayer_dbus_detect_player ();
			}
			if (myData.bIsRunning)  // si rhythmbox n'est pas lancé, on n'affiche pas l'osd de pause ;-)
			{
				_draw_osd (myData.TextureOsdPause, myData.osdPausecoordX, myData.osdPausecoordY, myData.osdPausesizeX, myData.osdPausesizeY);
			}
		}
		else if (myData.iPlayingStatus == PLAYER_PLAYING && ! myData.cover_exist)
		{
			_draw_osd (myData.TextureOsdPlay, myData.osdPlaycoordX, myData.osdPlaycoordY, myData.osdPlaysizeX, myData.osdPlaysizeY);
		}
	}
	
	// on dessine les reflets.
	_cairo_dock_set_blend_pbuffer ();
	if (myData.TextureReflect != 0)
		_cairo_dock_apply_texture_at_size_with_alpha (myData.TextureReflect, iWidth, iHeight, 1.);
	
	_cairo_dock_disable_texture ();
}
static void cd_render_opengl (CairoDock *pDock)
{
	//\_____________ On definit notre rectangle.
	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;
	double fFrameHeight = pDock->iDecorationsHeight + fLineWidth;
	
	double fDockOffsetX, fDockOffsetY;  // Offset du coin haut gauche du cadre.
	GList *pFirstDrawnElement = pDock->icons;
	if (pFirstDrawnElement == NULL)
		return ;
	if (cairo_dock_is_extended_dock (pDock))  // mode panel etendu.
	{
		fDockWidth = pDock->container.iWidth - fExtraWidth;
		fDockOffsetX = fLineWidth / 2;
	}
	else
	{
		fDockWidth = cairo_dock_get_current_dock_width_linear (pDock);
		Icon *pFirstIcon = pFirstDrawnElement->data;
		fDockOffsetX = (pFirstIcon != NULL ? pFirstIcon->fX + 0 - fMargin - fRadius : fLineWidth / 2);
		if (fDockOffsetX - fLineWidth/2 < 0)
			fDockOffsetX = fLineWidth / 2;
		if (fDockOffsetX + fDockWidth + (2*fRadius + fLineWidth) > pDock->container.iWidth)
			fDockWidth = pDock->container.iWidth - fDockOffsetX - (2*fRadius + fLineWidth);
	}
	
	fDockOffsetY = pDock->iDecorationsHeight + 1.5 * fLineWidth;
	
	double fDockMagnitude = cairo_dock_calculate_magnitude (pDock->iMagnitudeIndex);
	
	//\_____________ On genere les coordonnees du contour.
	const CairoDockGLPath *pFramePath = cairo_dock_generate_rectangle_path (fDockWidth, fFrameHeight, fRadius, FALSE);  // same remark as in cairo rendering
	
	//\_____________ On remplit avec le fond.
	glPushMatrix ();
	cairo_dock_set_container_orientation_opengl (CAIRO_CONTAINER (pDock));
	glTranslatef (fDockOffsetX + (fDockWidth+2*fRadius)/2,
		fDockOffsetY - fFrameHeight/2,
		0.);
	
	_cairo_dock_set_blend_source ();
	cairo_dock_fill_gl_path (pFramePath, pDock->backgroundBuffer.iTexture);
	
	//\_____________ On trace le contour.
	if (fLineWidth != 0)
	{
		glLineWidth (fLineWidth);
		if (myDocksParam.bUseDefaultColors)
			gldi_style_colors_set_line_color (NULL);
		else
			gldi_color_set_opengl (&myDocksParam.fLineColor);
		cairo_dock_stroke_gl_path (pFramePath, TRUE);
	}
	glPopMatrix ();
	
	
	//\_____________ On trace les separateurs physiques.
	GList *ic;
	Icon *pIcon;
	if (my_bPanelPhysicalSeparator)
	{
		glPushMatrix ();
		cairo_dock_set_container_orientation_opengl (CAIRO_CONTAINER (pDock));
		
		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;
				
				CairoDockGLPath *pPath = cairo_dock_new_gl_path (2*(iNbCurveSteps+1) + 1, (x1+x2)/2, h, 0., 0.);  // on part du milieu en haut pour que les triangles soient contenus dans l'enveloppe.
				
				dx = MIN (my_fPanelRadius, (x2 - x1) / 2);
				delta = dx + h*tan(my_fPanelInclination)/2;
				if (delta > (x2 - x1) / 2)
					delta = (x2 - x1) / 2;
				
				cairo_dock_gl_path_rel_line_to (pPath,
					-(x2-x1)/2, 0.);
				cairo_dock_gl_path_rel_curve_to (pPath, iNbCurveSteps,
					dx, 0.,
					delta - dx, -h,
					delta, -h);
				cairo_dock_gl_path_rel_line_to (pPath,
					x2 - x1 - 2*delta, 0.);
				cairo_dock_gl_path_rel_curve_to (pPath, iNbCurveSteps,
					dx, 0.,
					delta - dx, h,
					delta, h);
				
				glBlendFunc (GL_ONE, GL_ZERO);
				glColor4f (0., 0., 0., 0.);
				cairo_dock_fill_gl_path (pPath, 0);
				glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				
				if (fLineWidth > 0)
				{
					cairo_dock_gl_path_move_to (pPath, x1, h - fLineWidth/2);  // on part du haut/gauche, le nombre de points est ok.
					cairo_dock_gl_path_rel_curve_to (pPath, iNbCurveSteps,
						dx, 0.,
						delta - dx, -h_,
						delta, -h_);
					cairo_dock_gl_path_rel_line_to (pPath,
						x2 - x1 - 2*delta, 0.);
					cairo_dock_gl_path_rel_curve_to (pPath, iNbCurveSteps,
						dx, 0.,
						delta - dx, h_,
						delta, h_);
					glLineWidth (fLineWidth);
					if (myDocksParam.bUseDefaultColors)
						gldi_style_colors_set_line_color (NULL);
					else
						gldi_color_set_opengl (&myDocksParam.fLineColor);
					cairo_dock_stroke_gl_path (pPath, FALSE);
				}
				
				cairo_dock_free_gl_path (pPath);
			}
		}
		glPopMatrix ();
	}
	
	//\_____________ On dessine la ficelle.
	if (myIconsParam.iStringLineWidth > 0)
		cairo_dock_draw_string_opengl (pDock, myIconsParam.iStringLineWidth, FALSE, FALSE);
	
	
	//\_____________ On dessine les icones.
	pFirstDrawnElement = cairo_dock_get_first_drawn_element_linear (pDock->icons);
	if (pFirstDrawnElement == NULL)
		return;
	
	ic = pFirstDrawnElement;
	do
	{
		pIcon = ic->data;
		
		if (! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pIcon))
		{
			glPushMatrix ();
			cairo_dock_render_one_icon_opengl (pIcon, pDock, fDockMagnitude, pIcon->bPointed);
			glPopMatrix ();
		}
		
		ic = cairo_dock_get_next_element (ic, pDock->icons);
	} while (ic != pFirstDrawnElement);
}
static void render_opengl (ProgressBar *pProgressBar)
{
	g_return_if_fail (pProgressBar != NULL);
	
	CairoDataRenderer *pRenderer = CAIRO_DATA_RENDERER (pProgressBar);
	int iNbValues = cairo_data_renderer_get_nb_values (pRenderer);
	int iWidth = pRenderer->iWidth;
	
	double x, y, v, w, r = pProgressBar->iBarThickness/2.;
	double dx = .5;  // required to not have sharp edges on the left rounded corners... although maybe it should be adressed by the Overlay...
	int i;
	for (i = 0; i < iNbValues; i ++)
	{
		v = cairo_data_renderer_get_normalized_current_value_with_latency (pRenderer, i);
		w = iWidth - pProgressBar->iBarThickness;
		x = - iWidth / 2. + w * v/2 + r + dx;  // center of the bar; the bar is left-aligned.
		y = i * pProgressBar->iBarThickness;  // first value at bottom.
		
		if (v > 0 && v <= 1)  // any negative value is an "undef" value
		{
			// make a rounded rectangle path.
			const CairoDockGLPath *pFramePath = cairo_dock_generate_rectangle_path (w * v, 2*r, r, TRUE);
			
			// bind the texture to the path
			// we don't use the automatic coords generation because we want to bind the texture to the interval [0; v].
			glColor4f (1., 1., 1., 1.);
			_cairo_dock_set_blend_source ();  // doesn't really matter here.
			_cairo_dock_enable_texture ();
			glBindTexture (GL_TEXTURE_2D, pProgressBar->iBarTexture);
			
			GLfloat *pCoords = g_new0 (GLfloat, (pFramePath->iNbPoints+1) * _CD_PATH_DIM);
			int i;
			for (i = 0; i < pFramePath->iCurrentPt; i ++)
			{
				pCoords[_CD_PATH_DIM*i] = (.5 + _cd_gl_path_get_nth_vertex_x (pFramePath, i) / (w*v+2*r)) * v;  // [0;v]
				pCoords[_CD_PATH_DIM*i+1] = .5 + _cd_gl_path_get_nth_vertex_y (pFramePath, i) / (pProgressBar->iBarThickness);
			}
			glEnableClientState (GL_TEXTURE_COORD_ARRAY);
			glTexCoordPointer (_CD_PATH_DIM, GL_FLOAT, 0, pCoords);
			
			// draw the path.
			glPushMatrix ();
			glTranslatef (x,
				y,
				0.);
			cairo_dock_fill_gl_path (pFramePath, 0);  // 0 <=> no texture, since we bound it ourselves.
			
			_cairo_dock_disable_texture ();
			glDisableClientState (GL_TEXTURE_COORD_ARRAY);
			
			// outline
			if (myIndicatorsParam.bBarUseDefaultColors || myIndicatorsParam.fBarColorOutline.rgba.alpha != 0.)
			{
				if (myIndicatorsParam.bBarUseDefaultColors)
					gldi_style_colors_set_line_color (NULL);
				else
					gldi_color_set_opengl (&myIndicatorsParam.fBarColorOutline);
				_cairo_dock_set_blend_alpha ();
				glLineWidth (1.5);
				cairo_dock_stroke_gl_path (pFramePath, FALSE);
			}
			
			g_free (pCoords);
			glPopMatrix ();
		}
	}
}