INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winerror.h"
30
31 #include "wgl.h"
32 #include "opengl_ext.h"
33 #include "wine/debug.h"
34 #include "wine/port.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
37
38 /* x11drv GDI escapes */
39 #define X11DRV_ESCAPE 6789
40 enum x11drv_escape_codes
41 {
42     X11DRV_GET_DISPLAY,   /* get X11 display for a DC */
43     X11DRV_GET_DRAWABLE,  /* get current drawable for a DC */
44     X11DRV_GET_FONT,      /* get current X font for a DC */
45 };
46
47 void (*wine_tsx11_lock_ptr)(void) = NULL;
48 void (*wine_tsx11_unlock_ptr)(void) = NULL;
49
50 static GLXContext default_cx = NULL;
51 static Display *default_display;  /* display to use for default context */
52
53 static void *(*p_glXGetProcAddressARB)(const GLubyte *);
54
55 typedef struct wine_glcontext {
56   HDC hdc;
57   Display *display;
58   GLXContext ctx;
59   XVisualInfo *vis;
60   struct wine_glcontext *next;
61   struct wine_glcontext *prev;
62 } Wine_GLContext;
63 static Wine_GLContext *context_list;
64
65 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
66 {
67     Wine_GLContext *ret;
68     for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
69     return ret;
70 }
71
72 static inline void free_context(Wine_GLContext *context)
73 {
74   if (context->next != NULL) context->next->prev = context->prev;
75   if (context->prev != NULL) context->prev->next = context->next;
76   else context_list = context->next;
77
78   HeapFree(GetProcessHeap(), 0, context);
79 }
80
81 static inline Wine_GLContext *alloc_context(void)
82 {
83   Wine_GLContext *ret;
84
85   if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
86   {
87       ret->next = context_list;
88       if (context_list) context_list->prev = ret;
89       context_list = ret;
90   }
91   return ret;
92 }
93
94 inline static BOOL is_valid_context( Wine_GLContext *ctx )
95 {
96     Wine_GLContext *ptr;
97     for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
98     return (ptr != NULL);
99 }
100
101 /* retrieve the X display to use on a given DC */
102 inline static Display *get_display( HDC hdc )
103 {
104     Display *display;
105     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
106
107     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
108                     sizeof(display), (LPSTR)&display )) display = NULL;
109     return display;
110 }
111
112
113 /* retrieve the X drawable to use on a given DC */
114 inline static Drawable get_drawable( HDC hdc )
115 {
116     Drawable drawable;
117     enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
118
119     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
120                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
121     return drawable;
122 }
123
124
125 /* retrieve the X drawable to use on a given DC */
126 inline static Font get_font( HDC hdc )
127 {
128     Font font;
129     enum x11drv_escape_codes escape = X11DRV_GET_FONT;
130
131     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
132                     sizeof(font), (LPSTR)&font )) font = 0;
133     return font;
134 }
135
136
137 /***********************************************************************
138  *              wglCreateContext (OPENGL32.@)
139  */
140 HGLRC WINAPI wglCreateContext(HDC hdc)
141 {
142   XVisualInfo *vis;
143   Wine_GLContext *ret;
144   int num;
145   XVisualInfo template;
146   Display *display = get_display( hdc );
147
148   TRACE("(%p)\n", hdc);
149
150   /* First, get the visual in use by the X11DRV */
151   if (!display) return 0;
152   template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
153   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
154
155   if (vis == NULL) {
156     ERR("NULL visual !!!\n");
157     /* Need to set errors here */
158     return NULL;
159   }
160
161   /* The context will be allocated in the wglMakeCurrent call */
162   ENTER_GL();
163   ret = alloc_context();
164   LEAVE_GL();
165   ret->hdc = hdc;
166   ret->display = display;
167   ret->vis = vis;
168
169   TRACE(" creating context %p (GL context creation delayed)\n", ret);
170   return (HGLRC) ret;
171 }
172
173 /***********************************************************************
174  *              wglCreateLayerContext (OPENGL32.@)
175  */
176 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
177                                    int iLayerPlane) {
178   TRACE("(%p,%d)\n", hdc, iLayerPlane);
179
180   if (iLayerPlane == 0) {
181       return wglCreateContext(hdc);
182   }
183   FIXME(" no handler for layer %d\n", iLayerPlane);
184
185   return NULL;
186 }
187
188 /***********************************************************************
189  *              wglCopyContext (OPENGL32.@)
190  */
191 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
192                            HGLRC hglrcDst,
193                            UINT mask) {
194   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
195
196   return FALSE;
197 }
198
199 /***********************************************************************
200  *              wglDeleteContext (OPENGL32.@)
201  */
202 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
203 {
204   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
205   BOOL ret = TRUE;
206
207   TRACE("(%p)\n", hglrc);
208
209   ENTER_GL();
210   /* A game (Half Life not to name it) deletes twice the same context,
211    * so make sure it is valid first */
212   if (is_valid_context( ctx ))
213   {
214       if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
215       free_context(ctx);
216   }
217   else
218   {
219     WARN("Error deleting context !\n");
220     SetLastError(ERROR_INVALID_HANDLE);
221     ret = FALSE;
222   }
223   LEAVE_GL();
224
225   return ret;
226 }
227
228 /***********************************************************************
229  *              wglDescribeLayerPlane (OPENGL32.@)
230  */
231 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
232                                   int iPixelFormat,
233                                   int iLayerPlane,
234                                   UINT nBytes,
235                                   LPLAYERPLANEDESCRIPTOR plpd) {
236   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
237
238   return FALSE;
239 }
240
241 /***********************************************************************
242  *              wglGetCurrentContext (OPENGL32.@)
243  */
244 HGLRC WINAPI wglGetCurrentContext(void) {
245   GLXContext gl_ctx;
246   Wine_GLContext *ret;
247
248   TRACE("()\n");
249
250   ENTER_GL();
251   gl_ctx = glXGetCurrentContext();
252   ret = get_context_from_GLXContext(gl_ctx);
253   LEAVE_GL();
254
255   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
256
257   return ret;
258 }
259
260 /***********************************************************************
261  *              wglGetCurrentDC (OPENGL32.@)
262  */
263 HDC WINAPI wglGetCurrentDC(void) {
264   GLXContext gl_ctx;
265   Wine_GLContext *ret;
266
267   TRACE("()\n");
268
269   ENTER_GL();
270   gl_ctx = glXGetCurrentContext();
271   ret = get_context_from_GLXContext(gl_ctx);
272   LEAVE_GL();
273
274   if (ret) {
275     TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
276     return ret->hdc;
277   } else {
278     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
279     return 0;
280   }
281 }
282
283 /***********************************************************************
284  *              wglGetLayerPaletteEntries (OPENGL32.@)
285  */
286 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
287                                      int iLayerPlane,
288                                      int iStart,
289                                      int cEntries,
290                                      const COLORREF *pcr) {
291   FIXME("(): stub !\n");
292
293   return 0;
294 }
295
296 /***********************************************************************
297  *              wglGetProcAddress (OPENGL32.@)
298  */
299 static int compar(const void *elt_a, const void *elt_b) {
300   return strcmp(((OpenGL_extension *) elt_a)->name,
301                 ((OpenGL_extension *) elt_b)->name);
302 }
303
304 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
305   void *local_func;
306   static HMODULE hm = 0;
307   OpenGL_extension  ext;
308   OpenGL_extension *ext_ret;
309
310
311   TRACE("(%s)\n", lpszProc);
312
313   if (hm == 0)
314       hm = GetModuleHandleA("opengl32");
315
316   /* First, look if it's not already defined in the 'standard' OpenGL functions */
317   if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
318     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
319     return local_func;
320   }
321
322   if (p_glXGetProcAddressARB == NULL) {
323     ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
324     return NULL;
325   }
326   
327   /* After that, search in the thunks to find the real name of the extension */
328   ext.name = (char *) lpszProc;
329   ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
330                                          extension_registry_size, sizeof(OpenGL_extension), compar);
331
332   if (ext_ret == NULL) {
333     /* Some sanity checks :-) */
334     ENTER_GL();
335     local_func = p_glXGetProcAddressARB(lpszProc);
336     LEAVE_GL();
337     if (local_func != NULL) {
338       ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
339       return NULL;
340     }
341
342     WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
343     return NULL;
344   } else {
345     ENTER_GL();
346     local_func = p_glXGetProcAddressARB(ext_ret->glx_name);
347     LEAVE_GL();
348     
349     /* After that, look at the extensions defined in the Linux OpenGL library */
350     if (local_func == NULL) {
351       char buf[256];
352       void *ret = NULL;
353
354       /* Remove the 3 last letters (EXT, ARB, ...).
355
356          I know that some extensions have more than 3 letters (MESA, NV,
357          INTEL, ...), but this is only a stop-gap measure to fix buggy
358          OpenGL drivers (moreover, it is only useful for old 1.0 apps
359          that query the glBindTextureEXT extension).
360       */
361       strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
362       buf[strlen(ext_ret->glx_name) - 3] = '\0';
363       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
364
365       ret = GetProcAddress(hm, buf);
366       if (ret != NULL) {
367         TRACE(" found function in main OpenGL library (%p) !\n", ret);
368       } else {
369         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
370       }
371
372       return ret;
373     } else {
374       TRACE(" returning function  (%p)\n", ext_ret->func);
375       *(ext_ret->func_ptr) = local_func;
376
377       return ext_ret->func;
378     }
379   }
380 }
381
382 /***********************************************************************
383  *              wglMakeCurrent (OPENGL32.@)
384  */
385 BOOL WINAPI wglMakeCurrent(HDC hdc,
386                            HGLRC hglrc) {
387   BOOL ret;
388
389   TRACE("(%p,%p)\n", hdc, hglrc);
390
391   ENTER_GL();
392   if (hglrc == NULL) {
393       ret = glXMakeCurrent(default_display, None, NULL);
394   } else {
395       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
396       Drawable drawable = get_drawable( hdc );
397
398       if (ctx->ctx == NULL) {
399         ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
400         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
401       }
402       ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
403   }
404   LEAVE_GL();
405   TRACE(" returning %s\n", (ret ? "True" : "False"));
406   return ret;
407 }
408
409 /***********************************************************************
410  *              wglRealizeLayerPalette (OPENGL32.@)
411  */
412 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
413                                    int iLayerPlane,
414                                    BOOL bRealize) {
415   FIXME("()\n");
416
417   return FALSE;
418 }
419
420 /***********************************************************************
421  *              wglSetLayerPaletteEntries (OPENGL32.@)
422  */
423 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
424                                      int iLayerPlane,
425                                      int iStart,
426                                      int cEntries,
427                                      const COLORREF *pcr) {
428   FIXME("(): stub !\n");
429
430   return 0;
431 }
432
433 /***********************************************************************
434  *              wglShareLists (OPENGL32.@)
435  */
436 BOOL WINAPI wglShareLists(HGLRC hglrc1,
437                           HGLRC hglrc2) {
438   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
439   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
440
441   TRACE("(%p, %p)\n", org, dest);
442
443   if (dest->ctx != NULL) {
444     ERR("Could not share display lists, context already created !\n");
445     return FALSE;
446   } else {
447     if (org->ctx == NULL) {
448       ENTER_GL();
449       org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
450       LEAVE_GL();
451       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
452     }
453
454     ENTER_GL();
455     /* Create the destination context with display lists shared */
456     dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
457     LEAVE_GL();
458     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
459   }
460
461   return TRUE;
462 }
463
464 /***********************************************************************
465  *              wglSwapLayerBuffers (OPENGL32.@)
466  */
467 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
468                                 UINT fuPlanes) {
469   TRACE("(%p, %08x)\n", hdc, fuPlanes);
470
471   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
472     if (!SwapBuffers(hdc)) return FALSE;
473     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
474   }
475
476   if (fuPlanes) {
477     WARN("Following layers unhandled : %08x\n", fuPlanes);
478   }
479
480   return TRUE;
481 }
482
483 /***********************************************************************
484  *              wglUseFontBitmapsA (OPENGL32.@)
485  */
486 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
487                                DWORD first,
488                                DWORD count,
489                                DWORD listBase)
490 {
491   Font fid = get_font( hdc );
492
493   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
494
495   if (fid == 0) {
496     /* We are running using client-side rendering fonts... */
497     GLYPHMETRICS gm;
498     static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
499     int glyph;
500     int size = 0;
501     void *bitmap = NULL, *gl_bitmap = NULL;
502     int org_alignment;
503
504     ENTER_GL();
505     glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
506     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
507     LEAVE_GL();
508
509     for (glyph = first; glyph < first + count; glyph++) {
510       int needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
511       int height, width_int;
512
513       if (needed_size == GDI_ERROR) goto error;
514       if (needed_size > size) {
515         size = needed_size;
516         if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
517         if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
518         bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
519         gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
520       }
521       if (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
522       if (TRACE_ON(opengl)) {
523         unsigned int height, width, bitmask;
524         unsigned char *bitmap_ = (unsigned char *) bitmap;
525
526         DPRINTF("Glyph : %d\n", glyph);
527         DPRINTF("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
528         DPRINTF("  - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
529         DPRINTF("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
530         DPRINTF("  - size : %d\n", needed_size);
531         DPRINTF("  - bitmap : \n");
532         for (height = 0; height < gm.gmBlackBoxY; height++) {
533           DPRINTF("      ");
534           for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
535             if (bitmask == 0) {
536               bitmap_ += 1;
537               bitmask = 0x80;
538             }
539             if (*bitmap_ & bitmask)
540               DPRINTF("*");
541             else
542               DPRINTF(" ");
543           }
544           bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
545           DPRINTF("\n");
546         }
547       }
548
549       /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
550          As Wine does not seem to support the MAT2 field, I need to do it myself.... */
551       width_int = (gm.gmBlackBoxX + 31) / 32;
552       for (height = 0; height < gm.gmBlackBoxY; height++) {
553         int width;
554         for (width = 0; width < width_int; width++) {
555           ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
556             ((int *) bitmap)[height * width_int + width];
557         }
558       }
559
560       ENTER_GL();
561       glNewList(listBase++, GL_COMPILE);
562       glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
563       glEndList();
564       LEAVE_GL();
565     }
566
567     ENTER_GL();
568     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
569     LEAVE_GL();
570
571     if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
572     if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
573     return TRUE;
574
575   error:
576     ENTER_GL();
577     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
578     LEAVE_GL();
579
580     if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
581     if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
582     return FALSE;
583   }
584
585   ENTER_GL();
586   /* I assume that the glyphs are at the same position for X and for Windows */
587   glXUseXFont(fid, first, count, listBase);
588   LEAVE_GL();
589   return TRUE;
590 }
591
592 /***********************************************************************
593  *              wglUseFontOutlinesA (OPENGL32.@)
594  */
595 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
596                                 DWORD first,
597                                 DWORD count,
598                                 DWORD listBase,
599                                 FLOAT deviation,
600                                 FLOAT extrusion,
601                                 int format,
602                                 LPGLYPHMETRICSFLOAT lpgmf) {
603   FIXME("(): stub !\n");
604
605   return FALSE;
606 }
607
608 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
609    include all dependencies
610 */
611 #ifndef SONAME_LIBGL
612 #define SONAME_LIBGL "libGL.so"
613 #endif
614
615 /* This is for brain-dead applications that use OpenGL functions before even
616    creating a rendering context.... */
617 static BOOL process_attach(void)
618 {
619   XWindowAttributes win_attr;
620   Visual *rootVisual;
621   int num;
622   XVisualInfo template;
623   HDC hdc;
624   XVisualInfo *vis = NULL;
625   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
626   HMODULE mod = GetModuleHandleA( "x11drv.dll" );
627   void *opengl_handle;
628   const char *extensions = NULL;
629   
630   if (!root || !mod)
631   {
632       ERR("X11DRV not loaded. Cannot create default context.\n");
633       return FALSE;
634   }
635
636   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
637   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
638
639   hdc = GetDC(0);
640   default_display = get_display( hdc );
641   ReleaseDC( 0, hdc );
642   if (!default_display)
643   {
644       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
645       return FALSE;
646   }
647
648   ENTER_GL();
649
650   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
651      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
652      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
653      with mismatched visuals.  Note that the Root Window visual may not be double
654      buffered, so apps actually attempting to render this way may flicker */
655   if (XGetWindowAttributes( default_display, root, &win_attr ))
656   {
657     rootVisual = win_attr.visual;
658   }
659   else
660   {
661     /* Get the default visual, since we can't seem to get the attributes from the
662        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
663     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
664   }
665
666   template.visualid = XVisualIDFromVisual(rootVisual);
667   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
668   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
669   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
670   extensions = glXQueryExtensionsString(default_display, DefaultScreen(default_display));
671   XFree(vis);
672   LEAVE_GL();
673
674   if ((extensions != NULL) && (strstr(extensions, "GLX_ARB_get_proc_address"))) {
675     opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
676     if (opengl_handle != NULL) {
677       p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
678       wine_dlclose(opengl_handle, NULL, 0);
679     }
680   }
681   
682   if (default_cx == NULL) {
683     ERR("Could not create default context.\n");
684   }
685   return TRUE;
686 }
687
688 /**********************************************************************/
689
690 /* Some WGL extensions... */
691 static const char *WGL_extensions = "WGL_ARB_extensions_string WGL_EXT_extensions_string";
692
693 /**********************************************************************/
694
695 const char * WINAPI wglGetExtensionsStringEXT(void) {
696     TRACE("() returning \"%s\"\n", WGL_extensions);
697
698     return WGL_extensions;
699 }
700
701 /**********************************************************************/
702
703 static void process_detach(void)
704 {
705   glXDestroyContext(default_display, default_cx);
706 }
707
708 /***********************************************************************
709  *              wglGetExtensionsStringARB(OPENGL32.@)
710  */
711 const char * WINAPI wglGetExtensionsStringARB(HDC hdc) {
712
713   return wglGetExtensionsStringEXT();
714 }
715
716
717 /***********************************************************************
718  *           OpenGL initialisation routine
719  */
720 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
721 {
722     switch(reason)
723     {
724     case DLL_PROCESS_ATTACH:
725         DisableThreadLibraryCalls(hinst);
726         return process_attach();
727     case DLL_PROCESS_DETACH:
728         process_detach();
729         break;
730     }
731     return TRUE;
732 }