Added support for registry values larger than the server buffer.
[wine] / dlls / ddraw / ddraw / x11.c
1 /*              DirectDraw IDirectDraw Xlib interface
2  *
3  * Copyright 1997-2000 Marcus Meissner
4  * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5  */
6 /*
7  * This file contains the Xlib specific interface functions.
8  */
9
10 #include "config.h"
11
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <assert.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18
19 #include "winerror.h"
20 #include "ddraw.h"
21 #include "d3d.h"
22 #include "win.h"
23 #include "debugtools.h"
24 #include "message.h"
25 #include "options.h"
26 #include "monitor.h"
27
28 DEFAULT_DEBUG_CHANNEL(ddraw);
29
30 #include "x11_private.h"
31
32 #define DDPRIVATE(x) x11_dd_private *ddpriv = ((x11_dd_private*)(x)->private)
33 #define DPPRIVATE(x) x11_dp_private *dppriv = ((x11_dp_private*)(x)->private)
34 #define DSPRIVATE(x) x11_ds_private *dspriv = ((x11_ds_private*)(x)->private)
35
36 static inline BOOL get_option( const char *name, BOOL def ) {
37     return PROFILE_GetWineIniBool( "x11drv", name, def );
38 }
39
40 int _common_depth_to_pixelformat(
41     DWORD depth, DDPIXELFORMAT *pixelformat,DDPIXELFORMAT *screen_pixelformat,
42     int *pix_depth
43 ) {
44   XVisualInfo *vi;
45   XPixmapFormatValues *pf;
46   XVisualInfo vt;
47   int nvisuals, npixmap, i;
48   int match = 0;
49   int index = -2;
50
51   vi = TSXGetVisualInfo(display, VisualNoMask, &vt, &nvisuals);
52   pf = TSXListPixmapFormats(display, &npixmap);
53
54   for (i = 0; i < npixmap; i++) {
55     if (pf[i].depth == depth) {
56       int j;
57
58       for (j = 0; j < nvisuals; j++) {
59         if (vi[j].depth == pf[i].depth) {
60           pixelformat->dwSize = sizeof(*pixelformat);
61           if (depth == 8) {
62             pixelformat->dwFlags = DDPF_PALETTEINDEXED8|DDPF_RGB;
63             pixelformat->u1.dwRBitMask = 0;
64             pixelformat->u2.dwGBitMask = 0;
65             pixelformat->u3.dwBBitMask = 0;
66           } else {
67             pixelformat->dwFlags = DDPF_RGB;
68             pixelformat->u1.dwRBitMask = vi[j].red_mask;
69             pixelformat->u2.dwGBitMask = vi[j].green_mask;
70             pixelformat->u3.dwBBitMask = vi[j].blue_mask;
71           }
72           pixelformat->dwFourCC = 0;
73           pixelformat->u.dwRGBBitCount = pf[i].bits_per_pixel;
74           pixelformat->u4.dwRGBAlphaBitMask= 0;
75
76           *screen_pixelformat = *pixelformat;
77
78           if (pix_depth)
79             *pix_depth = vi[j].depth;
80
81           match = 1;
82           index = -1;
83           goto clean_up_and_exit;
84         }
85       }
86       WARN("No visual corresponding to pixmap format !\n");
87     }
88   }
89
90   if (match == 0) {
91     /* We try now to find an emulated mode */
92     int c;
93
94     for (c = 0; c < sizeof(ModeEmulations) / sizeof(Convert); c++) {
95       if (ModeEmulations[c].dest.depth == depth) {
96         /* Found an emulation function, now tries to find a matching visual / pixel format pair */
97         for (i = 0; i < npixmap; i++) {
98           if ((pf[i].depth == ModeEmulations[c].screen.depth) &&
99               (pf[i].bits_per_pixel == ModeEmulations[c].screen.bpp)) {
100             int j;
101
102             for (j = 0; j < nvisuals; j++) {
103               if (vi[j].depth == pf[i].depth) {
104                 screen_pixelformat->dwSize = sizeof(*screen_pixelformat);
105                 screen_pixelformat->dwFlags = DDPF_RGB;
106                 screen_pixelformat->dwFourCC = 0;
107                 screen_pixelformat->u.dwRGBBitCount = pf[i].bits_per_pixel;
108                 screen_pixelformat->u1.dwRBitMask = vi[j].red_mask;
109                 screen_pixelformat->u2.dwGBitMask = vi[j].green_mask;
110                 screen_pixelformat->u3.dwBBitMask = vi[j].blue_mask;
111                 screen_pixelformat->u4.dwRGBAlphaBitMask= 0;
112
113                 pixelformat->dwSize = sizeof(*pixelformat);
114                 pixelformat->dwFourCC = 0;
115                 if (depth == 8) {
116                   pixelformat->dwFlags = DDPF_RGB|DDPF_PALETTEINDEXED8;
117                   pixelformat->u.dwRGBBitCount = 8;
118                   pixelformat->u1.dwRBitMask = 0;
119                   pixelformat->u2.dwGBitMask = 0;
120                   pixelformat->u3.dwBBitMask = 0;
121                 } else {
122                   pixelformat->dwFlags = DDPF_RGB;
123                   pixelformat->u.dwRGBBitCount = ModeEmulations[c].dest.bpp;
124                   pixelformat->u1.dwRBitMask = ModeEmulations[c].dest.rmask;
125                   pixelformat->u2.dwGBitMask = ModeEmulations[c].dest.gmask;
126                   pixelformat->u3.dwBBitMask = ModeEmulations[c].dest.bmask;
127                 }
128                 pixelformat->u4.dwRGBAlphaBitMask= 0;    
129
130                 if (pix_depth)
131                   *pix_depth = vi[j].depth;
132
133                 match = 2;
134                 index = c;
135                 goto clean_up_and_exit;
136               }
137               ERR("No visual corresponding to pixmap format !\n");
138             }
139           }
140         }
141       }
142     }
143   }
144
145 clean_up_and_exit:
146   TSXFree(vi);
147   TSXFree(pf);
148
149   return index;
150 }
151
152 /*******************************************************************************
153  *                              IDirectDraw
154  */
155 #ifdef HAVE_LIBXXSHM
156 /* Error handlers for Image creation */
157 static int XShmErrorHandler(Display *dpy, XErrorEvent *event) {
158     XShmErrorFlag = 1;
159     return 0;
160 }
161
162 static XImage *create_xshmimage(
163     IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lpdsf
164 ) {
165     DSPRIVATE(lpdsf);
166     DDPRIVATE(This);
167     XImage *img;
168     int (*WineXHandler)(Display *, XErrorEvent *);
169
170     img = TSXShmCreateImage(display,
171         DefaultVisualOfScreen(X11DRV_GetXScreen()),
172         This->d.pixmap_depth,
173         ZPixmap,
174         NULL,
175         &(dspriv->shminfo),
176         lpdsf->s.surface_desc.dwWidth,
177         lpdsf->s.surface_desc.dwHeight
178     );
179
180     if (img == NULL) {
181         FIXME("Couldn't create XShm image (due to X11 remote display or failure).\nReverting to standard X images !\n");
182         ddpriv->xshm_active = 0;
183         return NULL;
184     }
185
186     dspriv->shminfo.shmid = shmget( IPC_PRIVATE, img->bytes_per_line * img->height, IPC_CREAT|0777 );
187     if (dspriv->shminfo.shmid < 0) {
188         FIXME("Couldn't create shared memory segment (due to X11 remote display or failure).\nReverting to standard X images !\n");
189         ddpriv->xshm_active = 0;
190         TSXDestroyImage(img);
191         return NULL;
192     }
193
194     dspriv->shminfo.shmaddr=img->data=(char*)shmat(dspriv->shminfo.shmid,0,0);
195
196     if (img->data == (char *) -1) {
197         FIXME("Couldn't attach shared memory segment (due to X11 remote display or failure).\nReverting to standard X images !\n");
198         ddpriv->xshm_active = 0;
199         TSXDestroyImage(img);
200         shmctl(dspriv->shminfo.shmid, IPC_RMID, 0);
201         return NULL;
202     }
203     dspriv->shminfo.readOnly = False;
204
205     /* This is where things start to get trickier....
206      * First, we flush the current X connections to be sure to catch all
207      * non-XShm related errors
208      */
209     TSXSync(display, False);
210     /* Then we enter in the non-thread safe part of the tests */
211     EnterCriticalSection( &X11DRV_CritSection );
212
213     /* Reset the error flag, sets our new error handler and try to attach
214      * the surface
215      */
216     XShmErrorFlag = 0;
217     WineXHandler = XSetErrorHandler(XShmErrorHandler);
218     XShmAttach(display, &(dspriv->shminfo));
219     XSync(display, False);
220
221     /* Check the error flag */
222     if (XShmErrorFlag) {
223         /* An error occured */
224         XFlush(display);
225         XShmErrorFlag = 0;
226         XDestroyImage(img);
227         shmdt(dspriv->shminfo.shmaddr);
228         shmctl(dspriv->shminfo.shmid, IPC_RMID, 0);
229         XSetErrorHandler(WineXHandler);
230
231         FIXME("Couldn't attach shared memory segment to X server (due to X11 remote display or failure).\nReverting to standard X images !\n");
232         ddpriv->xshm_active = 0;
233
234         /* Leave the critical section */
235         LeaveCriticalSection( &X11DRV_CritSection );
236         return NULL;
237     }
238     /* Here, to be REALLY sure, I should do a XShmPutImage to check if
239      * this works, but it may be a bit overkill....
240      */
241     XSetErrorHandler(WineXHandler);
242     LeaveCriticalSection( &X11DRV_CritSection );
243
244     shmctl(dspriv->shminfo.shmid, IPC_RMID, 0);
245
246     if (This->d.pixel_convert != NULL) {
247         int bpp = PFGET_BPP(This->d.directdraw_pixelformat);
248         lpdsf->s.surface_desc.u1.lpSurface = VirtualAlloc(
249             NULL,
250             lpdsf->s.surface_desc.dwWidth *
251             lpdsf->s.surface_desc.dwHeight *
252             bpp,
253             MEM_RESERVE | MEM_COMMIT,
254             PAGE_READWRITE
255         );
256     } else {
257         lpdsf->s.surface_desc.u1.lpSurface = img->data;
258         VirtualAlloc(img->data, img->bytes_per_line * img->height, MEM_RESERVE|MEM_SYSTEM, PAGE_READWRITE);
259     }
260     return img;
261 }
262 #endif /* HAVE_LIBXXSHM */
263
264 static XImage *create_ximage(IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lpdsf) {
265     XImage *img = NULL;
266     DDPRIVATE(This);
267     void *img_data;
268     int bpp = PFGET_BPP(This->d.directdraw_pixelformat);
269     
270 #ifdef HAVE_LIBXXSHM
271     if (ddpriv->xshm_active)
272         img = create_xshmimage(This, lpdsf);
273
274     if (img == NULL) {
275 #endif
276     /* Allocate surface memory */
277         lpdsf->s.surface_desc.u1.lpSurface = VirtualAlloc(
278             NULL,
279             lpdsf->s.surface_desc.dwWidth *
280             lpdsf->s.surface_desc.dwHeight *
281             bpp,
282             MEM_RESERVE | MEM_COMMIT,
283             PAGE_READWRITE
284         );
285
286         if (This->d.pixel_convert != NULL)
287             img_data = HeapAlloc(
288                 GetProcessHeap(),
289                 HEAP_ZERO_MEMORY,
290                 lpdsf->s.surface_desc.dwWidth *
291                 lpdsf->s.surface_desc.dwHeight *
292                 bpp
293             );
294         else
295             img_data = lpdsf->s.surface_desc.u1.lpSurface;
296
297         /* In this case, create an XImage */
298         img = TSXCreateImage(display,
299             DefaultVisualOfScreen(X11DRV_GetXScreen()),
300             This->d.pixmap_depth,
301             ZPixmap,
302             0,
303             img_data,
304             lpdsf->s.surface_desc.dwWidth,
305             lpdsf->s.surface_desc.dwHeight,
306             32,
307             lpdsf->s.surface_desc.dwWidth*bpp
308         );
309 #ifdef HAVE_LIBXXSHM
310     }
311 #endif
312     /* assert(bpp*lpdsf->s.surface_desc.dwWidth == img->bytes_per_line); */
313
314     if (This->d.pixel_convert != NULL)
315         lpdsf->s.surface_desc.lPitch = bpp*lpdsf->s.surface_desc.dwWidth;
316     else
317         lpdsf->s.surface_desc.lPitch = img->bytes_per_line;
318     return img;
319 }
320
321 static HRESULT WINAPI Xlib_IDirectDraw2Impl_CreateSurface(
322     LPDIRECTDRAW2 iface,LPDDSURFACEDESC lpddsd,LPDIRECTDRAWSURFACE *lpdsf,
323     IUnknown *lpunk
324 ) {
325     ICOM_THIS(IDirectDraw2Impl,iface);
326     IDirectDrawSurfaceImpl* dsurf;
327     x11_ds_private      *dspriv;
328
329     TRACE("(%p)->CreateSurface(%p,%p,%p)\n", This,lpddsd,lpdsf,lpunk);
330
331     if (TRACE_ON(ddraw)) _dump_surface_desc(lpddsd);
332
333     *lpdsf = HeapAlloc(
334         GetProcessHeap(),
335         HEAP_ZERO_MEMORY,
336         sizeof(IDirectDrawSurfaceImpl)
337     );
338     dsurf = (IDirectDrawSurfaceImpl*)*lpdsf;
339     dsurf->ref                 = 2;
340     dsurf->private = HeapAlloc(
341             GetProcessHeap(),
342             HEAP_ZERO_MEMORY,
343             sizeof(x11_ds_private)
344     );
345     ICOM_VTBL(dsurf) = (ICOM_VTABLE(IDirectDrawSurface)*)&xlib_dds4vt;
346     dspriv = (x11_ds_private*)dsurf->private;
347
348     dsurf->s.ddraw      = This;
349     IDirectDraw2_AddRef(iface);
350
351     dsurf->s.palette    = NULL;
352     dsurf->s.lpClipper  = NULL;
353     dspriv->image       = NULL; /* This is for off-screen buffers */
354
355     /* Copy the surface description */
356     dsurf->s.surface_desc = *lpddsd;
357
358     if (!(lpddsd->dwFlags & DDSD_WIDTH))
359         dsurf->s.surface_desc.dwWidth  = This->d.width;
360     if (!(lpddsd->dwFlags & DDSD_HEIGHT))
361         dsurf->s.surface_desc.dwHeight = This->d.height;
362     dsurf->s.surface_desc.dwFlags |= DDSD_WIDTH|DDSD_HEIGHT;
363
364     /* Check if this a 'primary surface' or not */
365     if ((lpddsd->dwFlags & DDSD_CAPS) && 
366         (lpddsd->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
367     ) {
368         XImage *img;
369
370         TRACE("using standard XImage for a primary surface (%p)\n", dsurf);
371         /* Create the XImage */
372         img = create_ximage(This,(IDirectDrawSurface4Impl*)dsurf);
373         if (img == NULL)
374             return DDERR_OUTOFMEMORY;
375         dspriv->image = img;
376
377         /* Add flags if there were not present */
378         dsurf->s.surface_desc.dwFlags |= DDSD_WIDTH|DDSD_HEIGHT|DDSD_PITCH|DDSD_LPSURFACE|DDSD_PIXELFORMAT;
379         dsurf->s.surface_desc.dwWidth = This->d.width;
380         dsurf->s.surface_desc.dwHeight = This->d.height;
381         dsurf->s.surface_desc.ddsCaps.dwCaps |= DDSCAPS_VISIBLE|DDSCAPS_VIDEOMEMORY;
382         dsurf->s.surface_desc.ddpfPixelFormat = This->d.directdraw_pixelformat;
383
384         /* Check for backbuffers */
385         if (lpddsd->dwFlags & DDSD_BACKBUFFERCOUNT) {
386             IDirectDrawSurface4Impl*    back;
387             XImage *img;
388             int i;
389
390             for (i=lpddsd->dwBackBufferCount;i--;) {
391                 x11_ds_private *bspriv;
392                 back = (IDirectDrawSurface4Impl*)HeapAlloc(
393                     GetProcessHeap(),
394                     HEAP_ZERO_MEMORY,
395                     sizeof(IDirectDrawSurface4Impl)
396                 );
397                 TRACE("allocated back-buffer (%p)\n", back);
398
399                 IDirectDraw2_AddRef(iface);
400                 back->s.ddraw = This;
401                 
402                 back->ref = 2;
403                 ICOM_VTBL(back)=(ICOM_VTABLE(IDirectDrawSurface4)*)&xlib_dds4vt;
404                 /* Copy the surface description from the front buffer */
405                 back->s.surface_desc = dsurf->s.surface_desc;
406                 back->s.surface_desc.u1.lpSurface = NULL;
407                 
408                 back->private = HeapAlloc(
409                     GetProcessHeap(),
410                     HEAP_ZERO_MEMORY,
411                     sizeof(x11_ds_private)
412                 );
413                 bspriv = (x11_ds_private*)back->private;
414
415                 /* Create the XImage. */
416                 img = create_ximage(This, back);
417                 if (img == NULL)
418                     return DDERR_OUTOFMEMORY;
419                 TRACE("bspriv = %p\n",bspriv);
420                 bspriv->image = img;
421
422                 /* Add relevant info to front and back buffers */
423                 /* FIXME: backbuffer/frontbuffer handling broken here, but
424                  * will be fixed up in _Flip().
425                  */
426                 SDDSCAPS(dsurf) |= DDSCAPS_FRONTBUFFER;
427                 SDDSCAPS(back) |= DDSCAPS_BACKBUFFER|DDSCAPS_VIDEOMEMORY|DDSCAPS_FLIP;
428                 back->s.surface_desc.dwFlags &= ~DDSD_BACKBUFFERCOUNT;
429                 SDDSCAPS(back) &= ~DDSCAPS_VISIBLE;
430                 TRACE("attaching surface %p to %p\n",back,*lpdsf);
431                 IDirectDrawSurface4_AddAttachedSurface((LPDIRECTDRAWSURFACE4)(*lpdsf),(LPDIRECTDRAWSURFACE4)back);
432             }
433         }
434     } else {
435         /* There is no Xlib-specific code here...
436          * Go to the common surface creation function
437          */
438         return common_off_screen_CreateSurface(This,dsurf);
439     }
440     return DD_OK;
441 }
442
443 /* 
444  * The Xlib Implementation tries to use the passed hwnd as drawing window,
445  * even when the approbiate bitmasks are not specified.
446  */
447 static HRESULT WINAPI Xlib_IDirectDraw2Impl_SetCooperativeLevel(
448     LPDIRECTDRAW2 iface,HWND hwnd,DWORD cooplevel
449 ) {
450     ICOM_THIS(IDirectDraw2Impl,iface);
451     DDPRIVATE(This);
452
453     FIXME("(%p)->(%08lx,%08lx)\n",This,(DWORD)hwnd,cooplevel);
454     if (TRACE_ON(ddraw))
455         _dump_cooperativelevel(cooplevel);
456     This->d.mainWindow = hwnd;
457
458     /* This will be overwritten in the case of Full Screen mode.
459        Windowed games could work with that :-) */
460     if (hwnd) {
461         WND *tmpWnd = WIN_FindWndPtr(hwnd);
462         ddpriv->drawable  = X11DRV_WND_GetXWindow(tmpWnd);
463         WIN_ReleaseWndPtr(tmpWnd);
464
465         if( !ddpriv->drawable ) {
466             ddpriv->drawable = ((X11DRV_WND_DATA *) WIN_GetDesktop()->pDriverData)->window;
467             WIN_ReleaseDesktop();
468         }
469         TRACE("Setting drawable to %ld\n", ddpriv->drawable);
470     }
471     return DD_OK;
472 }
473
474 static HRESULT WINAPI Xlib_IDirectDrawImpl_SetDisplayMode(
475     LPDIRECTDRAW iface,DWORD width,DWORD height,DWORD depth
476 ) {
477     ICOM_THIS(IDirectDrawImpl,iface);
478     DDPRIVATE(This);
479     char        buf[200];
480     WND *tmpWnd;
481     int c;
482
483     TRACE("(%p)->SetDisplayMode(%ld,%ld,%ld)\n",
484                   This, width, height, depth);
485
486     switch ((c = _common_depth_to_pixelformat(depth,
487                                          &(This->d.directdraw_pixelformat),
488                                          &(This->d.screen_pixelformat),
489                                               &(This->d.pixmap_depth)))) {
490     case -2:
491       sprintf(buf,"SetDisplayMode(w=%ld,h=%ld,d=%ld), unsupported depth!",width,height,depth);
492       MessageBoxA(0,buf,"WINE DirectDraw",MB_OK|MB_ICONSTOP);
493       return DDERR_UNSUPPORTEDMODE;
494
495     case -1:
496       /* No convertion */
497       This->d.pixel_convert = NULL;
498       This->d.palette_convert = NULL;
499       break;
500
501     default:
502       DPRINTF("DirectDraw warning: running in depth-convertion mode. Should run using a %ld depth for optimal performances.\n", depth);
503       /* Set the depth convertion routines */
504       This->d.pixel_convert = ModeEmulations[c].funcs.pixel_convert;
505       This->d.palette_convert = ModeEmulations[c].funcs.palette_convert;
506     }
507         
508     This->d.width       = width;
509     This->d.height      = height;
510
511     _common_IDirectDrawImpl_SetDisplayMode(This);
512
513     tmpWnd = WIN_FindWndPtr(This->d.window);
514     This->d.paintable = 1;
515     ddpriv->drawable  = ((X11DRV_WND_DATA *) tmpWnd->pDriverData)->window;
516     WIN_ReleaseWndPtr(tmpWnd);
517
518     /* We don't have a context for this window. Host off the desktop */
519     if( !ddpriv->drawable )
520     {
521        ddpriv->drawable = ((X11DRV_WND_DATA *) WIN_GetDesktop()->pDriverData)->window;
522         WIN_ReleaseDesktop();
523     }
524     TRACE("Setting drawable to %ld\n", ddpriv->drawable);
525
526     if (get_option( "DXGrab", 0 )) {
527         /* Confine cursor movement (risky, but the user asked for it) */
528         TSXGrabPointer(display, ddpriv->drawable, True, 0, GrabModeAsync, GrabModeAsync, ddpriv->drawable, None, CurrentTime);
529     }
530
531     return DD_OK;
532 }
533
534 static void fill_caps(LPDDCAPS caps) {
535   /* This function tries to fill the capabilities of Wine's DDraw implementation.
536      Need to be fixed, though.. */
537   if (caps == NULL)
538     return;
539
540   caps->dwSize = sizeof(*caps);
541   caps->dwCaps = DDCAPS_ALPHA | DDCAPS_BLT | DDCAPS_BLTSTRETCH | DDCAPS_BLTCOLORFILL | DDCAPS_BLTDEPTHFILL | DDCAPS_CANBLTSYSMEM |  DDCAPS_COLORKEY | DDCAPS_PALETTE /*| DDCAPS_NOHARDWARE*/;
542   caps->dwCaps2 = DDCAPS2_CERTIFIED | DDCAPS2_NOPAGELOCKREQUIRED | DDCAPS2_WIDESURFACES;
543   caps->dwCKeyCaps = 0xFFFFFFFF; /* Should put real caps here one day... */
544   caps->dwFXCaps = 0;
545   caps->dwFXAlphaCaps = 0;
546   caps->dwPalCaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256;
547   caps->dwSVCaps = 0;
548   caps->dwZBufferBitDepths = DDBD_16;
549   /* I put here 8 Mo so that D3D applications will believe they have enough memory
550      to put textures in video memory.
551      BTW, is this only frame buffer memory or also texture memory (for Voodoo boards
552      for example) ? */
553   caps->dwVidMemTotal = 8192 * 1024;
554   caps->dwVidMemFree = 8192 * 1024;
555   /* These are all the supported capabilities of the surfaces */
556   caps->ddsCaps.dwCaps = DDSCAPS_ALPHA | DDSCAPS_BACKBUFFER | DDSCAPS_COMPLEX | DDSCAPS_FLIP |
557     DDSCAPS_FRONTBUFFER | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_OFFSCREENPLAIN |
558       /*DDSCAPS_OVERLAY |*/ DDSCAPS_PALETTE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY |
559         DDSCAPS_VIDEOMEMORY | DDSCAPS_VISIBLE;
560 #ifdef HAVE_OPENGL
561   caps->dwCaps |= DDCAPS_3D | DDCAPS_ZBLTS;
562   caps->dwCaps2 |=  DDCAPS2_NO2DDURING3DSCENE;
563   caps->ddsCaps.dwCaps |= DDSCAPS_3DDEVICE | DDSCAPS_MIPMAP | DDSCAPS_TEXTURE | DDSCAPS_ZBUFFER;
564 #endif
565 }
566
567 static HRESULT WINAPI Xlib_IDirectDraw2Impl_GetCaps(
568     LPDIRECTDRAW2 iface,LPDDCAPS caps1,LPDDCAPS caps2
569 )  {
570     ICOM_THIS(IDirectDraw2Impl,iface);
571     TRACE("(%p)->GetCaps(%p,%p)\n",This,caps1,caps2);
572
573     /* Put the same caps for the two capabilities */
574     fill_caps(caps1);
575     fill_caps(caps2);
576
577     return DD_OK;
578 }
579
580 static HRESULT WINAPI Xlib_IDirectDraw2Impl_CreatePalette(
581     LPDIRECTDRAW2 iface,DWORD dwFlags,LPPALETTEENTRY palent,
582     LPDIRECTDRAWPALETTE *lpddpal,LPUNKNOWN lpunk
583 ) {
584     ICOM_THIS(IDirectDraw2Impl,iface);
585     IDirectDrawPaletteImpl** ilpddpal=(IDirectDrawPaletteImpl**)lpddpal;
586     int xsize;
587     HRESULT res;
588
589     TRACE("(%p)->(%08lx,%p,%p,%p)\n",This,dwFlags,palent,ilpddpal,lpunk);
590     res = common_IDirectDraw2Impl_CreatePalette(This,dwFlags,palent,ilpddpal,lpunk,&xsize);
591     if (res != 0)
592         return res;
593     (*ilpddpal)->private = HeapAlloc(
594         GetProcessHeap(),
595         HEAP_ZERO_MEMORY,
596         sizeof(x11_dp_private)
597     );
598     ICOM_VTBL(*ilpddpal) = &xlib_ddpalvt;
599     return DD_OK;
600 }
601
602 static ULONG WINAPI Xlib_IDirectDraw2Impl_Release(LPDIRECTDRAW2 iface) {
603     ICOM_THIS(IDirectDraw2Impl,iface);
604     TRACE("(%p)->() decrementing from %lu.\n", This, This->ref );
605
606     if (!--(This->ref)) {
607         if (This->d.window && GetPropA(This->d.window,ddProp))
608             DestroyWindow(This->d.window);
609         HeapFree(GetProcessHeap(),0,This);
610         return S_OK;
611     }
612     /* FIXME: destroy window ... */
613     return This->ref;
614 }
615
616 static HRESULT WINAPI Xlib_IDirectDraw2Impl_QueryInterface(
617     LPDIRECTDRAW2 iface,REFIID refiid,LPVOID *obj
618 ) {
619     ICOM_THIS(IDirectDraw2Impl,iface);
620
621     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
622     if ( IsEqualGUID( &IID_IUnknown, refiid ) ) {
623         *obj = This;
624         IDirectDraw2_AddRef(iface);
625
626         TRACE("  Creating IUnknown interface (%p)\n", *obj);
627         
628         return S_OK;
629     }
630     if ( IsEqualGUID( &IID_IDirectDraw, refiid ) ) {
631         ICOM_VTBL(This) = (ICOM_VTABLE(IDirectDraw2)*)&xlib_ddvt;
632         IDirectDraw2_AddRef(iface);
633         *obj = This;
634
635         TRACE("  Creating IDirectDraw interface (%p)\n", *obj);
636         
637         return S_OK;
638     }
639     if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) ) {
640         ICOM_VTBL(This) = (ICOM_VTABLE(IDirectDraw2)*)&xlib_dd2vt;
641         IDirectDraw2_AddRef(iface);
642         *obj = This;
643
644         TRACE("  Creating IDirectDraw2 interface (%p)\n", *obj);
645         
646         return S_OK;
647     }
648     if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) ) {
649         ICOM_VTBL(This) = (ICOM_VTABLE(IDirectDraw2)*)&xlib_dd4vt;
650         IDirectDraw2_AddRef(iface);
651         *obj = This;
652
653         TRACE("  Creating IDirectDraw4 interface (%p)\n", *obj);
654
655         return S_OK;
656     }
657 #ifdef HAVE_OPENGL
658     if ( IsEqualGUID( &IID_IDirect3D, refiid ) )
659         return create_direct3d(obj,This);
660     if ( IsEqualGUID( &IID_IDirect3D2, refiid ) )
661         return create_direct3d2(obj,This);
662     if ( IsEqualGUID( &IID_IDirect3D3, refiid ) ) 
663         return create_direct3d3(obj,This);
664 #endif
665     FIXME("(%p):interface for IID %s _NOT_ found!\n",This,debugstr_guid(refiid));
666     return OLE_E_ENUM_NOMORE;
667 }
668
669 static HRESULT WINAPI Xlib_IDirectDraw2Impl_EnumDisplayModes(
670     LPDIRECTDRAW2 iface,DWORD dwFlags,LPDDSURFACEDESC lpddsfd,LPVOID context,LPDDENUMMODESCALLBACK modescb
671 ) {
672   ICOM_THIS(IDirectDraw2Impl,iface);
673   XVisualInfo *vi;
674   XPixmapFormatValues *pf;
675   XVisualInfo vt;
676   int xbpp = 1, nvisuals, npixmap, i, emu;
677   int has_mode[]  = { 0,  0,  0,  0 };
678   int has_depth[] = { 8, 15, 16, 24 };
679   DDSURFACEDESC ddsfd;
680   static struct {
681         int w,h;
682   } modes[] = { /* some of the usual modes */
683         {512,384},
684         {640,400},
685         {640,480},
686         {800,600},
687         {1024,768},
688         {1280,1024}
689   };
690   DWORD maxWidth, maxHeight;
691
692   TRACE("(%p)->(0x%08lx,%p,%p,%p)\n",This,dwFlags,lpddsfd,context,modescb);
693   ddsfd.dwSize = sizeof(ddsfd);
694   ddsfd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_CAPS|DDSD_PITCH;
695   if (dwFlags & DDEDM_REFRESHRATES) {
696     ddsfd.dwFlags |= DDSD_REFRESHRATE;
697     ddsfd.u.dwRefreshRate = 60;
698   }
699   maxWidth = MONITOR_GetWidth(&MONITOR_PrimaryMonitor);
700   maxHeight = MONITOR_GetHeight(&MONITOR_PrimaryMonitor);
701   
702   vi = TSXGetVisualInfo(display, VisualNoMask, &vt, &nvisuals);
703   pf = TSXListPixmapFormats(display, &npixmap);
704
705   i = 0;
706   emu = 0;
707   while ((i < npixmap) || (emu != 4)) {
708     int mode_index = 0;
709     int send_mode = 0;
710     int j;
711
712     if (i < npixmap) {
713       for (j = 0; j < 4; j++) {
714         if (has_depth[j] == pf[i].depth) {
715           mode_index = j;
716           break;
717         }
718       }
719       if (j == 4) {
720         i++;
721         continue;
722       }
723       
724
725       if (has_mode[mode_index] == 0) {
726         if (mode_index == 0) {
727           send_mode = 1;
728
729           ddsfd.ddsCaps.dwCaps = DDSCAPS_PALETTE;
730           ddsfd.ddpfPixelFormat.dwSize = sizeof(ddsfd.ddpfPixelFormat);
731           ddsfd.ddpfPixelFormat.dwFlags = DDPF_RGB|DDPF_PALETTEINDEXED8;
732           ddsfd.ddpfPixelFormat.dwFourCC = 0;
733           ddsfd.ddpfPixelFormat.u.dwRGBBitCount = 8;
734           ddsfd.ddpfPixelFormat.u1.dwRBitMask = 0;
735           ddsfd.ddpfPixelFormat.u2.dwGBitMask = 0;
736           ddsfd.ddpfPixelFormat.u3.dwBBitMask = 0;
737           ddsfd.ddpfPixelFormat.u4.dwRGBAlphaBitMask= 0;
738
739           xbpp = 1;
740           
741           has_mode[mode_index] = 1;
742         } else {
743           /* All the 'true color' depths (15, 16 and 24)
744              First, find the corresponding visual to extract the bit masks */
745           for (j = 0; j < nvisuals; j++) {
746             if (vi[j].depth == pf[i].depth) {
747               ddsfd.ddsCaps.dwCaps = 0;
748               ddsfd.ddpfPixelFormat.dwSize = sizeof(ddsfd.ddpfPixelFormat);
749               ddsfd.ddpfPixelFormat.dwFlags = DDPF_RGB;
750               ddsfd.ddpfPixelFormat.dwFourCC = 0;
751               ddsfd.ddpfPixelFormat.u.dwRGBBitCount = pf[i].bits_per_pixel;
752               ddsfd.ddpfPixelFormat.u1.dwRBitMask = vi[j].red_mask;
753               ddsfd.ddpfPixelFormat.u2.dwGBitMask = vi[j].green_mask;
754               ddsfd.ddpfPixelFormat.u3.dwBBitMask = vi[j].blue_mask;
755               ddsfd.ddpfPixelFormat.u4.dwRGBAlphaBitMask= 0;
756
757               xbpp = pf[i].bits_per_pixel/8;
758
759               send_mode = 1;
760                   has_mode[mode_index] = 1;
761               break;
762             }
763           }
764           if (j == nvisuals)
765             WARN("Did not find visual corresponding the the pixmap format !\n");
766         }
767       }
768       i++;
769     } else {
770       /* Now to emulated modes */
771       if (has_mode[emu] == 0) {
772         int c;
773         int l;
774         int depth = has_depth[emu];
775       
776         for (c = 0; (c < sizeof(ModeEmulations) / sizeof(Convert)) && (send_mode == 0); c++) {
777           if (ModeEmulations[c].dest.depth == depth) {
778             /* Found an emulation function, now tries to find a matching visual / pixel format pair */
779             for (l = 0; (l < npixmap) && (send_mode == 0); l++) {
780               if ((pf[l].depth == ModeEmulations[c].screen.depth) &&
781                   (pf[l].bits_per_pixel == ModeEmulations[c].screen.bpp)) {
782                 int j;
783                 for (j = 0; (j < nvisuals) && (send_mode == 0); j++) {
784                   if ((vi[j].depth == pf[l].depth) &&
785                       (vi[j].red_mask == ModeEmulations[c].screen.rmask) &&
786                       (vi[j].green_mask == ModeEmulations[c].screen.gmask) &&
787                       (vi[j].blue_mask == ModeEmulations[c].screen.bmask)) {
788                     ddsfd.ddpfPixelFormat.dwSize = sizeof(ddsfd.ddpfPixelFormat);
789                     ddsfd.ddpfPixelFormat.dwFourCC = 0;
790                     if (depth == 8) {
791                       ddsfd.ddpfPixelFormat.dwFlags = DDPF_RGB|DDPF_PALETTEINDEXED8;
792                       ddsfd.ddpfPixelFormat.u.dwRGBBitCount = 8;
793                       ddsfd.ddpfPixelFormat.u1.dwRBitMask = 0;
794                       ddsfd.ddpfPixelFormat.u2.dwGBitMask = 0;
795                       ddsfd.ddpfPixelFormat.u3.dwBBitMask = 0;
796                     } else {
797                       ddsfd.ddpfPixelFormat.dwFlags = DDPF_RGB;
798                       ddsfd.ddpfPixelFormat.u.dwRGBBitCount = ModeEmulations[c].dest.bpp;
799                       ddsfd.ddpfPixelFormat.u1.dwRBitMask = ModeEmulations[c].dest.rmask;
800                       ddsfd.ddpfPixelFormat.u2.dwGBitMask = ModeEmulations[c].dest.gmask;
801                       ddsfd.ddpfPixelFormat.u3.dwBBitMask = ModeEmulations[c].dest.bmask;
802                     }
803                     ddsfd.ddpfPixelFormat.u4.dwRGBAlphaBitMask= 0;
804                     send_mode = 1;
805                   }
806                   
807                   if (send_mode == 0)
808                     WARN("No visual corresponding to pixmap format !\n");
809                 }
810               }
811             }
812           }
813         }
814       }
815
816       emu++;
817     }
818
819     if (send_mode) {
820       int mode;
821
822       if (TRACE_ON(ddraw)) {
823         TRACE("Enumerating with pixel format : \n");
824         _dump_pixelformat(&(ddsfd.ddpfPixelFormat));
825         DPRINTF("\n");
826       }
827       
828       for (mode = 0; mode < sizeof(modes)/sizeof(modes[0]); mode++) {
829         /* Do not enumerate modes we cannot handle anyway */
830         if ((modes[mode].w > maxWidth) || (modes[mode].h > maxHeight))
831           break;
832
833         ddsfd.dwWidth = modes[mode].w;
834         ddsfd.dwHeight= modes[mode].h;
835         ddsfd.lPitch  = ddsfd.dwWidth * xbpp;
836         
837         /* Now, send the mode description to the application */
838         TRACE(" - mode %4ld - %4ld\n", ddsfd.dwWidth, ddsfd.dwHeight);
839         if (!modescb(&ddsfd, context))
840           goto exit_enum;
841       }
842
843       if (!(dwFlags & DDEDM_STANDARDVGAMODES)) {
844         /* modeX is not standard VGA */
845         ddsfd.dwWidth = 320;
846         ddsfd.dwHeight = 200;
847         ddsfd.lPitch  = 320 * xbpp;
848         if (!modescb(&ddsfd, context))
849           goto exit_enum;
850       }
851     }
852   }
853  exit_enum:
854   TSXFree(vi);
855   TSXFree(pf);
856
857   return DD_OK;
858 }
859
860 static HRESULT WINAPI Xlib_IDirectDraw2Impl_GetDisplayMode(
861     LPDIRECTDRAW2 iface,LPDDSURFACEDESC lpddsfd
862 ) {
863     ICOM_THIS(IDirectDraw2Impl,iface);
864     TRACE("(%p)->GetDisplayMode(%p)\n",This,lpddsfd);
865     lpddsfd->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_BACKBUFFERCOUNT|DDSD_PIXELFORMAT|DDSD_CAPS;
866     lpddsfd->dwHeight = This->d.height;
867     lpddsfd->dwWidth = This->d.width;
868     lpddsfd->lPitch = lpddsfd->dwWidth * PFGET_BPP(This->d.directdraw_pixelformat);
869     lpddsfd->dwBackBufferCount = 2;
870     lpddsfd->u.dwRefreshRate = 60;
871     lpddsfd->ddsCaps.dwCaps = DDSCAPS_PALETTE;
872     lpddsfd->ddpfPixelFormat = This->d.directdraw_pixelformat;
873     if (TRACE_ON(ddraw))
874         _dump_surface_desc(lpddsfd);
875     return DD_OK;
876 }
877
878 /* Note: Hack so we can reuse the old functions without compiler warnings */
879 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
880 # define XCAST(fun)     (typeof(xlib_ddvt.fn##fun))
881 #else
882 # define XCAST(fun)     (void *)
883 #endif
884
885 ICOM_VTABLE(IDirectDraw) xlib_ddvt = {
886     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
887     XCAST(QueryInterface)Xlib_IDirectDraw2Impl_QueryInterface,
888     XCAST(AddRef)IDirectDraw2Impl_AddRef,
889     XCAST(Release)Xlib_IDirectDraw2Impl_Release,
890     XCAST(Compact)IDirectDraw2Impl_Compact,
891     XCAST(CreateClipper)IDirectDraw2Impl_CreateClipper,
892     XCAST(CreatePalette)Xlib_IDirectDraw2Impl_CreatePalette,
893     XCAST(CreateSurface)Xlib_IDirectDraw2Impl_CreateSurface,
894     XCAST(DuplicateSurface)IDirectDraw2Impl_DuplicateSurface,
895     XCAST(EnumDisplayModes)Xlib_IDirectDraw2Impl_EnumDisplayModes,
896     XCAST(EnumSurfaces)IDirectDraw2Impl_EnumSurfaces,
897     XCAST(FlipToGDISurface)IDirectDraw2Impl_FlipToGDISurface,
898     XCAST(GetCaps)Xlib_IDirectDraw2Impl_GetCaps,
899     XCAST(GetDisplayMode)Xlib_IDirectDraw2Impl_GetDisplayMode,
900     XCAST(GetFourCCCodes)IDirectDraw2Impl_GetFourCCCodes,
901     XCAST(GetGDISurface)IDirectDraw2Impl_GetGDISurface,
902     XCAST(GetMonitorFrequency)IDirectDraw2Impl_GetMonitorFrequency,
903     XCAST(GetScanLine)IDirectDraw2Impl_GetScanLine,
904     XCAST(GetVerticalBlankStatus)IDirectDraw2Impl_GetVerticalBlankStatus,
905     XCAST(Initialize)IDirectDraw2Impl_Initialize,
906     XCAST(RestoreDisplayMode)IDirectDraw2Impl_RestoreDisplayMode,
907     XCAST(SetCooperativeLevel)Xlib_IDirectDraw2Impl_SetCooperativeLevel,
908     Xlib_IDirectDrawImpl_SetDisplayMode,
909     XCAST(WaitForVerticalBlank)IDirectDraw2Impl_WaitForVerticalBlank,
910 };
911
912 #undef XCAST
913
914 /*****************************************************************************
915  *      IDirectDraw2
916  *
917  */
918
919 static HRESULT WINAPI Xlib_IDirectDraw2Impl_SetDisplayMode(
920     LPDIRECTDRAW2 iface,DWORD width,DWORD height,DWORD depth,DWORD dwRefreshRate,DWORD dwFlags
921 ) {
922     FIXME( "Ignored parameters (0x%08lx,0x%08lx)\n", dwRefreshRate, dwFlags ); 
923     return Xlib_IDirectDrawImpl_SetDisplayMode((LPDIRECTDRAW)iface,width,height,depth);
924 }
925
926 static HRESULT WINAPI Xlib_IDirectDraw2Impl_GetAvailableVidMem(
927     LPDIRECTDRAW2 iface,LPDDSCAPS ddscaps,LPDWORD total,LPDWORD free
928 ) {
929     ICOM_THIS(IDirectDraw2Impl,iface);
930     TRACE("(%p)->(%p,%p,%p)\n",This,ddscaps,total,free);
931     if (total) *total = 16* 1024 * 1024;
932     if (free) *free = 16* 1024 * 1024;
933     return DD_OK;
934 }
935
936 ICOM_VTABLE(IDirectDraw2) xlib_dd2vt = {
937     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
938     Xlib_IDirectDraw2Impl_QueryInterface,
939     IDirectDraw2Impl_AddRef,
940     Xlib_IDirectDraw2Impl_Release,
941     IDirectDraw2Impl_Compact,
942     IDirectDraw2Impl_CreateClipper,
943     Xlib_IDirectDraw2Impl_CreatePalette,
944     Xlib_IDirectDraw2Impl_CreateSurface,
945     IDirectDraw2Impl_DuplicateSurface,
946     Xlib_IDirectDraw2Impl_EnumDisplayModes,
947     IDirectDraw2Impl_EnumSurfaces,
948     IDirectDraw2Impl_FlipToGDISurface,
949     Xlib_IDirectDraw2Impl_GetCaps,
950     Xlib_IDirectDraw2Impl_GetDisplayMode,
951     IDirectDraw2Impl_GetFourCCCodes,
952     IDirectDraw2Impl_GetGDISurface,
953     IDirectDraw2Impl_GetMonitorFrequency,
954     IDirectDraw2Impl_GetScanLine,
955     IDirectDraw2Impl_GetVerticalBlankStatus,
956     IDirectDraw2Impl_Initialize,
957     IDirectDraw2Impl_RestoreDisplayMode,
958     Xlib_IDirectDraw2Impl_SetCooperativeLevel,
959     Xlib_IDirectDraw2Impl_SetDisplayMode,
960     IDirectDraw2Impl_WaitForVerticalBlank,
961     Xlib_IDirectDraw2Impl_GetAvailableVidMem    
962 };
963
964 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
965 # define XCAST(fun)     (typeof(xlib_dd4vt.fn##fun))
966 #else
967 # define XCAST(fun)     (void*)
968 #endif
969
970 ICOM_VTABLE(IDirectDraw4) xlib_dd4vt = {
971     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
972     XCAST(QueryInterface)Xlib_IDirectDraw2Impl_QueryInterface,
973     XCAST(AddRef)IDirectDraw2Impl_AddRef,
974     XCAST(Release)Xlib_IDirectDraw2Impl_Release,
975     XCAST(Compact)IDirectDraw2Impl_Compact,
976     XCAST(CreateClipper)IDirectDraw2Impl_CreateClipper,
977     XCAST(CreatePalette)Xlib_IDirectDraw2Impl_CreatePalette,
978     XCAST(CreateSurface)Xlib_IDirectDraw2Impl_CreateSurface,
979     XCAST(DuplicateSurface)IDirectDraw2Impl_DuplicateSurface,
980     XCAST(EnumDisplayModes)Xlib_IDirectDraw2Impl_EnumDisplayModes,
981     XCAST(EnumSurfaces)IDirectDraw2Impl_EnumSurfaces,
982     XCAST(FlipToGDISurface)IDirectDraw2Impl_FlipToGDISurface,
983     XCAST(GetCaps)Xlib_IDirectDraw2Impl_GetCaps,
984     XCAST(GetDisplayMode)Xlib_IDirectDraw2Impl_GetDisplayMode,
985     XCAST(GetFourCCCodes)IDirectDraw2Impl_GetFourCCCodes,
986     XCAST(GetGDISurface)IDirectDraw2Impl_GetGDISurface,
987     XCAST(GetMonitorFrequency)IDirectDraw2Impl_GetMonitorFrequency,
988     XCAST(GetScanLine)IDirectDraw2Impl_GetScanLine,
989     XCAST(GetVerticalBlankStatus)IDirectDraw2Impl_GetVerticalBlankStatus,
990     XCAST(Initialize)IDirectDraw2Impl_Initialize,
991     XCAST(RestoreDisplayMode)IDirectDraw2Impl_RestoreDisplayMode,
992     XCAST(SetCooperativeLevel)Xlib_IDirectDraw2Impl_SetCooperativeLevel,
993     XCAST(SetDisplayMode)Xlib_IDirectDrawImpl_SetDisplayMode,
994     XCAST(WaitForVerticalBlank)IDirectDraw2Impl_WaitForVerticalBlank,
995     XCAST(GetAvailableVidMem)Xlib_IDirectDraw2Impl_GetAvailableVidMem,
996     IDirectDraw4Impl_GetSurfaceFromDC,
997     IDirectDraw4Impl_RestoreAllSurfaces,
998     IDirectDraw4Impl_TestCooperativeLevel,
999     IDirectDraw4Impl_GetDeviceIdentifier
1000 };
1001 #undef XCAST