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