Fixed the behavior for SHGetFileInfo when the SHGFI_USEFILEATTRIBUTES
[wine] / dlls / opengl32 / wgl.c
1 /* Window-specific OpenGL functions implementation.
2
3      Copyright (c) 1999 Lionel Ulmer
4 */
5
6 #include "config.h"
7
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "wine/exception.h"
12
13 #include "debugtools.h"
14 #include "gdi.h"
15 #include "windef.h"
16 #include "winerror.h"
17 #include "wine_gl.h"
18 #include "x11drv.h"
19 #include "x11font.h"
20
21 #include "wgl.h"
22 #include "opengl_ext.h"
23
24 DEFAULT_DEBUG_CHANNEL(opengl);
25
26 static GLXContext default_cx = NULL;
27
28 typedef struct wine_glcontext {
29   HDC hdc;
30   GLXContext ctx;
31   XVisualInfo *vis;
32   struct wine_glcontext *next;
33   struct wine_glcontext *prev;
34 } Wine_GLContext;
35 static Wine_GLContext *context_array;
36
37 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx) {
38   Wine_GLContext *ret = context_array;
39   while (ret != NULL) if (ctx == ret->ctx) break; else ret = ret->next;
40   return ret;
41 }
42   
43 static inline void free_context(Wine_GLContext *context) {
44   if (context->next != NULL) context->next->prev = context->prev;
45   if (context->prev != NULL) context->prev->next = context->next;
46   else                       context_array = context->next;
47
48   HeapFree(GetProcessHeap(), 0, context);
49 }
50
51 static inline Wine_GLContext *alloc_context(void) {
52   Wine_GLContext *ret;
53
54   ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext));
55   ret->next = context_array;
56   if (context_array != NULL) context_array->prev = ret;
57   else                       context_array = ret;
58   
59   return ret;
60 }
61
62
63 static int XGLErrorFlag = 0;
64 static int XGLErrorHandler(Display *dpy, XErrorEvent *event) {
65     XGLErrorFlag = 1;
66     return 0;
67 }
68 /* filter for page-fault exceptions */
69 static WINE_EXCEPTION_FILTER(page_fault)
70 {
71   return EXCEPTION_EXECUTE_HANDLER;
72 }
73
74 /***********************************************************************
75  *              wglCreateContext (OPENGL32.@)
76  */
77 HGLRC WINAPI wglCreateContext(HDC hdc)
78 {
79   XVisualInfo *vis;
80   Wine_GLContext *ret;
81   int num;
82   XVisualInfo template;
83
84   TRACE("(%08x)\n", hdc);
85
86   /* First, get the visual in use by the X11DRV */
87   template.visualid = GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
88   vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
89
90   if (vis == NULL) {
91     ERR("NULL visual !!!\n");
92     /* Need to set errors here */
93     return NULL;
94   }
95
96   /* The context will be allocated in the wglMakeCurrent call */
97   ENTER_GL();
98   ret = alloc_context();
99   LEAVE_GL();
100   ret->hdc = hdc;
101   ret->vis = vis;
102
103   TRACE(" creating context %p (GL context creation delayed)\n", ret);
104   return (HGLRC) ret;
105 }
106
107 /***********************************************************************
108  *              wglCreateLayerContext (OPENGL32.@)
109  */
110 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
111                                    int iLayerPlane) {
112   FIXME("(%08x,%d): stub !\n", hdc, iLayerPlane);
113
114   return NULL;
115 }
116
117 /***********************************************************************
118  *              wglCopyContext (OPENGL32.@)
119  */
120 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
121                            HGLRC hglrcDst,
122                            UINT mask) {
123   FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
124
125   return FALSE;
126 }
127
128 /***********************************************************************
129  *              wglDeleteContext (OPENGL32.@)
130  */
131 BOOL WINAPI wglDeleteContext(HGLRC hglrc) {
132   int (*WineXHandler)(Display *, XErrorEvent *);
133   Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
134   BOOL ret;
135   
136   TRACE("(%p)\n", hglrc);
137   
138   ENTER_GL();
139   /* A game (Half Life not to name it) deletes twice the same context. To prevent
140      crashes, run with our own error function enabled */
141   XSync(gdi_display, False);
142   XGLErrorFlag = 0;
143   WineXHandler = XSetErrorHandler(XGLErrorHandler);
144   __TRY {
145     glXDestroyContext(gdi_display, ctx->ctx);
146     XSync(gdi_display, False);
147     XFlush(gdi_display);
148
149     if (XGLErrorHandler == 0) free_context(ctx);
150   }
151   __EXCEPT(page_fault) {
152     XGLErrorFlag = 1;
153   }
154   __ENDTRY
155
156   ret = TRUE;
157   XSetErrorHandler(WineXHandler);
158   if (XGLErrorFlag) {
159     WARN("Error deleting context !\n");
160     SetLastError(ERROR_INVALID_HANDLE);
161     ret = FALSE;
162   }
163   LEAVE_GL();
164   
165   return ret;
166 }
167
168 /***********************************************************************
169  *              wglDescribeLayerPlane (OPENGL32.@)
170  */
171 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
172                                   int iPixelFormat,
173                                   int iLayerPlane,
174                                   UINT nBytes,
175                                   LPLAYERPLANEDESCRIPTOR plpd) {
176   FIXME("(%08x,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
177
178   return FALSE;
179 }
180
181 /***********************************************************************
182  *              wglGetCurrentContext (OPENGL32.@)
183  */
184 HGLRC WINAPI wglGetCurrentContext(void) {
185   GLXContext gl_ctx;
186   Wine_GLContext *ret;
187
188   TRACE("()\n");
189
190   ENTER_GL();
191   gl_ctx = glXGetCurrentContext();
192   ret = get_context_from_GLXContext(gl_ctx);
193   LEAVE_GL();
194
195   TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
196   
197   return ret;
198 }
199
200 /***********************************************************************
201  *              wglGetCurrentDC (OPENGL32.@)
202  */
203 HDC WINAPI wglGetCurrentDC(void) {
204   GLXContext gl_ctx;
205   Wine_GLContext *ret;
206
207   TRACE("()\n");
208   
209   ENTER_GL();
210   gl_ctx = glXGetCurrentContext();
211   ret = get_context_from_GLXContext(gl_ctx);
212   LEAVE_GL();
213
214   if (ret) {
215     TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
216     return ret->hdc;
217   } else {
218     TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
219     return 0;
220   }
221 }
222
223 /***********************************************************************
224  *              wglGetLayerPaletteEntries (OPENGL32.@)
225  */
226 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
227                                      int iLayerPlane,
228                                      int iStart,
229                                      int cEntries,
230                                      const COLORREF *pcr) {
231   FIXME("(): stub !\n");
232
233   return 0;
234 }
235
236 static int compar(const void *elt_a, const void *elt_b) {
237   return strcmp(((OpenGL_extension *) elt_a)->name,
238                 ((OpenGL_extension *) elt_b)->name);
239 }
240
241 /***********************************************************************
242  *              wglGetProcAddress (OPENGL32.@)
243  */
244 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
245   void *local_func;
246   static HMODULE hm = 0;
247
248   TRACE("(%s)\n", lpszProc);
249
250   if (hm == 0)
251       hm = GetModuleHandleA("opengl32");
252
253   /* First, look if it's not already defined in the 'standard' OpenGL functions */
254   if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
255     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
256     return local_func;
257   }
258
259   /* After that, look at the extensions defined in the Linux OpenGL library */
260   if ((local_func = glXGetProcAddressARB(lpszProc)) == NULL) {
261     char buf[256];
262     void *ret = NULL;
263     
264     /* Remove the 3 last letters (EXT, ARB, ...).
265        
266        I know that some extensions have more than 3 letters (MESA, NV,
267        INTEL, ...), but this is only a stop-gap measure to fix buggy
268        OpenGL drivers (moreover, it is only useful for old 1.0 apps
269        that query the glBindTextureEXT extension).
270     */
271     strncpy(buf, lpszProc, strlen(lpszProc) - 3);
272     buf[strlen(lpszProc) - 3] = '\0';
273     TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
274     
275     ret = GetProcAddress(hm, buf);
276     if (ret != NULL) {
277       TRACE(" found function in main OpenGL library (%p) !\n", ret);
278     }
279
280     return ret;
281   } else {
282     OpenGL_extension  ext;
283     OpenGL_extension *ret;
284
285     ext.name = (char *) lpszProc;
286     ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
287                                        extension_registry_size, sizeof(OpenGL_extension), compar);
288
289     if (ret != NULL) {
290       TRACE(" returning function  (%p)\n", ret->func);
291       *(ret->func_ptr) = local_func;
292
293       return ret->func;
294     } else {
295       ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
296       return NULL;
297     }
298   }
299 }
300
301 /***********************************************************************
302  *              wglMakeCurrent (OPENGL32.@)
303  */
304 BOOL WINAPI wglMakeCurrent(HDC hdc,
305                            HGLRC hglrc) {
306   BOOL ret;
307
308   TRACE("(%08x,%p)\n", hdc, hglrc);
309   
310   if (hglrc == NULL) {
311     ENTER_GL();
312     ret = glXMakeCurrent(gdi_display,
313                          None,
314                          NULL);
315     LEAVE_GL();
316   } else {
317     DC * dc = DC_GetDCPtr( hdc );
318     
319     if (dc == NULL) {
320       ERR("Null DC !!!\n");
321       ret = FALSE;
322     } else {
323       X11DRV_PDEVICE *physDev;
324       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
325       
326       physDev =(X11DRV_PDEVICE *)dc->physDev;
327
328       if (ctx->ctx == NULL) {
329         ENTER_GL();
330         ctx->ctx = glXCreateContext(gdi_display, ctx->vis, NULL, True);
331         LEAVE_GL();
332         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
333       }
334       
335       ENTER_GL();
336       ret = glXMakeCurrent(gdi_display,
337                            physDev->drawable,
338                            ctx->ctx);
339       LEAVE_GL();
340       GDI_ReleaseObj( hdc );
341     }
342   }
343   TRACE(" returning %s\n", (ret ? "True" : "False"));
344   return ret;
345 }
346
347 /***********************************************************************
348  *              wglRealizeLayerPalette (OPENGL32.@)
349  */
350 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
351                                    int iLayerPlane,
352                                    BOOL bRealize) {
353   FIXME("()\n");
354
355   return FALSE;
356 }
357
358 /***********************************************************************
359  *              wglSetLayerPaletteEntries (OPENGL32.@)
360  */
361 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
362                                      int iLayerPlane,
363                                      int iStart,
364                                      int cEntries,
365                                      const COLORREF *pcr) {
366   FIXME("(): stub !\n");
367
368   return 0;
369 }
370
371 /***********************************************************************
372  *              wglShareLists (OPENGL32.@)
373  */
374 BOOL WINAPI wglShareLists(HGLRC hglrc1,
375                           HGLRC hglrc2) {
376   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
377   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
378   
379   TRACE("(%p, %p)\n", org, dest);
380
381   if (dest->ctx != NULL) {
382     ERR("Could not share display lists, context already created !\n");
383     return FALSE;
384   } else {
385     if (org->ctx == NULL) {
386       ENTER_GL();
387       org->ctx = glXCreateContext(gdi_display, org->vis, NULL, True);
388       LEAVE_GL();
389       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
390     }
391
392     ENTER_GL();
393     /* Create the destination context with display lists shared */
394     dest->ctx = glXCreateContext(gdi_display, dest->vis, org->ctx, True);
395     LEAVE_GL();
396     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
397   }
398   
399   return TRUE;
400 }
401
402 /***********************************************************************
403  *              wglSwapLayerBuffers (OPENGL32.@)
404  */
405 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
406                                 UINT fuPlanes) {
407   FIXME("(): stub !\n");
408
409   return FALSE;
410 }
411
412 /***********************************************************************
413  *              wglUseFontBitmapsA (OPENGL32.@)
414  */
415 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
416                                DWORD first,
417                                DWORD count,
418                                DWORD listBase) {
419   DC * dc = DC_GetDCPtr( hdc );
420   X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
421   fontObject* pfo = XFONT_GetFontObject( physDev->font );
422   Font fid = pfo->fs->fid;
423
424   TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
425
426   ENTER_GL();
427   /* I assume that the glyphs are at the same position for X and for Windows */
428   glXUseXFont(fid, first, count, listBase);
429   LEAVE_GL();
430   GDI_ReleaseObj( hdc );
431   return TRUE;
432 }
433  
434 /***********************************************************************
435  *              wglUseFontOutlinesA (OPENGL32.@)
436  */
437 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
438                                 DWORD first,
439                                 DWORD count,
440                                 DWORD listBase,
441                                 FLOAT deviation,
442                                 FLOAT extrusion,
443                                 int format,
444                                 LPGLYPHMETRICSFLOAT lpgmf) {
445   FIXME("(): stub !\n");
446
447   return FALSE;
448 }
449
450
451 /* This is for brain-dead applications that use OpenGL functions before even
452    creating a rendering context.... */
453 static void process_attach(void) {
454   XWindowAttributes win_attr;
455   Visual *rootVisual;
456   int num;
457   XVisualInfo template;
458   XVisualInfo *vis = NULL;
459   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
460
461   if (!root)
462   {
463       ERR("X11DRV not loaded. Cannot create default context.\n");
464       return;
465   }
466
467   ENTER_GL();
468
469   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
470      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
471      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal 
472      with mismatched visuals.  Note that the Root Window visual may not be double 
473      buffered, so apps actually attempting to render this way may flicker */
474   if (XGetWindowAttributes( gdi_display, root, &win_attr ))
475   {
476     rootVisual = win_attr.visual; 
477   }
478   else
479   {
480     /* Get the default visual, since we can't seem to get the attributes from the 
481        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
482     rootVisual = DefaultVisual( gdi_display, DefaultScreen(gdi_display) );
483   }
484
485   template.visualid = XVisualIDFromVisual(rootVisual);
486   vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
487   if (vis != NULL)        default_cx = glXCreateContext(gdi_display, vis, 0, GL_TRUE);
488   if (default_cx != NULL) glXMakeCurrent(gdi_display, root, default_cx);
489   XFree(vis);
490   LEAVE_GL();
491
492   if (default_cx == NULL) {
493     ERR("Could not create default context.\n");
494   }
495   
496   context_array = NULL;
497 }
498
499 static void process_detach(void) {
500   glXDestroyContext(gdi_display, default_cx);
501 }
502
503 /***********************************************************************
504  *           OpenGL initialisation routine
505  */
506 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
507 {
508   switch(reason) {
509   case DLL_PROCESS_ATTACH:
510     process_attach();
511     break;
512   case DLL_PROCESS_DETACH:
513     process_detach();
514     break;
515   }
516   return TRUE;
517 }