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