crypt32: Fixed day/month mismatch in time encoding routines.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "wgl_ext.h"
38 #include "opengl_ext.h"
39 #ifdef HAVE_GL_GLU_H
40 #undef far
41 #undef near
42 #include <GL/glu.h>
43 #endif
44 #include "wine/library.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
48 WINE_DECLARE_DEBUG_CHANNEL(opengl);
49
50 /** global glx object */
51 wine_glx_t wine_glx;
52
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
56 {
57     X11DRV_GET_DISPLAY,         /* get X11 display for a DC */
58     X11DRV_GET_DRAWABLE,        /* get current drawable for a DC */
59     X11DRV_GET_FONT,            /* get current X font for a DC */
60     X11DRV_SET_DRAWABLE,        /* set current drawable for a DC */
61     X11DRV_START_EXPOSURES,     /* start graphics exposures */
62     X11DRV_END_EXPOSURES,       /* end graphics exposures */
63     X11DRV_GET_DCE,             /* get the DCE pointer */
64     X11DRV_SET_DCE,             /* set the DCE pointer */
65     X11DRV_GET_GLX_DRAWABLE,    /* get current glx drawable for a DC */
66     X11DRV_SYNC_PIXMAP          /* sync the dibsection to its pixmap */
67 };
68
69 void (*wine_tsx11_lock_ptr)(void) = NULL;
70 void (*wine_tsx11_unlock_ptr)(void) = NULL;
71
72 static GLXContext default_cx = NULL;
73 static Display *default_display;  /* display to use for default context */
74
75 static HMODULE opengl32_handle;
76
77 static glXGetProcAddressARB_t p_glXGetProcAddressARB = NULL;
78
79 static char  internal_gl_disabled_extensions[512];
80 static char* internal_gl_extensions = NULL;
81
82 typedef struct wine_glcontext {
83   HDC hdc;
84   Display *display;
85   XVisualInfo *vis;
86   GLXFBConfig fb_conf;
87   GLXContext ctx;
88   BOOL do_escape;
89   struct wine_glcontext *next;
90   struct wine_glcontext *prev;
91 } Wine_GLContext;
92 static Wine_GLContext *context_list;
93
94 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
95 {
96     Wine_GLContext *ret;
97     for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
98     return ret;
99 }
100
101 void enter_gl(void)
102 {
103     Wine_GLContext *curctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
104     
105     if (curctx && curctx->do_escape)
106     {
107         enum x11drv_escape_codes escape = X11DRV_SYNC_PIXMAP;
108         ExtEscape(curctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape, 0, NULL);
109     }
110
111     wine_tsx11_lock_ptr();
112     return;
113 }
114
115 static inline void free_context(Wine_GLContext *context)
116 {
117   if (context->next != NULL) context->next->prev = context->prev;
118   if (context->prev != NULL) context->prev->next = context->next;
119   else context_list = context->next;
120
121   HeapFree(GetProcessHeap(), 0, context);
122 }
123
124 static inline Wine_GLContext *alloc_context(void)
125 {
126   Wine_GLContext *ret;
127
128   if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
129   {
130       ret->next = context_list;
131       if (context_list) context_list->prev = ret;
132       context_list = ret;
133   }
134   return ret;
135 }
136
137 inline static BOOL is_valid_context( Wine_GLContext *ctx )
138 {
139     Wine_GLContext *ptr;
140     for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
141     return (ptr != NULL);
142 }
143
144 /* retrieve the X display to use on a given DC */
145 inline static Display *get_display( HDC hdc )
146 {
147     Display *display;
148     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
149
150     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
151                     sizeof(display), (LPSTR)&display )) display = NULL;
152     return display;
153 }
154
155
156 /* retrieve the GLX drawable to use on a given DC */
157 inline static Drawable get_drawable( HDC hdc )
158 {
159     GLXDrawable drawable;
160     enum x11drv_escape_codes escape = X11DRV_GET_GLX_DRAWABLE;
161
162     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
163                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
164     return drawable;
165 }
166
167 /** for use of wglGetCurrentReadDCARB */
168 inline static HDC get_hdc_from_Drawable(GLXDrawable d)
169 {
170   Wine_GLContext *ret;
171   for (ret = context_list; ret; ret = ret->next) {  
172     if (d == get_drawable( ret->hdc )) {
173       return ret->hdc;
174     }
175   }
176   return NULL;
177 }
178
179 /* retrieve the X font to use on a given DC */
180 inline static Font get_font( HDC hdc )
181 {
182     Font font;
183     enum x11drv_escape_codes escape = X11DRV_GET_FONT;
184
185     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
186                     sizeof(font), (LPSTR)&font )) font = 0;
187     return font;
188 }
189
190
191 /***********************************************************************
192  *              wglCreateContext (OPENGL32.@)
193  */
194 HGLRC WINAPI wglCreateContext(HDC hdc)
195 {
196   Wine_GLContext *ret;
197   int num;
198   XVisualInfo template;
199   XVisualInfo *vis = NULL;
200   Display *display = get_display( hdc );
201   int hdcPF = GetPixelFormat(hdc);
202   GLXFBConfig cur_cfg;
203
204   TRACE("(%p)->(PF:%d)\n", hdc, hdcPF);
205
206   /* First, get the visual in use by the X11DRV */
207   if (!display) return 0;
208   template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
209   vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
210
211   if (vis == NULL) {
212     ERR("NULL visual !!!\n");
213     /* Need to set errors here */
214     return NULL;
215   }
216   if (0 >= hdcPF) {
217     SetLastError(ERROR_INVALID_PIXEL_FORMAT);
218     return NULL;
219   }
220
221   {
222     int nCfgs_fmt = 0;
223     GLXFBConfig* cfgs_fmt = NULL;
224     int value;
225     int gl_test = 0;
226     cfgs_fmt = wine_glx.p_glXGetFBConfigs(display, DefaultScreen(display), &nCfgs_fmt);
227     if (NULL == cfgs_fmt || 0 == nCfgs_fmt) {
228       ERR("Cannot get FB Configs, expect problems.\n");
229       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
230       return NULL;
231     }
232     if (nCfgs_fmt < hdcPF) {
233       ERR("(%p): unexpected pixelFormat(%d) > nFormats(%d), returns NULL\n", hdc, hdcPF, nCfgs_fmt);
234       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
235       return NULL;
236     }
237     cur_cfg = cfgs_fmt[hdcPF - 1];
238     gl_test = wine_glx.p_glXGetFBConfigAttrib(display, cur_cfg, GLX_FBCONFIG_ID, &value);
239     if (gl_test) {
240       ERR("Failed to retrieve FBCONFIG_ID from GLXFBConfig, expect problems.\n");
241       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
242       return NULL;
243     }
244     XFree(cfgs_fmt);
245   }
246
247   /* The context will be allocated in the wglMakeCurrent call */
248   ENTER_GL();
249   ret = alloc_context();
250   LEAVE_GL();
251   ret->hdc = hdc;
252   ret->display = display;
253   ret->fb_conf = cur_cfg;
254   /*ret->vis = vis;*/
255   ret->vis = wine_glx.p_glXGetVisualFromFBConfig(display, cur_cfg);
256
257   TRACE(" creating context %p (GL context creation delayed)\n", ret);
258   return (HGLRC) ret;
259 }
260
261 /***********************************************************************
262  *              wglCreateLayerContext (OPENGL32.@)
263  */
264 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
265                                    int iLayerPlane) {
266   TRACE("(%p,%d)\n", hdc, iLayerPlane);
267
268   if (iLayerPlane == 0) {
269       return wglCreateContext(hdc);
270   }
271   FIXME(" no handler for layer %d\n", iLayerPlane);
272
273   return NULL;
274 }
275
276 /***********************************************************************
277  *              wglCopyContext (OPENGL32.@)
278  */
279 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
280                            HGLRC hglrcDst,
281                            UINT mask) {
282   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
283
284   return FALSE;
285 }
286
287 /***********************************************************************
288  *              wglDeleteContext (OPENGL32.@)
289  */
290 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
291 {
292   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
293   BOOL ret = TRUE;
294
295   TRACE("(%p)\n", hglrc);
296
297   ENTER_GL();
298   /* A game (Half Life not to name it) deletes twice the same context,
299    * so make sure it is valid first */
300   if (is_valid_context( ctx ))
301   {
302       if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
303       free_context(ctx);
304   }
305   else
306   {
307     WARN("Error deleting context !\n");
308     SetLastError(ERROR_INVALID_HANDLE);
309     ret = FALSE;
310   }
311   LEAVE_GL();
312
313   return ret;
314 }
315
316 /***********************************************************************
317  *              wglDescribeLayerPlane (OPENGL32.@)
318  */
319 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
320                                   int iPixelFormat,
321                                   int iLayerPlane,
322                                   UINT nBytes,
323                                   LPLAYERPLANEDESCRIPTOR plpd) {
324   FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
325
326   return FALSE;
327 }
328
329 /***********************************************************************
330  *              wglGetCurrentContext (OPENGL32.@)
331  */
332 HGLRC WINAPI wglGetCurrentContext(void) {
333   GLXContext gl_ctx;
334   Wine_GLContext *ret;
335
336   TRACE("()\n");
337
338   ENTER_GL();
339   gl_ctx = glXGetCurrentContext();
340   ret = get_context_from_GLXContext(gl_ctx);
341   LEAVE_GL();
342
343   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
344
345   return (HGLRC)ret;
346 }
347
348 /***********************************************************************
349  *              wglGetCurrentDC (OPENGL32.@)
350  */
351 HDC WINAPI wglGetCurrentDC(void) {
352   GLXContext gl_ctx;
353   Wine_GLContext *ret;
354
355   TRACE("()\n");
356
357   ENTER_GL();
358   gl_ctx = glXGetCurrentContext();
359   ret = get_context_from_GLXContext(gl_ctx);
360   LEAVE_GL();
361
362   if (ret) {
363     TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
364     return ret->hdc;
365   } else {
366     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
367     return 0;
368   }
369 }
370
371 /***********************************************************************
372  *              wglGetLayerPaletteEntries (OPENGL32.@)
373  */
374 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
375                                      int iLayerPlane,
376                                      int iStart,
377                                      int cEntries,
378                                      const COLORREF *pcr) {
379   FIXME("(): stub !\n");
380
381   return 0;
382 }
383
384 /***********************************************************************
385  *              wglGetProcAddress (OPENGL32.@)
386  */
387 static int compar(const void *elt_a, const void *elt_b) {
388   return strcmp(((const OpenGL_extension *) elt_a)->name,
389                 ((const OpenGL_extension *) elt_b)->name);
390 }
391
392 static int wgl_compar(const void *elt_a, const void *elt_b) {
393   return strcmp(((const WGL_extension *) elt_a)->func_name,
394                 ((const WGL_extension *) elt_b)->func_name);
395 }
396
397 PROC WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
398   void *local_func;
399   OpenGL_extension  ext;
400   OpenGL_extension *ext_ret;
401
402   TRACE("(%s)\n", lpszProc);
403
404   /* First, look if it's not already defined in the 'standard' OpenGL functions */
405   if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
406     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
407     return local_func;
408   }
409
410   if (p_glXGetProcAddressARB == NULL) {
411     ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
412     return NULL;
413   }
414   
415   /* After that, search in the thunks to find the real name of the extension */
416   ext.name = (char *) lpszProc;
417   ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
418                                          extension_registry_size, sizeof(OpenGL_extension), compar);
419
420   if (ext_ret == NULL) {
421     WGL_extension wgl_ext, *wgl_ext_ret;
422
423     /* Try to find the function in the WGL extensions ... */
424     wgl_ext.func_name = (char *) lpszProc;
425     wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
426                                             wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);
427
428     if (wgl_ext_ret == NULL) {
429       /* Some sanity checks :-) */
430       ENTER_GL();
431       local_func = p_glXGetProcAddressARB( (const GLubyte *) lpszProc);
432       LEAVE_GL();
433       if (local_func != NULL) {
434         WARN("Extension %s defined in the OpenGL library but NOT in opengl_ext.c...\n", lpszProc);
435         return NULL;
436       }
437       
438       WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
439       return NULL;
440     } else {
441         void *ret = NULL;
442
443         if (wgl_ext_ret->func_init != NULL) {
444             const char *err_msg;
445             if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
446                                                   wgl_ext_ret->context)) == NULL) {
447                 ret = wgl_ext_ret->func_address;
448             } else {
449                 WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
450                 return NULL;
451             }
452         } else {
453           ret = wgl_ext_ret->func_address;
454         }
455
456         if (ret)
457             TRACE(" returning WGL function  (%p)\n", ret);
458         return ret;
459     }
460   } else {
461     ENTER_GL();
462     local_func = p_glXGetProcAddressARB( (const GLubyte*) ext_ret->glx_name);
463     LEAVE_GL();
464     
465     /* After that, look at the extensions defined in the Linux OpenGL library */
466     if (local_func == NULL) {
467       char buf[256];
468       void *ret = NULL;
469
470       /* Remove the 3 last letters (EXT, ARB, ...).
471
472          I know that some extensions have more than 3 letters (MESA, NV,
473          INTEL, ...), but this is only a stop-gap measure to fix buggy
474          OpenGL drivers (moreover, it is only useful for old 1.0 apps
475          that query the glBindTextureEXT extension).
476       */
477       memcpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
478       buf[strlen(ext_ret->glx_name) - 3] = '\0';
479       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
480
481       ret = GetProcAddress(opengl32_handle, buf);
482       if (ret != NULL) {
483         TRACE(" found function in main OpenGL library (%p) !\n", ret);
484       } else {
485         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
486       }
487
488       return ret;
489     } else {
490       TRACE(" returning function  (%p)\n", ext_ret->func);
491       *(ext_ret->func_ptr) = local_func;
492
493       return ext_ret->func;
494     }
495   }
496 }
497
498 static int describeContext(Wine_GLContext* ctx) {
499   int tmp;
500   int ctx_vis_id;
501   TRACE(" Context %p have (vis:%p):\n", ctx, ctx->vis);
502   wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_FBCONFIG_ID, &tmp);
503   TRACE(" - FBCONFIG_ID 0x%x\n", tmp);
504   wine_glx.p_glXGetFBConfigAttrib(ctx->display, ctx->fb_conf, GLX_VISUAL_ID, &tmp);
505   TRACE(" - VISUAL_ID 0x%x\n", tmp);
506   ctx_vis_id = tmp;
507   return ctx_vis_id;
508 }
509
510 static int describeDrawable(Wine_GLContext* ctx, Drawable drawable) {
511   int tmp;
512   int draw_vis_id;
513   if (3 > wine_glx.version || NULL == wine_glx.p_glXQueryDrawable)  {
514     /** glXQueryDrawable not available so returns not supported */
515     return -1;
516   }
517   TRACE(" Drawable %p have :\n", (void*) drawable);
518   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_FBCONFIG_ID, (unsigned int*) &tmp);
519   TRACE(" - FBCONFIG_ID as 0x%x\n", tmp);
520   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_VISUAL_ID, (unsigned int*) &tmp);
521   TRACE(" - VISUAL_ID as 0x%x\n", tmp);
522   draw_vis_id = tmp;
523   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_WIDTH, (unsigned int*) &tmp);
524   TRACE(" - WIDTH as %d\n", tmp);
525   wine_glx.p_glXQueryDrawable(ctx->display, drawable, GLX_HEIGHT, (unsigned int*) &tmp);
526   TRACE(" - HEIGHT as %d\n", tmp);
527   return draw_vis_id;
528 }
529
530 /***********************************************************************
531  *              wglMakeCurrent (OPENGL32.@)
532  */
533 BOOL WINAPI wglMakeCurrent(HDC hdc,
534                            HGLRC hglrc) {
535   BOOL ret;
536   DWORD type = GetObjectType(hdc);
537
538   TRACE("(%p,%p)\n", hdc, hglrc);
539
540   ENTER_GL();
541   if (hglrc == NULL) {
542       ret = glXMakeCurrent(default_display, None, NULL);
543       NtCurrentTeb()->glContext = NULL;
544   } else {
545       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
546       Drawable drawable = get_drawable( hdc );
547       if (ctx->ctx == NULL) {
548         int draw_vis_id, ctx_vis_id;
549         VisualID visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
550         TRACE(" Wine desktop VISUAL_ID is 0x%x\n", (unsigned int) visualid);
551         draw_vis_id = describeDrawable(ctx, drawable);
552         ctx_vis_id = describeContext(ctx);
553
554         if (-1 == draw_vis_id || (draw_vis_id == visualid && draw_vis_id != ctx_vis_id)) {
555           /**
556            * Inherits from root window so reuse desktop visual
557            */
558           XVisualInfo template;
559           XVisualInfo *vis;
560           int num;
561           template.visualid = visualid;
562           vis = XGetVisualInfo(ctx->display, VisualIDMask, &template, &num);
563
564           TRACE(" Creating GLX Context\n");
565           ctx->ctx = glXCreateContext(ctx->display, vis, NULL, type == OBJ_MEMDC ? False : True);
566         } else {
567           TRACE(" Creating GLX Context\n");
568           ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, type == OBJ_MEMDC ? False : True);
569         }
570         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
571       }
572       TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
573       ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
574       NtCurrentTeb()->glContext = ctx;
575       if(ret && type == OBJ_MEMDC)
576       {
577           ctx->do_escape = TRUE;
578           glDrawBuffer(GL_FRONT_LEFT);
579       }
580   }
581   LEAVE_GL();
582   TRACE(" returning %s\n", (ret ? "True" : "False"));
583   return ret;
584 }
585
586 /***********************************************************************
587  *              wglMakeContextCurrentARB (OPENGL32.@)
588  */
589 BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc) 
590 {
591   BOOL ret;
592   TRACE("(%p,%p,%p)\n", hDrawDC, hReadDC, hglrc);
593
594   ENTER_GL();
595   if (hglrc == NULL) {
596     ret = glXMakeCurrent(default_display, None, NULL);
597   } else {
598     if (NULL == wine_glx.p_glXMakeContextCurrent) {
599       ret = FALSE;
600     } else {
601       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
602       Drawable d_draw = get_drawable( hDrawDC );
603       Drawable d_read = get_drawable( hReadDC );
604       
605       if (ctx->ctx == NULL) {
606         ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, GetObjectType(hDrawDC) == OBJ_MEMDC ? False : True);
607         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
608       }
609       ret = wine_glx.p_glXMakeContextCurrent(ctx->display, d_draw, d_read, ctx->ctx);
610     }
611   }
612   LEAVE_GL();
613   
614   TRACE(" returning %s\n", (ret ? "True" : "False"));
615   return ret;
616 }
617
618 /***********************************************************************
619  *              wglGetCurrentReadDCARB (OPENGL32.@)
620  */
621 HDC WINAPI wglGetCurrentReadDCARB(void) 
622 {
623   GLXDrawable gl_d;
624   HDC ret;
625
626   TRACE("()\n");
627
628   ENTER_GL();
629   gl_d = glXGetCurrentReadDrawable();
630   ret = get_hdc_from_Drawable(gl_d);
631   LEAVE_GL();
632
633   TRACE(" returning %p (GL drawable %lu)\n", ret, gl_d);
634   return ret;
635 }
636
637
638
639 /***********************************************************************
640  *              wglRealizeLayerPalette (OPENGL32.@)
641  */
642 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
643                                    int iLayerPlane,
644                                    BOOL bRealize) {
645   FIXME("()\n");
646
647   return FALSE;
648 }
649
650 /***********************************************************************
651  *              wglSetLayerPaletteEntries (OPENGL32.@)
652  */
653 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
654                                      int iLayerPlane,
655                                      int iStart,
656                                      int cEntries,
657                                      const COLORREF *pcr) {
658   FIXME("(): stub !\n");
659
660   return 0;
661 }
662
663 /***********************************************************************
664  *              wglShareLists (OPENGL32.@)
665  */
666 BOOL WINAPI wglShareLists(HGLRC hglrc1,
667                           HGLRC hglrc2) {
668   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
669   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
670
671   TRACE("(%p, %p)\n", org, dest);
672
673   if (NULL != dest && dest->ctx != NULL) {
674     ERR("Could not share display lists, context already created !\n");
675     return FALSE;
676   } else {
677     if (org->ctx == NULL) {
678       ENTER_GL();
679       describeContext(org);
680       org->ctx = glXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
681       LEAVE_GL();
682       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
683     }
684     if (NULL != dest) {
685       ENTER_GL();
686       describeContext(dest);
687       /* Create the destination context with display lists shared */
688       dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True);
689       LEAVE_GL();
690       TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
691       return TRUE;
692     }
693   }
694   return FALSE;
695 }
696
697 /***********************************************************************
698  *              wglSwapLayerBuffers (OPENGL32.@)
699  */
700 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
701                                 UINT fuPlanes) {
702   TRACE_(opengl)("(%p, %08x)\n", hdc, fuPlanes);
703
704   if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
705     if (!SwapBuffers(hdc)) return FALSE;
706     fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
707   }
708
709   if (fuPlanes) {
710     WARN("Following layers unhandled : %08x\n", fuPlanes);
711   }
712
713   return TRUE;
714 }
715
716 static BOOL internal_wglUseFontBitmaps(HDC hdc,
717                                        DWORD first,
718                                        DWORD count,
719                                        DWORD listBase,
720                                        DWORD (WINAPI *GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
721 {
722     /* We are running using client-side rendering fonts... */
723     GLYPHMETRICS gm;
724     unsigned int glyph;
725     int size = 0;
726     void *bitmap = NULL, *gl_bitmap = NULL;
727     int org_alignment;
728
729     ENTER_GL();
730     glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
731     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
732     LEAVE_GL();
733
734     for (glyph = first; glyph < first + count; glyph++) {
735         unsigned int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
736         int height, width_int;
737
738         TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
739         if (needed_size == GDI_ERROR) {
740             TRACE("  - needed size : %d (GDI_ERROR)\n", needed_size);
741             goto error;
742         } else {
743             TRACE("  - needed size : %d\n", needed_size);
744         }
745
746         if (needed_size > size) {
747             size = needed_size;
748             HeapFree(GetProcessHeap(), 0, bitmap);
749             HeapFree(GetProcessHeap(), 0, gl_bitmap);
750             bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
751             gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
752         }
753         if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
754         if (TRACE_ON(opengl)) {
755             unsigned int height, width, bitmask;
756             unsigned char *bitmap_ = (unsigned char *) bitmap;
757             
758             TRACE("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
759             TRACE("  - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
760             TRACE("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
761             if (needed_size != 0) {
762                 TRACE("  - bitmap :\n");
763                 for (height = 0; height < gm.gmBlackBoxY; height++) {
764                     TRACE("      ");
765                     for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
766                         if (bitmask == 0) {
767                             bitmap_ += 1;
768                             bitmask = 0x80;
769                         }
770                         if (*bitmap_ & bitmask)
771                             TRACE("*");
772                         else
773                             TRACE(" ");
774                     }
775                     bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
776                     TRACE("\n");
777                 }
778             }
779         }
780         
781         /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
782          * glyph for it to be drawn properly.
783          */
784         if (needed_size != 0) {
785             width_int = (gm.gmBlackBoxX + 31) / 32;
786             for (height = 0; height < gm.gmBlackBoxY; height++) {
787                 int width;
788                 for (width = 0; width < width_int; width++) {
789                     ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
790                         ((int *) bitmap)[height * width_int + width];
791                 }
792             }
793         }
794         
795         ENTER_GL();
796         glNewList(listBase++, GL_COMPILE);
797         if (needed_size != 0) {
798             glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
799                      0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
800                      gm.gmCellIncX, gm.gmCellIncY,
801                      gl_bitmap);
802         } else {
803             /* This is the case of 'empty' glyphs like the space character */
804             glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
805         }
806         glEndList();
807         LEAVE_GL();
808     }
809     
810     ENTER_GL();
811     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
812     LEAVE_GL();
813     
814     HeapFree(GetProcessHeap(), 0, bitmap);
815     HeapFree(GetProcessHeap(), 0, gl_bitmap);
816     return TRUE;
817
818   error:
819     ENTER_GL();
820     glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
821     LEAVE_GL();
822
823     HeapFree(GetProcessHeap(), 0, bitmap);
824     HeapFree(GetProcessHeap(), 0, gl_bitmap);
825     return FALSE;    
826 }
827
828 /***********************************************************************
829  *              wglUseFontBitmapsA (OPENGL32.@)
830  */
831 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
832                                DWORD first,
833                                DWORD count,
834                                DWORD listBase)
835 {
836   Font fid = get_font( hdc );
837
838   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
839
840   if (fid == 0) {
841       return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
842   }
843
844   ENTER_GL();
845   /* I assume that the glyphs are at the same position for X and for Windows */
846   glXUseXFont(fid, first, count, listBase);
847   LEAVE_GL();
848   return TRUE;
849 }
850
851 /***********************************************************************
852  *              wglUseFontBitmapsW (OPENGL32.@)
853  */
854 BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
855                                DWORD first,
856                                DWORD count,
857                                DWORD listBase)
858 {
859   Font fid = get_font( hdc );
860
861   TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
862
863   if (fid == 0) {
864       return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
865   }
866
867   WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
868   
869   ENTER_GL();
870   /* I assume that the glyphs are at the same position for X and for Windows */
871   glXUseXFont(fid, first, count, listBase);
872   LEAVE_GL();
873   return TRUE;
874 }
875
876 #ifdef HAVE_GL_GLU_H
877
878 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
879 {
880     vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;  
881     vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;  
882     vertex[2] = 0.0;
883 }
884
885 static void tess_callback_vertex(GLvoid *vertex)
886 {
887     GLdouble *dbl = vertex;
888     TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
889     glVertex3dv(vertex);
890 }
891
892 static void tess_callback_begin(GLenum which)
893 {
894     TRACE("%d\n", which);
895     glBegin(which);
896 }
897
898 static void tess_callback_end(void)
899 {
900     TRACE("\n");
901     glEnd();
902 }
903
904 /***********************************************************************
905  *              wglUseFontOutlines_common
906  */
907 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
908                                       DWORD first,
909                                       DWORD count,
910                                       DWORD listBase,
911                                       FLOAT deviation,
912                                       FLOAT extrusion,
913                                       int format,
914                                       LPGLYPHMETRICSFLOAT lpgmf,
915                                       BOOL unicode)
916 {
917     UINT glyph;
918     const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
919     GLUtesselator *tess;
920     LOGFONTW lf;
921     HFONT old_font, unscaled_font;
922     UINT em_size = 1024;
923     RECT rc;
924
925     TRACE("(%p, %ld, %ld, %ld, %f, %f, %d, %p, %s)\n", hdc, first, count,
926           listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
927
928
929     ENTER_GL();
930     tess = gluNewTess();
931     if(tess)
932     {
933         gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
934         gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
935         gluTessCallback(tess, GLU_TESS_END, tess_callback_end);
936     }
937     LEAVE_GL();
938
939     if(!tess) return FALSE;
940
941     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
942     rc.left = rc.right = rc.bottom = 0;
943     rc.top = em_size;
944     DPtoLP(hdc, (POINT*)&rc, 2);
945     lf.lfHeight = -abs(rc.top - rc.bottom);
946     lf.lfOrientation = lf.lfEscapement = 0;
947     unscaled_font = CreateFontIndirectW(&lf);
948     old_font = SelectObject(hdc, unscaled_font);
949
950     for (glyph = first; glyph < first + count; glyph++)
951     {
952         DWORD needed;
953         GLYPHMETRICS gm;
954         BYTE *buf;
955         TTPOLYGONHEADER *pph;
956         TTPOLYCURVE *ppc;
957         GLdouble *vertices;
958
959         if(unicode)
960             needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
961         else
962             needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
963
964         if(needed == GDI_ERROR)
965             goto error;
966
967         buf = HeapAlloc(GetProcessHeap(), 0, needed);
968         vertices = HeapAlloc(GetProcessHeap(), 0, needed / sizeof(POINTFX) * 3 * sizeof(GLdouble));
969
970         if(unicode)
971             GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
972         else
973             GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
974
975         TRACE("glyph %d\n", glyph);
976
977         if(lpgmf)
978         {
979             lpgmf->gmfBlackBoxX = gm.gmBlackBoxX / em_size;
980             lpgmf->gmfBlackBoxY = gm.gmBlackBoxY / em_size;
981             lpgmf->gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / em_size;
982             lpgmf->gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / em_size;
983             lpgmf->gmfCellIncX = gm.gmCellIncX / em_size;
984             lpgmf->gmfCellIncY = gm.gmCellIncY / em_size;
985             TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
986                   lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY); 
987             lpgmf++;
988         }
989
990         ENTER_GL();
991         glNewList(listBase++, GL_COMPILE);
992         gluTessBeginPolygon(tess, NULL);
993
994         pph = (TTPOLYGONHEADER*)buf;
995         while((BYTE*)pph < buf + needed)
996         {
997             TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
998
999             gluTessBeginContour(tess);
1000
1001             fixed_to_double(pph->pfxStart, em_size, vertices);
1002             gluTessVertex(tess, vertices, vertices);
1003             vertices += 3;
1004
1005             ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
1006             while((char*)ppc < (char*)pph + pph->cb)
1007             {
1008                 int i;
1009
1010                 switch(ppc->wType) {
1011                 case TT_PRIM_LINE:
1012                     for(i = 0; i < ppc->cpfx; i++)
1013                     {
1014                         TRACE("\t\tline to %d, %d\n", ppc->apfx[i].x.value, ppc->apfx[i].y.value);
1015                         fixed_to_double(ppc->apfx[i], em_size, vertices); 
1016                         gluTessVertex(tess, vertices, vertices);
1017                         vertices += 3;
1018                     }
1019                     break;
1020
1021                 case TT_PRIM_QSPLINE:
1022                     for(i = 0; i < ppc->cpfx/2; i++)
1023                     {
1024                         /* FIXME just connecting the control points for now */
1025                         TRACE("\t\tcurve  %d,%d %d,%d\n",
1026                               ppc->apfx[i * 2].x.value,     ppc->apfx[i * 3].y.value,
1027                               ppc->apfx[i * 2 + 1].x.value, ppc->apfx[i * 3 + 1].y.value);
1028                         fixed_to_double(ppc->apfx[i * 2], em_size, vertices); 
1029                         gluTessVertex(tess, vertices, vertices);
1030                         vertices += 3;
1031                         fixed_to_double(ppc->apfx[i * 2 + 1], em_size, vertices); 
1032                         gluTessVertex(tess, vertices, vertices);
1033                         vertices += 3;
1034                     }
1035                     break;
1036                 default:
1037                     ERR("\t\tcurve type = %d\n", ppc->wType);
1038                     gluTessEndContour(tess);
1039                     goto error_in_list;
1040                 }
1041
1042                 ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
1043                                      (ppc->cpfx - 1) * sizeof(POINTFX));
1044             }
1045             gluTessEndContour(tess);
1046             pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
1047         }
1048
1049 error_in_list:
1050         gluTessEndPolygon(tess);
1051         glEndList();
1052         LEAVE_GL();
1053         HeapFree(GetProcessHeap(), 0, buf);
1054         HeapFree(GetProcessHeap(), 0, vertices);
1055     }
1056
1057  error:
1058     DeleteObject(SelectObject(hdc, old_font));
1059     gluDeleteTess(tess);
1060     return TRUE;
1061
1062 }
1063
1064 #else /* HAVE_GL_GLU_H */
1065
1066 BOOL WINAPI wglUseFontOutlines_common(HDC hdc,
1067                                       DWORD first,
1068                                       DWORD count,
1069                                       DWORD listBase,
1070                                       FLOAT deviation,
1071                                       FLOAT extrusion,
1072                                       int format,
1073                                       LPGLYPHMETRICSFLOAT lpgmf,
1074                                       BOOL unicode)
1075 {
1076     FIXME("Unable to compile in wglUseFontOutlines support without GL/glu.h\n");
1077     return FALSE;
1078 }
1079
1080 #endif /* HAVE_GL_GLU_H */
1081
1082 /***********************************************************************
1083  *              wglUseFontOutlinesA (OPENGL32.@)
1084  */
1085 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
1086                                 DWORD first,
1087                                 DWORD count,
1088                                 DWORD listBase,
1089                                 FLOAT deviation,
1090                                 FLOAT extrusion,
1091                                 int format,
1092                                 LPGLYPHMETRICSFLOAT lpgmf)
1093 {
1094     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
1095 }
1096
1097 /***********************************************************************
1098  *              wglUseFontOutlinesW (OPENGL32.@)
1099  */
1100 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
1101                                 DWORD first,
1102                                 DWORD count,
1103                                 DWORD listBase,
1104                                 FLOAT deviation,
1105                                 FLOAT extrusion,
1106                                 int format,
1107                                 LPGLYPHMETRICSFLOAT lpgmf)
1108 {
1109     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
1110 }
1111
1112 const GLubyte * internal_glGetString(GLenum name) {
1113   const char* GL_Extensions = NULL;
1114   
1115   if (GL_EXTENSIONS != name) {
1116     return glGetString(name);
1117   }
1118
1119   if (NULL == internal_gl_extensions) {
1120     GL_Extensions = (const char *) glGetString(GL_EXTENSIONS);
1121
1122     TRACE("GL_EXTENSIONS reported:\n");  
1123     if (NULL == GL_Extensions) {
1124       ERR("GL_EXTENSIONS returns NULL\n");      
1125       return NULL;
1126     } else {
1127       size_t len = strlen(GL_Extensions);
1128       internal_gl_extensions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 2);
1129
1130       while (*GL_Extensions != 0x00) {
1131         const char* Start = GL_Extensions;
1132         char        ThisExtn[256];
1133          
1134         memset(ThisExtn, 0x00, sizeof(ThisExtn));
1135         while (*GL_Extensions != ' ' && *GL_Extensions != 0x00) {
1136           GL_Extensions++;
1137         }
1138         memcpy(ThisExtn, Start, (GL_Extensions - Start));
1139         TRACE("- %s:", ThisExtn);
1140         
1141         /* test if supported API is disabled by config */
1142         if (NULL == strstr(internal_gl_disabled_extensions, ThisExtn)) {
1143           strcat(internal_gl_extensions, " ");
1144           strcat(internal_gl_extensions, ThisExtn);
1145           TRACE(" active\n");
1146         } else {
1147           TRACE(" deactived (by config)\n");
1148         }
1149
1150         if (*GL_Extensions == ' ') GL_Extensions++;
1151       }
1152     }
1153   }
1154   return (const GLubyte *) internal_gl_extensions;
1155 }
1156
1157 void internal_glGetIntegerv(GLenum pname, GLint* params) {
1158   glGetIntegerv(pname, params);
1159   if (pname == GL_DEPTH_BITS) { 
1160     GLXContext gl_ctx = glXGetCurrentContext();
1161     Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1162     /*TRACE("returns Wine Ctx as %p\n", ret);*/
1163     /** 
1164      * if we cannot find a Wine Context
1165      * we only have the default wine desktop context, 
1166      * so if we have only a 24 depth say we have 32
1167      */
1168     if (NULL == ret && 24 == *params) { 
1169       *params = 32;
1170     }
1171     TRACE("returns GL_DEPTH_BITS as '%d'\n", *params);
1172   }
1173   if (pname == GL_ALPHA_BITS) {
1174     GLint tmp;
1175     GLXContext gl_ctx = glXGetCurrentContext();
1176     Wine_GLContext* ret = get_context_from_GLXContext(gl_ctx);
1177     glXGetFBConfigAttrib(ret->display, ret->fb_conf, GLX_ALPHA_SIZE, &tmp);
1178     TRACE("returns GL_ALPHA_BITS as '%d'\n", tmp);
1179     *params = tmp;
1180   }
1181 }
1182
1183
1184 /* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
1185    include all dependencies
1186 */
1187 #ifndef SONAME_LIBGL
1188 #define SONAME_LIBGL "libGL.so"
1189 #endif
1190
1191 static void wgl_initialize_glx(Display *display, int screen, glXGetProcAddressARB_t proc) 
1192 {
1193   const char *server_glx_version = glXQueryServerString(display, screen, GLX_VERSION);
1194   const char *server_glx_extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1195   /*
1196   const char *client_glx_version = glXGetClientString(display, GLX_VERSION);
1197   const char *client_glx_extensions = glXGetClientString(display, GLX_EXTENSIONS);
1198   const char *glx_extensions = glXQueryExtensionsString(display, screen);
1199   */
1200
1201   memset(&wine_glx, 0, sizeof(wine_glx));
1202
1203   if (!strcmp("1.2", server_glx_version)) {
1204     wine_glx.version = 2;
1205   } else {
1206     wine_glx.version = 3;
1207   }
1208
1209   if (2 < wine_glx.version) {
1210     wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfig");
1211     wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttrib");
1212     wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfig");
1213
1214     /*wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");*/
1215     wine_glx.p_glXQueryDrawable = proc( (const GLubyte *) "glXQueryDrawable");
1216   } else {
1217     if (NULL != strstr(server_glx_extensions, "GLX_SGIX_fbconfig")) {
1218       wine_glx.p_glXChooseFBConfig = proc( (const GLubyte *) "glXChooseFBConfigSGIX");
1219       wine_glx.p_glXGetFBConfigAttrib = proc( (const GLubyte *) "glXGetFBConfigAttribSGIX");
1220       wine_glx.p_glXGetVisualFromFBConfig = proc( (const GLubyte *) "glXGetVisualFromFBConfigSGIX");
1221     } else {
1222       ERR(" glx_version as %s and GLX_SGIX_fbconfig extension is unsupported. Expect problems.\n", server_glx_version);
1223     }
1224   }
1225   /** try anyway to retrieve that calls, maybe they works using glx client tricks */
1226   wine_glx.p_glXGetFBConfigs = proc( (const GLubyte *) "glXGetFBConfigs");
1227   wine_glx.p_glXMakeContextCurrent = proc( (const GLubyte *) "glXMakeContextCurrent");
1228 }
1229
1230 /* This is for brain-dead applications that use OpenGL functions before even
1231    creating a rendering context.... */
1232 static BOOL process_attach(void)
1233 {
1234   XWindowAttributes win_attr;
1235   Visual *rootVisual;
1236   int num;
1237   XVisualInfo template;
1238   HDC hdc;
1239   XVisualInfo *vis = NULL;
1240   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
1241   HMODULE mod = GetModuleHandleA( "winex11.drv" );
1242   void *opengl_handle;
1243   DWORD size = sizeof(internal_gl_disabled_extensions);
1244   HKEY hkey = 0;
1245
1246   if (!root || !mod)
1247   {
1248       ERR("X11DRV not loaded. Cannot create default context.\n");
1249       return FALSE;
1250   }
1251
1252   wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
1253   wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
1254
1255   hdc = GetDC(0);
1256   default_display = get_display( hdc );
1257   ReleaseDC( 0, hdc );
1258   if (!default_display)
1259   {
1260       ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
1261       return FALSE;
1262   }
1263
1264   ENTER_GL();
1265
1266   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
1267      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
1268      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
1269      with mismatched visuals.  Note that the Root Window visual may not be double
1270      buffered, so apps actually attempting to render this way may flicker */
1271   if (XGetWindowAttributes( default_display, root, &win_attr ))
1272   {
1273     rootVisual = win_attr.visual;
1274   }
1275   else
1276   {
1277     /* Get the default visual, since we can't seem to get the attributes from the
1278        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
1279     rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
1280   }
1281
1282   template.visualid = XVisualIDFromVisual(rootVisual);
1283   vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
1284   if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
1285   if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
1286   XFree(vis);
1287   LEAVE_GL();
1288
1289   opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
1290   if (opengl_handle != NULL) {
1291    p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
1292    wine_dlclose(opengl_handle, NULL, 0);
1293    if (p_glXGetProcAddressARB == NULL)
1294            TRACE("could not find glXGetProcAddressARB in libGL.\n");
1295   }
1296
1297   internal_gl_disabled_extensions[0] = 0;
1298   if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\OpenGL", &hkey)) {
1299     if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) {
1300       TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions);
1301     }
1302     RegCloseKey(hkey);
1303   }
1304
1305   if (default_cx == NULL) {
1306     ERR("Could not create default context.\n");
1307   }
1308   else
1309   {
1310     /* After context initialize also the list of supported WGL extensions. */
1311     wgl_initialize_glx(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB);
1312     wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display), p_glXGetProcAddressARB, internal_gl_disabled_extensions);
1313   }
1314   return TRUE;
1315 }
1316
1317
1318 /**********************************************************************/
1319
1320 static void process_detach(void)
1321 {
1322   glXDestroyContext(default_display, default_cx);
1323
1324   /* Do not leak memory... */
1325   wgl_ext_finalize_extensions();
1326   if (NULL != internal_gl_extensions) {
1327     HeapFree(GetProcessHeap(), 0, internal_gl_extensions);
1328   }
1329 }
1330
1331 /***********************************************************************
1332  *           OpenGL initialisation routine
1333  */
1334 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1335 {
1336     switch(reason)
1337     {
1338     case DLL_PROCESS_ATTACH:
1339         opengl32_handle = hinst;
1340         DisableThreadLibraryCalls(hinst);
1341         return process_attach();
1342     case DLL_PROCESS_DETACH:
1343         process_detach();
1344         break;
1345     }
1346     return TRUE;
1347 }