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