janitorial: Remove remaining NULL checks before free() (found by Smatch).
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  * Copyright (c) 2005 Raphael Junqueira
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winternl.h"
35 #include "winnt.h"
36
37 #include "opengl_ext.h"
38 #ifdef HAVE_GL_GLU_H
39 #undef far
40 #undef near
41 #include <GL/glu.h>
42 #endif
43 #include "wine/library.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
47 WINE_DECLARE_DEBUG_CHANNEL(opengl);
48
49 typedef struct wine_wgl_s {
50     BOOL WINAPI  (*p_wglDeleteContext)(HGLRC hglrc);
51     HGLRC WINAPI (*p_wglGetCurrentContext)(void);
52     HDC WINAPI   (*p_wglGetCurrentDC)(void);
53     PROC WINAPI  (*p_wglGetProcAddress)(LPCSTR  lpszProc);
54     BOOL WINAPI  (*p_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
55
56     void WINAPI  (*p_wglGetIntegerv)(GLenum pname, GLint* params);
57 } wine_wgl_t;
58
59 /** global wgl object */
60 static wine_wgl_t wine_wgl;
61
62 /* x11drv GDI escapes */
63 #define X11DRV_ESCAPE 6789
64 enum x11drv_escape_codes
65 {
66     X11DRV_GET_DISPLAY,         /* get X11 display for a DC */
67     X11DRV_GET_DRAWABLE,        /* get current drawable for a DC */
68     X11DRV_GET_FONT,            /* get current X font for a DC */
69     X11DRV_SET_DRAWABLE,        /* set current drawable for a DC */
70     X11DRV_START_EXPOSURES,     /* start graphics exposures */
71     X11DRV_END_EXPOSURES,       /* end graphics exposures */
72     X11DRV_GET_DCE,             /* get the DCE pointer */
73     X11DRV_SET_DCE,             /* set the DCE pointer */
74     X11DRV_GET_GLX_DRAWABLE,    /* get current glx drawable for a DC */
75     X11DRV_SYNC_PIXMAP          /* sync the dibsection to its pixmap */
76 };
77
78 void (*wine_tsx11_lock_ptr)(void) = NULL;
79 void (*wine_tsx11_unlock_ptr)(void) = NULL;
80
81 static GLXContext default_cx = NULL;
82 static Display *default_display;  /* display to use for default context */
83
84 static HMODULE opengl32_handle;
85
86 static void* (*p_glXGetProcAddressARB)(const GLubyte *);
87
88 static char  internal_gl_disabled_extensions[512];
89 static char* internal_gl_extensions = NULL;
90
91 typedef struct wine_glcontext {
92   HDC hdc;
93   Display *display;
94   XVisualInfo *vis;
95   GLXFBConfig fb_conf;
96   GLXContext ctx;
97   BOOL do_escape;
98   struct wine_glcontext *next;
99   struct wine_glcontext *prev;
100 } Wine_GLContext;
101
102 void enter_gl(void)
103 {
104     Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
105     
106     if (curctx && curctx->do_escape)
107     {
108         enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
109         ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
110     }
111
112     wine_tsx11_lock_ptr();
113     return;
114 }
115
116 /* retrieve the X display to use on a given DC */
117 inline static Display *get_display( HDC hdc )
118 {
119     Display *display;
120     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
121
122     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
123                     sizeof(display), (LPSTR)&display )) display = NULL;
124     return display;
125 }
126
127 /***********************************************************************
128  *              wglCreateLayerContext (OPENGL32.@)
129  */
130 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
131                                    int iLayerPlane) {
132   TRACE("(%p,%d)\n", hdc, iLayerPlane);
133
134   if (iLayerPlane == 0) {
135       return wglCreateContext(hdc);
136   }
137   FIXME(" no handler for layer %d\n", iLayerPlane);
138
139   return NULL;
140 }
141
142 /***********************************************************************
143  *              wglCopyContext (OPENGL32.@)
144  */
145 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
146                            HGLRC hglrcDst,
147                            UINT mask) {
148   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
149
150   return FALSE;
151 }
152
153 /***********************************************************************
154  *              wglDeleteContext (OPENGL32.@)
155  */
156 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
157 {
158     TRACE("(%p)\n", hglrc);
159     return wine_wgl.p_wglDeleteContext(hglrc);
160 }
161
162 /***********************************************************************
163  *              wglDescribeLayerPlane (OPENGL32.@)
164  */
165 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
166                                   int iPixelFormat,
167                                   int iLayerPlane,
168                                   UINT nBytes,
169                                   LPLAYERPLANEDESCRIPTOR plpd) {
170   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
171
172   return FALSE;
173 }
174
175 /***********************************************************************
176  *              wglGetCurrentContext (OPENGL32.@)
177  */
178 HGLRC WINAPI wglGetCurrentContext(void) {
179     TRACE("\n");
180     return wine_wgl.p_wglGetCurrentContext();
181 }
182
183 /***********************************************************************
184  *              wglGetCurrentDC (OPENGL32.@)
185  */
186 HDC WINAPI wglGetCurrentDC(void) {
187     TRACE("\n");
188     return wine_wgl.p_wglGetCurrentDC();
189 }
190
191 /***********************************************************************
192  *              wglGetLayerPaletteEntries (OPENGL32.@)
193  */
194 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
195                                      int iLayerPlane,
196                                      int iStart,
197                                      int cEntries,
198                                      const COLORREF *pcr) {
199   FIXME("(): stub !\n");
200
201   return 0;
202 }
203
204 /***********************************************************************
205  *              wglGetProcAddress (OPENGL32.@)
206  */
207 static int compar(const void *elt_a, const void *elt_b) {
208   return strcmp(((const OpenGL_extension *) elt_a)->name,
209                 ((const OpenGL_extension *) elt_b)->name);
210 }
211
212 PROC WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
213   void *local_func;
214   OpenGL_extension  ext;
215   const OpenGL_extension *ext_ret;
216
217   TRACE("(%s)\n", lpszProc);
218
219   /* First, look if it's not already defined in the 'standard' OpenGL functions */
220   if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
221     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
222     return local_func;
223   }
224
225   if (p_glXGetProcAddressARB == NULL) {
226     ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
227     return NULL;
228   }
229   
230   /* After that, search in the thunks to find the real name of the extension */
231   ext.name = lpszProc;
232   ext_ret = (const OpenGL_extension *) bsearch(&ext, extension_registry,
233                                          extension_registry_size, sizeof(OpenGL_extension), compar);
234
235   /* If nothing was found, we are looking for a WGL extension */
236   if (ext_ret == NULL) {
237     return wine_wgl.p_wglGetProcAddress(lpszProc);
238   } else { /* We are looking for an OpenGL extension */
239     const char *glx_name = ext_ret->glx_name ? ext_ret->glx_name : ext_ret->name;
240     ENTER_GL();
241     local_func = p_glXGetProcAddressARB( (const GLubyte*)glx_name);
242     LEAVE_GL();
243     
244     /* After that, look at the extensions defined in the Linux OpenGL library */
245     if (local_func == NULL) {
246       char buf[256];
247       void *ret = NULL;
248
249       /* Remove the 3 last letters (EXT, ARB, ...).
250
251          I know that some extensions have more than 3 letters (MESA, NV,
252          INTEL, ...), but this is only a stop-gap measure to fix buggy
253          OpenGL drivers (moreover, it is only useful for old 1.0 apps
254          that query the glBindTextureEXT extension).
255       */
256       memcpy(buf, glx_name, strlen(glx_name) - 3);
257       buf[strlen(glx_name) - 3] = '\0';
258       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
259
260       ret = GetProcAddress(opengl32_handle, buf);
261       if (ret != NULL) {
262         TRACE(" found function in main OpenGL library (%p) !\n", ret);
263       } else {
264         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, glx_name);
265       }
266
267       return ret;
268     } else {
269       TRACE(" returning function  (%p)\n", ext_ret->func);
270       extension_funcs[ext_ret - extension_registry] = local_func;
271
272       return ext_ret->func;
273     }
274   }
275 }
276
277 /***********************************************************************
278  *              wglRealizeLayerPalette (OPENGL32.@)
279  */
280 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
281                                    int iLayerPlane,
282                                    BOOL bRealize) {
283   FIXME("()\n");
284
285   return FALSE;
286 }
287
288 /***********************************************************************
289  *              wglSetLayerPaletteEntries (OPENGL32.@)
290  */
291 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
292                                      int iLayerPlane,
293                                      int iStart,
294                                      int cEntries,
295                                      const COLORREF *pcr) {
296   FIXME("(): stub !\n");
297
298   return 0;
299 }
300
301 /***********************************************************************
302  *              wglShareLists (OPENGL32.@)
303  */
304 BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2) {
305     TRACE("(%p, %p)\n", hglrc1, hglrc2);
306     return wine_wgl.p_wglShareLists(hglrc1, hglrc2);
307 }
308
309 /***********************************************************************
310  *              wglSwapLayerBuffers (OPENGL32.@)
311  */
312 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
313                                 UINT fuPlanes) {
314   TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
315
316   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
317     if (!SwapBuffers(hdc)) return FALSE;
318     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
319   }
320
321   if (fuPlanes) {
322     WARN("Following layers unhandled : %08x\n", fuPlanes);
323   }
324
325   return TRUE;
326 }
327
328 #ifdef HAVE_GL_GLU_H
329
330 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
331 {
332     vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;  
333     vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;  
334     vertex[2] = 0.0;
335 }
336
337 static void tess_callback_vertex(GLvoid *vertex)
338 {
339     GLdouble *dbl = vertex;
340     TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
341     glVertex3dv(vertex);
342 }
343
344 static void tess_callback_begin(GLenum which)
345 {
346     TRACE("%d\n", which);
347     glBegin(which);
348 }
349
350 static void tess_callback_end(void)
351 {
352     TRACE("\n");
353     glEnd();
354 }
355
356 /***********************************************************************
357  *              wglUseFontOutlines_common
358  */
359 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
360                                       DWORD first,
361                                       DWORD count,
362                                       DWORD listBase,
363                                       FLOAT deviation,
364                                       FLOAT extrusion,
365                                       int format,
366                                       LPGLYPHMETRICSFLOAT lpgmf,
367                                       BOOL unicode)
368 {
369     UINT glyph;
370     const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
371     GLUtesselator *tess;
372     LOGFONTW lf;
373     HFONT old_font, unscaled_font;
374     UINT em_size = 1024;
375     RECT rc;
376
377     TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
378           listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
379
380
381     ENTER_GL();
382     tess = gluNewTess();
383     if(tess)
384     {
385         gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
386         gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
387         gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
388     }
389     LEAVE_GL();
390
391     if(!tess) return FALSE;
392
393     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
394     rc.left = rc.right = rc.bottom = 0;
395     rc.top = em_size;
396     DPtoLP(hdc, (POINT*)&rc, 2);
397     lf.lfHeight = -abs(rc.top - rc.bottom);
398     lf.lfOrientation = lf.lfEscapement = 0;
399     unscaled_font = CreateFontIndirectW(&lf);
400     old_font = SelectObject(hdc, unscaled_font);
401
402     for (glyph = first; glyph < first + count; glyph++)
403     {
404         DWORD needed;
405         GLYPHMETRICS gm;
406         BYTE *buf;
407         TTPOLYGONHEADER *pph;
408         TTPOLYCURVE *ppc;
409         GLdouble *vertices;
410
411         if(unicode)
412             needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
413         else
414             needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
415
416         if(needed == GDI_ERROR)
417             goto error;
418
419         buf = HeapAlloc(GetProcessHeap(), 0, needed);
420         vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
421
422         if(unicode)
423             GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
424         else
425             GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
426
427         TRACE("glyph %d\n", glyph);
428
429         if(lpgmf)
430         {
431             lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
432             lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
433             lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
434             lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
435             lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
436             lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
437
438             TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
439                   lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); 
440             lpgmf++;
441         }
442
443         ENTER_GL();
444         glNewList(listBase++, GL_COMPILE);
445         gluTessBeginPolygon(tess, NULL);
446
447         pph = (TTPOLYGONHEADER*)buf;
448         while((BYTE*)pph < buf + needed)
449         {
450             TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
451
452             gluTessBeginContour(tess);
453
454             fixed_to_double(pph->pfxStart, em_size, vertices);
455             gluTessVertex(tess, vertices, vertices);
456             vertices += 3;
457
458             ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
459             while((char*)ppc < (char*)pph + pph->cb)
460             {
461                 int i;
462
463                 switch(ppc->wType) {
464                 case TT_PRIM_LINE:
465                     for(i = 0; i < ppc->cpfx; i++)
466                     {
467                         TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
468                         fixed_to_double(ppc->apfx[i], em_size, vertices); 
469                         gluTessVertex(tess, vertices, vertices);
470                         vertices += 3;
471                     }
472                     break;
473
474                 case TT_PRIM_QSPLINE:
475                     for(i = 0; i < ppc->cpfx/2; i++)
476                     {
477                         /* FIXME just connecting the control points for now */
478                         TRACE("\t\tcurve  %d,%d %d,%d\n",
479                               ppc->apfx[i * 2].x.value,     ppc->apfx[i * 3].y.value,
480                               ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
481                         fixed_to_double(ppc->apfx[i * 2], em_size, vertices); 
482                         gluTessVertex(tess, vertices, vertices);
483                         vertices += 3;
484                         fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices); 
485                         gluTessVertex(tess, vertices, vertices);
486                         vertices += 3;
487                     }
488                     break;
489                 default:
490                     ERR("\t\tcurve type = %d\n", ppc->wType);
491                     gluTessEndContour(tess);
492                     goto error_in_list;
493                 }
494
495                 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
496                                      (ppc->cpfx - 1) * sizeof(POINTFX));
497             }
498             gluTessEndContour(tess);
499             pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
500         }
501
502 error_in_list:
503         gluTessEndPolygon(tess);
504         glTranslated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
505         glEndList();
506         LEAVE_GL();
507         HeapFree(GetProcessHeap(), 0, buf);
508         HeapFree(GetProcessHeap(), 0, vertices);
509     }
510
511  error:
512     DeleteObject(SelectObject(hdc, old_font));
513     gluDeleteTess(tess);
514     return TRUE;
515
516 }
517
518 #else /* HAVE_GL_GLU_H */
519
520 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
521                                       DWORD first,
522                                       DWORD count,
523                                       DWORD listBase,
524                                       FLOAT deviation,
525                                       FLOAT extrusion,
526                                       int format,
527                                       LPGLYPHMETRICSFLOAT lpgmf,
528                                       BOOL unicode)
529 {
530     FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
531     return FALSE;
532 }
533
534 #endif /* HAVE_GL_GLU_H */
535
536 /***********************************************************************
537  *              wglUseFontOutlinesA (OPENGL32.@)
538  */
539 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
540                                 DWORD first,
541                                 DWORD count,
542                                 DWORD listBase,
543                                 FLOAT deviation,
544                                 FLOAT extrusion,
545                                 int format,
546                                 LPGLYPHMETRICSFLOAT lpgmf)
547 {
548     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
549 }
550
551 /***********************************************************************
552  *              wglUseFontOutlinesW (OPENGL32.@)
553  */
554 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
555                                 DWORD first,
556                                 DWORD count,
557                                 DWORD listBase,
558                                 FLOAT deviation,
559                                 FLOAT extrusion,
560                                 int format,
561                                 LPGLYPHMETRICSFLOAT lpgmf)
562 {
563     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
564 }
565
566 const GLubyte * internal_glGetString(GLenum name) {
567   const char* GL_Extensions = NULL;
568   
569   if (GL_EXTENSIONS != name) {
570     return glGetString(name);
571   }
572
573   if (NULL == internal_gl_extensions) {
574     GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
575
576     TRACE("GL_EXTENSIONS reported:\n");  
577     if (NULL == GL_Extensions) {
578       ERR("GL_EXTENSIONS returns NULL\n");      
579       return NULL;
580     } else {
581       size_t len = strlen(GL_Extensions);
582       internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
583
584       while (*GL_Extensions != 0x00) {
585         const char* Start = GL_Extensions;
586         char        ThisExtn[256];
587          
588         memset(ThisExtn, 0x00, sizeof(ThisExtn));
589         while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
590           GL_Extensions++;
591         }
592         memcpy(ThisExtn, Start, (GL_Extensions - Start));
593         TRACE("- %s:", ThisExtn);
594         
595         /* test if supported API is disabled by config */
596         if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
597           strcat(internal_gl_extensions, " ");
598           strcat(internal_gl_extensions, ThisExtn);
599           TRACE(" active\n");
600         } else {
601           TRACE(" deactived (by config)\n");
602         }
603
604         if (*GL_Extensions == ' ') GL_Extensions++;
605       }
606     }
607   }
608   return (const GLubyte *) internal_gl_extensions;
609 }
610
611 void internal_glGetIntegerv(GLenum pname, GLint* params) {
612   TRACE("pname: 0x%x, params %p\n", pname, params);
613   glGetIntegerv(pname, params);
614   /* A few parameters like GL_DEPTH_BITS differ between WGL and GLX, the wglGetIntegerv helper function handles those */
615   wine_wgl.p_wglGetIntegerv(pname, params);
616 }
617
618
619 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
620    include all dependencies
621 */
622 #ifndef SONAME_LIBGL
623 #define SONAME_LIBGL "libGL.so"
624 #endif
625
626 /* This is for brain-dead applications that use OpenGL functions before even
627    creating a rendering context.... */
628 static BOOL process_attach(void)
629 {
630   XWindowAttributes win_attr;
631   Visual *rootVisual;
632   int num;
633   XVisualInfo template;
634   HDC hdc;
635   XVisualInfo *vis = NULL;
636   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
637   HMODULE mod = GetModuleHandleA( "winex11.drv" );
638   void *opengl_handle;
639   DWORD size = sizeof(internal_gl_disabled_extensions);
640   HKEY hkey = 0;
641
642   if (!root || !mod)
643   {
644       ERR("X11DRV not loaded. Cannot create default context.\n");
645       return FALSE;
646   }
647
648   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
649   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
650
651   /* Load WGL function pointers from winex11.drv */
652   wine_wgl.p_wglDeleteContext = (void *)GetProcAddress(mod, "wglDeleteContext");
653   wine_wgl.p_wglGetCurrentContext = (void *)GetProcAddress(mod, "wglGetCurrentContext");
654   wine_wgl.p_wglGetCurrentDC = (void *)GetProcAddress(mod, "wglGetCurrentDC");
655   wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod, "wglGetProcAddress");
656   wine_wgl.p_wglShareLists = (void *)GetProcAddress(mod, "wglShareLists");
657
658   /* Interal WGL function */
659   wine_wgl.p_wglGetIntegerv = (void *)GetProcAddress(mod, "wglGetIntegerv");
660
661   hdc = GetDC(0);
662   default_display = get_display( hdc );
663   ReleaseDC( 0, hdc );
664   if (!default_display)
665   {
666       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
667       return FALSE;
668   }
669
670   ENTER_GL();
671
672   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
673      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
674      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
675      with mismatched visuals.  Note that the Root Window visual may not be double
676      buffered, so apps actually attempting to render this way may flicker */
677   if (XGetWindowAttributes( default_display, root, &win_attr ))
678   {
679     rootVisual = win_attr.visual;
680   }
681   else
682   {
683     /* Get the default visual, since we can't seem to get the attributes from the
684        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
685     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
686   }
687
688   template.visualid = XVisualIDFromVisual(rootVisual);
689   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
690   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
691   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
692   XFree(vis);
693   LEAVE_GL();
694
695   opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
696   if (opengl_handle != NULL) {
697    p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
698    wine_dlclose(opengl_handle, NULL, 0);
699    if (p_glXGetProcAddressARB == NULL)
700            TRACE("could not find glXGetProcAddressARB in libGL.\n");
701   }
702
703   internal_gl_disabled_extensions[0] = 0;
704   if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
705     if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
706       TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
707     }
708     RegCloseKey(hkey);
709   }
710
711   if (default_cx == NULL) {
712     ERR("Could not create default context.\n");
713   }
714   return TRUE;
715 }
716
717
718 /**********************************************************************/
719
720 static void process_detach(void)
721 {
722   glXDestroyContext(default_display, default_cx);
723
724   HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
725 }
726
727 /***********************************************************************
728  *           OpenGL initialisation routine
729  */
730 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
731 {
732     switch(reason)
733     {
734     case DLL_PROCESS_ATTACH:
735         opengl32_handle = hinst;
736         DisableThreadLibraryCalls(hinst);
737         return process_attach();
738     case DLL_PROCESS_DETACH:
739         process_detach();
740         break;
741     }
742     return TRUE;
743 }