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