2
* This file is a part of the Cairo-Dock project
4
* Copyright : (C) see the 'copyright' file.
5
* E-mail : see the 'copyright' file.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 3
10
* of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
25
#include <gtk/gtkgl.h>
27
#include <X11/extensions/Xrender.h>
29
#include <GL/glxext.h>
32
#include "cairo-dock-log.h"
33
#include "cairo-dock-dock-factory.h"
34
#include "cairo-dock-load.h"
35
#include "cairo-dock-internal-icons.h"
36
#include "cairo-dock-internal-system.h"
37
#include "cairo-dock-draw-opengl.h"
38
#include "cairo-dock-opengl.h"
40
extern CairoDockGLConfig g_openglConfig;
41
extern gboolean g_bUseOpenGL;
42
extern CairoDock *g_pMainDock;
43
extern CairoDockDesktopBackground *g_pFakeTransparencyDesktopBg;
44
extern int g_iXScreenWidth[2];
45
extern int g_iXScreenHeight[2];
46
extern gboolean g_bEasterEggs;
48
static inline gboolean _check_extension (const char *extName, const gchar *cExtensions)
50
g_return_val_if_fail (cExtensions != NULL, FALSE);
52
** Search for extName in the extensions string. Use of strstr()
53
** is not sufficient because extension names can be prefixes of
54
** other extension names. Could use strtok() but the constant
55
** string returned by glGetString can be in read-only memory.
57
char *p = (char *) cExtensions;
62
extNameLen = strlen(extName);
67
int n = strcspn(p, " ");
68
if ((extNameLen == n) && (strncmp(extName, p, n) == 0))
76
static gboolean _check_gl_extension (const char *extName)
78
const gchar *glExtensions = glGetString (GL_EXTENSIONS);
79
return _check_extension (extName, glExtensions);
81
static gboolean _check_client_glx_extension (const char *extName)
83
Display *display = gdk_x11_get_default_xdisplay ();
85
//const gchar *glxExtensions = glXQueryExtensionsString (display, screen);
86
const gchar *glxExtensions = glXGetClientString (display,GLX_EXTENSIONS);
87
return _check_extension (extName, glxExtensions);
91
static inline XVisualInfo *_get_visual_from_fbconfigs (GLXFBConfig *pFBConfigs, int iNumOfFBConfigs, Display *XDisplay)
93
XRenderPictFormat *pPictFormat;
94
XVisualInfo *pVisInfo = NULL;
96
for (i = 0; i < iNumOfFBConfigs; i++)
98
pVisInfo = glXGetVisualFromFBConfig (XDisplay, pFBConfigs[i]);
101
cd_warning ("this FBConfig has no visual.");
105
pPictFormat = XRenderFindVisualFormat (XDisplay, pVisInfo->visual);
108
cd_warning ("this visual has an unknown format.");
114
if (pPictFormat->direct.alphaMask > 0)
116
cd_message ("Strike, found a GLX visual with alpha-support !");
126
gboolean cairo_dock_initialize_opengl_backend (gboolean bToggleIndirectRendering, gboolean bForceOpenGL) // taken from a MacSlow's exemple.
128
memset (&g_openglConfig, 0, sizeof (CairoDockGLConfig));
129
g_bUseOpenGL = FALSE;
130
g_openglConfig.bHasBeenForced = bForceOpenGL;
131
gboolean bStencilBufferAvailable, bAlphaAvailable;
132
Display *XDisplay = gdk_x11_get_default_xdisplay ();
134
//\_________________ On cherche un visual qui reponde a tous les criteres.
135
GLXFBConfig *pFBConfigs;
136
XRenderPictFormat *pPictFormat = NULL;
137
int doubleBufferAttributes[] = {
138
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
139
GLX_RENDER_TYPE, GLX_RGBA_BIT,
140
GLX_DOUBLEBUFFER, True,
148
(g_bEasterEggs ? GLX_SAMPLE_BUFFERS_ARB : None), 1,
150
/*GL_MULTISAMPLEBUFFERS, 1,
151
GL_MULTISAMPLESAMPLES, 2,*/
154
XVisualInfo *pVisInfo = NULL;
155
int iNumOfFBConfigs = 0;
156
pFBConfigs = glXChooseFBConfig (XDisplay,
157
DefaultScreen (XDisplay),
158
doubleBufferAttributes,
160
cd_debug ("got %d FBConfig(s)", iNumOfFBConfigs);
161
bStencilBufferAvailable = TRUE;
162
bAlphaAvailable = TRUE;
164
pVisInfo = _get_visual_from_fbconfigs (pFBConfigs, iNumOfFBConfigs, XDisplay);
168
//\_________________ Si pas trouve, on en cherche un moins contraignant.
169
if (pVisInfo == NULL)
171
cd_warning ("couldn't find an appropriate visual, trying to get one without Stencil buffer\n(it may cause some little deterioration in the rendering) ...");
172
doubleBufferAttributes[16] = None;
173
pFBConfigs = glXChooseFBConfig (XDisplay,
174
DefaultScreen (XDisplay),
175
doubleBufferAttributes,
177
cd_debug ("this time got %d FBConfig(s)", iNumOfFBConfigs);
178
bStencilBufferAvailable = FALSE;
179
bAlphaAvailable = TRUE;
181
pVisInfo = _get_visual_from_fbconfigs (pFBConfigs, iNumOfFBConfigs, XDisplay);
186
//\_________________ Si toujours rien, on essaye avec la methode de gdkgl.
187
if (pVisInfo == NULL)
189
cd_warning ("still couldn't find an appropriate visual ourself, trying something else, this may not work with some drivers ...");
190
g_openglConfig.pGlConfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
194
GDK_GL_MODE_STENCIL);
195
bStencilBufferAvailable = TRUE;
196
bAlphaAvailable = TRUE;
198
if (g_openglConfig.pGlConfig == NULL)
200
cd_warning ("no luck, trying without double-buffer and stencil ...");
201
g_openglConfig.pGlConfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
204
bStencilBufferAvailable = FALSE;
205
bAlphaAvailable = TRUE;
209
//\_________________ Si toujours rien et si l'utilisateur n'en demord pas, on en cherche un sans canal alpha.
210
if (pVisInfo == NULL && g_openglConfig.pGlConfig == NULL && bForceOpenGL)
212
cd_warning ("we could not get an ARGB-visual, trying to get an RGB one (fake transparency will be used in return) ...");
213
g_openglConfig.bAlphaAvailable = FALSE;
214
doubleBufferAttributes[14] = None;
215
int i, iNumOfFBConfigs;
216
pFBConfigs = glXChooseFBConfig (XDisplay,
217
DefaultScreen (XDisplay),
218
doubleBufferAttributes,
220
bStencilBufferAvailable = FALSE;
221
bAlphaAvailable = FALSE;
222
cd_debug ("got %d FBConfig(s) without alpha channel", iNumOfFBConfigs);
223
for (i = 0; i < iNumOfFBConfigs; i++)
225
pVisInfo = glXGetVisualFromFBConfig (XDisplay, pFBConfigs[i]);
228
cd_warning ("this FBConfig has no visual.");
238
if (pVisInfo == NULL)
240
cd_warning ("still no visual, this is the last chance");
241
pVisInfo = glXChooseVisual (XDisplay,
242
DefaultScreen (XDisplay),
243
doubleBufferAttributes);
246
g_openglConfig.bStencilBufferAvailable = bStencilBufferAvailable;
247
g_openglConfig.bAlphaAvailable = bAlphaAvailable;
249
//\_________________ Si rien de chez rien, on quitte.
250
if (pVisInfo == NULL && g_openglConfig.pGlConfig == NULL)
252
cd_warning ("couldn't find a suitable GLX Visual, OpenGL can't be used.\n (sorry to say that, but your graphic card and/or its driver is crappy)");
256
//\_________________ On en deduit une config opengl valide pour les widgets gtk.
257
if (pVisInfo != NULL)
259
cd_message ("ok, got a visual");
260
g_openglConfig.pGlConfig = gdk_x11_gl_config_new_from_visualid (pVisInfo->visualid);
263
g_return_val_if_fail (g_openglConfig.pGlConfig != NULL, FALSE);
266
//\_________________ On regarde si le rendu doit etre indirect ou pas.
267
g_openglConfig.bIndirectRendering = bToggleIndirectRendering;
268
if (glXQueryVersion(XDisplay, &g_openglConfig.iGlxMajor, &g_openglConfig.iGlxMinor) == False)
270
cd_warning ("GLX not available !\nFear the worst !");
274
if (g_openglConfig.iGlxMajor <= 1 && g_openglConfig.iGlxMinor < 3) // on a besoin de GLX >= 1.3 pour les pbuffers; mais si on a l'extension GLX_SGIX_pbuffer et un version inferieure, ca marche quand meme.
276
if (! _check_client_glx_extension ("GLX_SGIX_pbuffer"))
278
cd_warning ("No pbuffer extension in GLX.\n this might affect the drawing of some applets which are inside a dock");
282
cd_warning ("GLX version too old (%d.%d).\nCairo-Dock needs at least GLX 1.3. Indirect rendering will be toggled on/off as a workaround.", g_openglConfig.iGlxMajor, g_openglConfig.iGlxMinor);
283
g_openglConfig.bPBufferAvailable = TRUE;
284
g_openglConfig.bIndirectRendering = ! bToggleIndirectRendering;
289
g_openglConfig.bPBufferAvailable = TRUE;
293
//\_________________ on verifier les capacites des textures.
294
g_openglConfig.bTextureFromPixmapAvailable = _check_client_glx_extension ("GLX_EXT_texture_from_pixmap");
295
if (g_openglConfig.bTextureFromPixmapAvailable)
297
g_openglConfig.bindTexImage = (gpointer)glXGetProcAddress ("glXBindTexImageEXT");
298
g_openglConfig.releaseTexImage = (gpointer)glXGetProcAddress ("glXReleaseTexImageEXT");
299
g_openglConfig.bTextureFromPixmapAvailable = (g_openglConfig.bindTexImage && g_openglConfig.releaseTexImage);
307
static GLXPbuffer _cairo_dock_create_pbuffer (int iWidth, int iHeight, GLXContext *pContext)
309
Display *XDisplay = gdk_x11_get_default_xdisplay ();
311
GLXFBConfig *pFBConfigs;
312
XRenderPictFormat *pPictFormat = NULL;
314
GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
315
GLX_RENDER_TYPE, GLX_RGBA_BIT,
323
XVisualInfo *pVisInfo = NULL;
324
int i, iNumOfFBConfigs = 0;
325
pFBConfigs = glXChooseFBConfig (XDisplay,
326
DefaultScreen (XDisplay),
329
if (iNumOfFBConfigs == 0)
331
cd_warning ("No suitable visual could be found for pbuffer\n this might affect the drawing of some applets which are inside a dock");
335
cd_debug (" -> %d FBConfig(s) pour le pbuffer", iNumOfFBConfigs);
337
int pbufAttribs [] = {
338
GLX_PBUFFER_WIDTH, iWidth,
339
GLX_PBUFFER_HEIGHT, iHeight,
340
GLX_LARGEST_PBUFFER, True,
342
GLXPbuffer pbuffer = glXCreatePbuffer (XDisplay, pFBConfigs[0], pbufAttribs);
344
pVisInfo = glXGetVisualFromFBConfig (XDisplay, pFBConfigs[0]);
346
GdkGLContext *pGlContext = gtk_widget_get_gl_context (g_pMainDock->container.pWidget);
347
GLXContext mainContext = GDK_GL_CONTEXT_GLXCONTEXT (pGlContext);
348
*pContext = glXCreateContext (XDisplay, pVisInfo, mainContext, ! g_openglConfig.bIndirectRendering);
356
void cairo_dock_create_icon_pbuffer (void)
358
if (! g_openglConfig.pGlConfig || ! g_openglConfig.bPBufferAvailable)
360
int iWidth = 0, iHeight = 0;
362
for (i = 0; i < CAIRO_DOCK_NB_TYPES; i += 2)
364
iWidth = MAX (iWidth, myIcons.tIconAuthorizedWidth[i]);
365
iHeight = MAX (iHeight, myIcons.tIconAuthorizedHeight[i]);
371
iWidth *= (1 + myIcons.fAmplitude);
372
iHeight *= (1 + myIcons.fAmplitude);
374
cd_debug ("%s (%dx%d)", __func__, iWidth, iHeight);
375
if (g_openglConfig.iIconPbufferWidth != iWidth || g_openglConfig.iIconPbufferHeight != iHeight)
377
Display *XDisplay = gdk_x11_get_default_xdisplay ();
378
if (g_openglConfig.iconPbuffer != 0)
380
glXDestroyPbuffer (XDisplay, g_openglConfig.iconPbuffer);
381
glXDestroyContext (XDisplay, g_openglConfig.iconContext);
382
g_openglConfig.iconContext = 0;
384
g_openglConfig.iconPbuffer = _cairo_dock_create_pbuffer (iWidth, iHeight, &g_openglConfig.iconContext);
385
g_openglConfig.iIconPbufferWidth = iWidth;
386
g_openglConfig.iIconPbufferHeight = iHeight;
388
g_print ("activating pbuffer, usually buggy drivers will crash here ...");
389
if (g_openglConfig.iconPbuffer != 0 && g_openglConfig.iconContext != 0 && glXMakeCurrent (XDisplay, g_openglConfig.iconPbuffer, g_openglConfig.iconContext))
391
glMatrixMode(GL_PROJECTION);
393
glOrtho(0, iWidth, 0, iHeight, 0.0, 500.0);
394
glMatrixMode (GL_MODELVIEW);
397
gluLookAt (0., 0., 3.,
401
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
404
g_print (" ok, they are fine enough.\n");
408
void cairo_dock_destroy_icon_pbuffer (void)
410
Display *XDisplay = gdk_x11_get_default_xdisplay ();
411
if (g_openglConfig.iconPbuffer != 0)
413
glXDestroyPbuffer (XDisplay, g_openglConfig.iconPbuffer);
414
g_openglConfig.iconPbuffer = 0;
416
if (g_openglConfig.iconContext != 0)
418
glXDestroyContext (XDisplay, g_openglConfig.iconContext);
419
g_openglConfig.iconContext = 0;
421
g_openglConfig.iIconPbufferWidth = 0;
422
g_openglConfig.iIconPbufferHeight = 0;
425
gboolean cairo_dock_begin_draw_icon (Icon *pIcon, CairoContainer *pContainer)
427
if (CAIRO_DOCK_IS_DESKLET (pContainer))
429
GdkGLContext *pGlContext = gtk_widget_get_gl_context (pContainer->pWidget);
430
GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (pContainer->pWidget);
431
if (! gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
434
cairo_dock_set_ortho_view (pContainer->iWidth, pContainer->iHeight);
436
else if (g_openglConfig.iconContext != 0)
438
Display *XDisplay = gdk_x11_get_default_xdisplay ();
439
if (! glXMakeCurrent (XDisplay, g_openglConfig.iconPbuffer, g_openglConfig.iconContext))
442
glTranslatef (g_openglConfig.iIconPbufferWidth/2, g_openglConfig.iIconPbufferHeight/2, - g_openglConfig.iIconPbufferHeight/2);
447
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
449
glColor4f(1., 1., 1., 1.);
451
glScalef (1., -1., 1.);
456
void cairo_dock_end_draw_icon (Icon *pIcon, CairoContainer *pContainer)
458
g_return_if_fail (pIcon->iIconTexture != 0);
459
// taille de la texture
461
cairo_dock_get_icon_extent (pIcon, pContainer, &iWidth, &iHeight);
463
// copie dans notre texture
464
glEnable (GL_TEXTURE_2D);
465
glBindTexture (GL_TEXTURE_2D, pIcon->iIconTexture);
466
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
468
glBlendFunc (GL_ZERO, GL_ONE);
469
glColor4f(1., 1., 1., 1.);
472
if (CAIRO_DOCK_IS_DESKLET (pContainer))
474
x = (pContainer->iWidth - iWidth)/2;
475
y = (pContainer->iHeight - iHeight)/2;
479
x = (g_openglConfig.iIconPbufferWidth - iWidth)/2;
480
y = (g_openglConfig.iIconPbufferHeight - iHeight)/2;
483
glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, x, y, iWidth, iHeight, 0); // target, num mipmap, format, x,y, w,h, border.
484
glDisable (GL_TEXTURE_2D);
485
glDisable (GL_BLEND);
488
if (CAIRO_DOCK_IS_DESKLET (pContainer))
490
cairo_dock_set_perspective_view (pContainer->iWidth, pContainer->iHeight);
492
GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (pContainer->pWidget);
493
gdk_gl_drawable_gl_end (pGlDrawable);
500
void cairo_dock_set_perspective_view (int iWidth, int iHeight)
502
glMatrixMode(GL_PROJECTION);
504
gluPerspective(60.0, 1.0*(GLfloat)iWidth/(GLfloat)iHeight, 1., 4*iHeight);
505
glMatrixMode (GL_MODELVIEW);
508
gluLookAt (0., 0., 3.,
511
glTranslatef (0., 0., -iHeight*(sqrt(3)/2) - 1);
514
void cairo_dock_set_ortho_view (int iWidth, int iHeight)
516
glMatrixMode(GL_PROJECTION);
518
glOrtho(0, iWidth, 0, iHeight, 0.0, 500.0);
519
glMatrixMode (GL_MODELVIEW);
522
gluLookAt (0/2, 0/2, 3.,
525
glTranslatef (iWidth/2, iHeight/2, - iHeight/2);
529
void cairo_dock_apply_desktop_background_opengl (CairoContainer *pContainer)
531
if (! mySystem.bUseFakeTransparency || ! g_pFakeTransparencyDesktopBg || g_pFakeTransparencyDesktopBg->iTexture == 0)
534
_cairo_dock_enable_texture ();
535
_cairo_dock_set_blend_source ();
536
_cairo_dock_set_alpha (1.);
537
glBindTexture (GL_TEXTURE_2D, g_pFakeTransparencyDesktopBg->iTexture);
540
glTexCoord2f (1.*(pContainer->iWindowPositionX + 0.)/g_iXScreenWidth[CAIRO_DOCK_HORIZONTAL],
541
1.*(pContainer->iWindowPositionY + 0.)/g_iXScreenHeight[CAIRO_DOCK_HORIZONTAL]);
542
glVertex3f (0., pContainer->iHeight, 0.); // Top Left.
544
glTexCoord2f (1.*(pContainer->iWindowPositionX + pContainer->iWidth)/g_iXScreenWidth[CAIRO_DOCK_HORIZONTAL], 1.*(pContainer->iWindowPositionY + 0.)/g_iXScreenHeight[CAIRO_DOCK_HORIZONTAL]);
545
glVertex3f (pContainer->iWidth, pContainer->iHeight, 0.); // Top Right
547
glTexCoord2f (1.*(pContainer->iWindowPositionX + pContainer->iWidth)/g_iXScreenWidth[CAIRO_DOCK_HORIZONTAL], 1.*(pContainer->iWindowPositionY + pContainer->iHeight)/g_iXScreenHeight[CAIRO_DOCK_HORIZONTAL]);
548
glVertex3f (pContainer->iWidth, 0., 0.); // Bottom Right
550
glTexCoord2f (1.*(pContainer->iWindowPositionX + 0.)/g_iXScreenWidth[CAIRO_DOCK_HORIZONTAL], 1.*(pContainer->iWindowPositionY + pContainer->iHeight)/g_iXScreenHeight[CAIRO_DOCK_HORIZONTAL]);
551
glVertex3f (0., 0., 0.); // Bottom Left
554
_cairo_dock_disable_texture ();
560
static void _cairo_dock_post_initialize_opengl_backend (GtkWidget* pWidget, gpointer data) // initialisation necessitant un contexte opengl.
562
static gboolean bChecked=FALSE;
565
GdkGLContext* pGlContext = gtk_widget_get_gl_context (pWidget);
566
GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (pWidget);
567
if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
571
g_openglConfig.bNonPowerOfTwoAvailable = _check_gl_extension ("GL_ARB_texture_non_power_of_two");
573
g_print ("OpenGL config summary :\n - bNonPowerOfTwoAvailable : %d\n - bPBufferAvailable : %d\n - direct rendering : %d\n - bTextureFromPixmapAvailable : %d\n - GLX version : %d.%d\n - OpenGL version: %s\n - OpenGL vendor: %s\n - OpenGL renderer: %s\n\n",
574
g_openglConfig.bNonPowerOfTwoAvailable,
575
g_openglConfig.bPBufferAvailable,
576
!g_openglConfig.bIndirectRendering,
577
g_openglConfig.bTextureFromPixmapAvailable,
578
g_openglConfig.iGlxMajor,
579
g_openglConfig.iGlxMinor,
580
glGetString (GL_VERSION),
581
glGetString (GL_VENDOR),
582
glGetString (GL_RENDERER));
584
gdk_gl_drawable_gl_end (pGlDrawable);
588
static void _reset_opengl_context (GtkWidget* pWidget, gpointer data)
593
GdkGLContext* pGlContext = gtk_widget_get_gl_context (pWidget);
594
GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (pWidget);
595
if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
598
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
601
glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
605
glEnable (GL_MULTISAMPLE_ARB);
607
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // GL_MODULATE / GL_DECAL / GL_BLEND
609
glTexParameteri (GL_TEXTURE_2D,
610
GL_TEXTURE_MIN_FILTER,
611
GL_LINEAR_MIPMAP_LINEAR);
612
glTexParameteri (GL_TEXTURE_2D,
613
GL_TEXTURE_MAG_FILTER,
616
gdk_gl_drawable_gl_end (pGlDrawable);
618
void cairo_dock_set_gl_capabilities (GtkWidget *pWindow)
620
gboolean bFirstContainer = (! g_pMainDock || ! g_pMainDock->container.pWidget);
621
GdkGLContext *pMainGlContext = (bFirstContainer ? NULL : gtk_widget_get_gl_context (g_pMainDock->container.pWidget)); // NULL si on est en train de creer la fenetre du main dock, ce qui nous convient.
622
gtk_widget_set_gl_capability (pWindow,
623
g_openglConfig.pGlConfig,
624
pMainGlContext, // on partage les ressources entre les contextes.
625
! g_openglConfig.bIndirectRendering, // TRUE <=> direct connection to the graphics system.
627
if (bFirstContainer) // c'est donc le 1er container cree, on finit l'initialisation du backend opengl.
628
g_signal_connect (G_OBJECT (pWindow),
630
G_CALLBACK (_cairo_dock_post_initialize_opengl_backend),
632
g_signal_connect_after (G_OBJECT (pWindow),
634
G_CALLBACK (_reset_opengl_context),