DrawText ellipsification on all lines, not just single-line.
[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 /***********************************************************************
237  *              wglGetProcAddress (OPENGL32.@)
238  */
239 static int compar(const void *elt_a, const void *elt_b) {
240   return strcmp(((OpenGL_extension *) elt_a)->name,
241                 ((OpenGL_extension *) elt_b)->name);
242 }
243
244 void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
245   void *local_func;
246   static HMODULE hm = 0;
247   OpenGL_extension  ext;
248   OpenGL_extension *ext_ret;
249
250
251   TRACE("(%s)\n", lpszProc);
252
253   if (hm == 0)
254       hm = GetModuleHandleA("opengl32");
255
256   /* First, look if it's not already defined in the 'standard' OpenGL functions */
257   if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
258     TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
259     return local_func;
260   }
261
262   /* After that, search in the thunks to find the real name of the extension */
263   ext.name = (char *) lpszProc;
264   ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
265                                          extension_registry_size, sizeof(OpenGL_extension), compar);
266
267   if (ext_ret == NULL) {
268     /* Some sanity checks :-) */
269     if (glXGetProcAddressARB(lpszProc) != NULL) {
270       ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
271       return NULL;
272     }
273
274     WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
275     return NULL;
276   } else {
277     /* After that, look at the extensions defined in the Linux OpenGL library */
278     if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
279       char buf[256];
280       void *ret = NULL;
281       
282       /* Remove the 3 last letters (EXT, ARB, ...).
283          
284          I know that some extensions have more than 3 letters (MESA, NV,
285          INTEL, ...), but this is only a stop-gap measure to fix buggy
286          OpenGL drivers (moreover, it is only useful for old 1.0 apps
287          that query the glBindTextureEXT extension).
288       */
289       strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
290       buf[strlen(ext_ret->glx_name) - 3] = '\0';
291       TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
292       
293       ret = GetProcAddress(hm, buf);
294       if (ret != NULL) {
295         TRACE(" found function in main OpenGL library (%p) !\n", ret);
296       } else {
297         WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
298       } 
299       
300       return ret;
301     } else {
302       TRACE(" returning function  (%p)\n", ext_ret->func);
303       *(ext_ret->func_ptr) = local_func;
304       
305       return ext_ret->func;
306     }
307   }
308 }
309
310 /***********************************************************************
311  *              wglMakeCurrent (OPENGL32.@)
312  */
313 BOOL WINAPI wglMakeCurrent(HDC hdc,
314                            HGLRC hglrc) {
315   BOOL ret;
316
317   TRACE("(%08x,%p)\n", hdc, hglrc);
318   
319   if (hglrc == NULL) {
320     ENTER_GL();
321     ret = glXMakeCurrent(gdi_display,
322                          None,
323                          NULL);
324     LEAVE_GL();
325   } else {
326     DC * dc = DC_GetDCPtr( hdc );
327     
328     if (dc == NULL) {
329       ERR("Null DC !!!\n");
330       ret = FALSE;
331     } else {
332       X11DRV_PDEVICE *physDev;
333       Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
334       
335       physDev =(X11DRV_PDEVICE *)dc->physDev;
336
337       if (ctx->ctx == NULL) {
338         ENTER_GL();
339         ctx->ctx = glXCreateContext(gdi_display, ctx->vis, NULL, True);
340         LEAVE_GL();
341         TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
342       }
343       
344       ENTER_GL();
345       ret = glXMakeCurrent(gdi_display,
346                            physDev->drawable,
347                            ctx->ctx);
348       LEAVE_GL();
349       GDI_ReleaseObj( hdc );
350     }
351   }
352   TRACE(" returning %s\n", (ret ? "True" : "False"));
353   return ret;
354 }
355
356 /***********************************************************************
357  *              wglRealizeLayerPalette (OPENGL32.@)
358  */
359 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
360                                    int iLayerPlane,
361                                    BOOL bRealize) {
362   FIXME("()\n");
363
364   return FALSE;
365 }
366
367 /***********************************************************************
368  *              wglSetLayerPaletteEntries (OPENGL32.@)
369  */
370 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
371                                      int iLayerPlane,
372                                      int iStart,
373                                      int cEntries,
374                                      const COLORREF *pcr) {
375   FIXME("(): stub !\n");
376
377   return 0;
378 }
379
380 /***********************************************************************
381  *              wglShareLists (OPENGL32.@)
382  */
383 BOOL WINAPI wglShareLists(HGLRC hglrc1,
384                           HGLRC hglrc2) {
385   Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
386   Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
387   
388   TRACE("(%p, %p)\n", org, dest);
389
390   if (dest->ctx != NULL) {
391     ERR("Could not share display lists, context already created !\n");
392     return FALSE;
393   } else {
394     if (org->ctx == NULL) {
395       ENTER_GL();
396       org->ctx = glXCreateContext(gdi_display, org->vis, NULL, True);
397       LEAVE_GL();
398       TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
399     }
400
401     ENTER_GL();
402     /* Create the destination context with display lists shared */
403     dest->ctx = glXCreateContext(gdi_display, dest->vis, org->ctx, True);
404     LEAVE_GL();
405     TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
406   }
407   
408   return TRUE;
409 }
410
411 /***********************************************************************
412  *              wglSwapLayerBuffers (OPENGL32.@)
413  */
414 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
415                                 UINT fuPlanes) {
416   FIXME("(): stub !\n");
417
418   return FALSE;
419 }
420
421 /***********************************************************************
422  *              wglUseFontBitmapsA (OPENGL32.@)
423  */
424 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
425                                DWORD first,
426                                DWORD count,
427                                DWORD listBase) {
428   DC * dc = DC_GetDCPtr( hdc );
429   X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
430   fontObject* pfo = XFONT_GetFontObject( physDev->font );
431   Font fid = pfo->fs->fid;
432
433   TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
434
435   ENTER_GL();
436   /* I assume that the glyphs are at the same position for X and for Windows */
437   glXUseXFont(fid, first, count, listBase);
438   LEAVE_GL();
439   GDI_ReleaseObj( hdc );
440   return TRUE;
441 }
442  
443 /***********************************************************************
444  *              wglUseFontOutlinesA (OPENGL32.@)
445  */
446 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
447                                 DWORD first,
448                                 DWORD count,
449                                 DWORD listBase,
450                                 FLOAT deviation,
451                                 FLOAT extrusion,
452                                 int format,
453                                 LPGLYPHMETRICSFLOAT lpgmf) {
454   FIXME("(): stub !\n");
455
456   return FALSE;
457 }
458
459
460 /* This is for brain-dead applications that use OpenGL functions before even
461    creating a rendering context.... */
462 static void process_attach(void) {
463   XWindowAttributes win_attr;
464   Visual *rootVisual;
465   int num;
466   XVisualInfo template;
467   XVisualInfo *vis = NULL;
468   Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
469
470   if (!root)
471   {
472       ERR("X11DRV not loaded. Cannot create default context.\n");
473       return;
474   }
475
476   ENTER_GL();
477
478   /* Try to get the visual from the Root Window.  We can't use the standard (presumably
479      double buffered) X11DRV visual with the Root Window, since we don't know if the Root
480      Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal 
481      with mismatched visuals.  Note that the Root Window visual may not be double 
482      buffered, so apps actually attempting to render this way may flicker */
483   if (XGetWindowAttributes( gdi_display, root, &win_attr ))
484   {
485     rootVisual = win_attr.visual; 
486   }
487   else
488   {
489     /* Get the default visual, since we can't seem to get the attributes from the 
490        Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
491     rootVisual = DefaultVisual( gdi_display, DefaultScreen(gdi_display) );
492   }
493
494   template.visualid = XVisualIDFromVisual(rootVisual);
495   vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
496   if (vis != NULL)        default_cx = glXCreateContext(gdi_display, vis, 0, GL_TRUE);
497   if (default_cx != NULL) glXMakeCurrent(gdi_display, root, default_cx);
498   XFree(vis);
499   LEAVE_GL();
500
501   if (default_cx == NULL) {
502     ERR("Could not create default context.\n");
503   }
504   
505   context_array = NULL;
506 }
507
508 static void process_detach(void) {
509   glXDestroyContext(gdi_display, default_cx);
510 }
511
512 /***********************************************************************
513  *           OpenGL initialisation routine
514  */
515 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
516 {
517   switch(reason) {
518   case DLL_PROCESS_ATTACH:
519     process_attach();
520     break;
521   case DLL_PROCESS_DETACH:
522     process_detach();
523     break;
524   }
525   return TRUE;
526 }