Fixed error handling in DGA_IDirectDraw2Impl_GetCaps().
[wine] / graphics / x11drv / bitmap.c
1 /*
2  * X11DRV bitmap objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #ifndef X_DISPLAY_MISSING
10
11 #include "ts_xlib.h"
12 #include "ts_xutil.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include "gdi.h"
17 #include "callback.h"
18 #include "dc.h"
19 #include "bitmap.h"
20 #include "heap.h"
21 #include "monitor.h"
22 #include "debug.h"
23 #include "xmalloc.h"
24 #include "local.h"
25 #include "x11drv.h"
26 #include "wine/winuser16.h"
27
28 DEFAULT_DEBUG_CHANNEL(x11drv)
29
30   /* GCs used for B&W and color bitmap operations */
31 GC BITMAP_monoGC = 0, BITMAP_colorGC = 0;
32
33
34 /***********************************************************************
35  *           X11DRV_BITMAP_Init
36  */
37 BOOL X11DRV_BITMAP_Init(void)
38 {
39     Pixmap tmpPixmap;
40     
41       /* Create the necessary GCs */
42     
43     if ((tmpPixmap = TSXCreatePixmap(display, 
44                                      X11DRV_GetXRootWindow(), 
45                                      1, 1, 
46                                      1)))
47     {
48         BITMAP_monoGC = TSXCreateGC( display, tmpPixmap, 0, NULL );
49         TSXSetGraphicsExposures( display, BITMAP_monoGC, False );
50         TSXFreePixmap( display, tmpPixmap );
51     }
52
53     if (MONITOR_GetDepth(&MONITOR_PrimaryMonitor) != 1)
54     {
55         if ((tmpPixmap = TSXCreatePixmap(display, 
56                                          X11DRV_GetXRootWindow(),
57                                          1, 1,
58                                          MONITOR_GetDepth(&MONITOR_PrimaryMonitor))))
59         {
60             BITMAP_colorGC = TSXCreateGC( display, tmpPixmap, 0, NULL );
61             TSXSetGraphicsExposures( display, BITMAP_colorGC, False );
62             TSXFreePixmap( display, tmpPixmap );
63         }
64     }
65     return TRUE;
66 }
67
68 /***********************************************************************
69  *           X11DRV_BITMAP_SelectObject
70  */
71 HBITMAP X11DRV_BITMAP_SelectObject( DC * dc, HBITMAP hbitmap,
72                                       BITMAPOBJ * bmp )
73 {
74     HRGN hrgn;
75     HBITMAP prevHandle = dc->w.hBitmap;
76     X11DRV_PHYSBITMAP *pbitmap;
77     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
78
79
80     if (!(dc->w.flags & DC_MEMORY)) return 0;
81
82     if(!bmp->DDBitmap)
83         if(!X11DRV_CreateBitmap(hbitmap))
84             return 0;
85
86     if(bmp->DDBitmap->funcs != dc->funcs) {
87         WARN(x11drv, "Trying to select non-X11 DDB into an X11 dc\n");
88         return 0;
89     }
90
91     pbitmap = bmp->DDBitmap->physBitmap;
92
93     dc->w.totalExtent.left   = 0;
94     dc->w.totalExtent.top    = 0;
95     dc->w.totalExtent.right  = bmp->bitmap.bmWidth;
96     dc->w.totalExtent.bottom = bmp->bitmap.bmHeight;
97
98     if (dc->w.hVisRgn)
99        SetRectRgn( dc->w.hVisRgn, 0, 0,
100                      bmp->bitmap.bmWidth, bmp->bitmap.bmHeight );
101     else
102     { 
103        hrgn = CreateRectRgn(0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight);
104        if (!hrgn) return 0;
105        dc->w.hVisRgn    = hrgn;
106     }
107
108     physDev->drawable = pbitmap->pixmap;
109     dc->w.hBitmap     = hbitmap;
110
111       /* Change GC depth if needed */
112
113     if (dc->w.bitsPerPixel != bmp->bitmap.bmBitsPixel)
114     {
115         TSXFreeGC( display, physDev->gc );
116         physDev->gc = TSXCreateGC( display, physDev->drawable, 0, NULL );
117         TSXSetGraphicsExposures( display, physDev->gc, False );
118         dc->w.bitsPerPixel = bmp->bitmap.bmBitsPixel;
119         DC_InitDC( dc );
120     }
121     else CLIPPING_UpdateGCRegion( dc );  /* Just update GC clip region */
122     return prevHandle;
123 }
124
125
126 /***********************************************************************
127  *           XPutImage_wrapper
128  *
129  * Wrapper to call XPutImage with CALL_LARGE_STACK.
130  */
131
132 struct XPutImage_descr
133 {
134     BITMAPOBJ *bmp;
135     XImage    *image;
136     INT      width;
137     INT      height;
138 };
139
140 static int XPutImage_wrapper( const struct XPutImage_descr *descr )
141 {
142     return XPutImage( display,
143                ((X11DRV_PHYSBITMAP *)descr->bmp->DDBitmap->physBitmap)->pixmap,
144                BITMAP_GC(descr->bmp),
145                descr->image, 0, 0, 0, 0, descr->width, descr->height );
146 }
147
148
149 /***************************************************************************
150  *
151  *      X11DRV_AllocBitmap
152  *
153  * Allocate DDBitmap and physBitmap
154  *
155  */
156 X11DRV_PHYSBITMAP *X11DRV_AllocBitmap( BITMAPOBJ *bmp )
157 {
158     X11DRV_PHYSBITMAP *pbitmap;
159
160     if(!(bmp->DDBitmap = HeapAlloc(GetProcessHeap(), 0, sizeof(DDBITMAP)))) {
161         WARN(x11drv, "Can't alloc DDBITMAP\n");
162         return NULL;
163     }
164
165     if(!(pbitmap = HeapAlloc(GetProcessHeap(), 0,sizeof(X11DRV_PHYSBITMAP)))) {
166         WARN(x11drv, "Can't alloc X11DRV_PHYSBITMAP\n");
167         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap);
168         return NULL;
169     }
170
171     bmp->DDBitmap->physBitmap = pbitmap;
172     bmp->DDBitmap->funcs = DRIVER_FindDriver( "DISPLAY" );
173     return pbitmap;
174 }
175
176
177 /****************************************************************************
178  *
179  *        X11DRV_CreateBitmap
180  *
181  * Create a device dependent X11 bitmap
182  *
183  * Returns TRUE on success else FALSE
184  *
185  */
186
187 BOOL X11DRV_CreateBitmap( HBITMAP hbitmap )
188 {
189     X11DRV_PHYSBITMAP *pbitmap;
190     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
191
192     if(!bmp) {
193         WARN(x11drv, "Bad bitmap handle %08x\n", hbitmap);
194         return FALSE;
195     }
196
197       /* Check parameters */
198     if (bmp->bitmap.bmPlanes != 1) return 0;
199     if ((bmp->bitmap.bmBitsPixel != 1) && 
200         (bmp->bitmap.bmBitsPixel != MONITOR_GetDepth(&MONITOR_PrimaryMonitor))) {
201         ERR(x11drv, "Trying to make bitmap with planes=%d, bpp=%d\n",
202             bmp->bitmap.bmPlanes, bmp->bitmap.bmBitsPixel);
203         GDI_HEAP_UNLOCK( hbitmap );
204         return FALSE;
205     }
206
207     TRACE(x11drv, "(%08x) %dx%d %d bpp\n", hbitmap, bmp->bitmap.bmWidth,
208           bmp->bitmap.bmHeight, bmp->bitmap.bmBitsPixel);
209
210     pbitmap = X11DRV_AllocBitmap( bmp );
211     if(!pbitmap) return FALSE;
212
213       /* Create the pixmap */
214     pbitmap->pixmap = TSXCreatePixmap(display, X11DRV_GetXRootWindow(), bmp->bitmap.bmWidth,
215                               bmp->bitmap.bmHeight, bmp->bitmap.bmBitsPixel);
216     if (!pbitmap->pixmap) {
217         WARN(x11drv, "Can't create Pixmap\n");
218         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap->physBitmap);
219         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap);
220         GDI_HEAP_UNLOCK( hbitmap );
221         return FALSE;
222     }
223
224     if (bmp->bitmap.bmBits) /* Set bitmap bits */
225         X11DRV_BitmapBits( hbitmap, bmp->bitmap.bmBits,
226                            bmp->bitmap.bmHeight * bmp->bitmap.bmWidthBytes,
227                            DDB_SET );
228
229     GDI_HEAP_UNLOCK( hbitmap );
230     return TRUE;
231 }
232
233
234 /***********************************************************************
235  *           X11DRV_BITMAP_GetXImage
236  *
237  * Get an X image for a bitmap. For use with CALL_LARGE_STACK.
238  */
239 XImage *X11DRV_BITMAP_GetXImage( const BITMAPOBJ *bmp )
240 {
241     return XGetImage( display,
242                       ((X11DRV_PHYSBITMAP *)bmp->DDBitmap->physBitmap)->pixmap,
243                       0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
244                       AllPlanes, ZPixmap );
245 }
246
247
248 /***********************************************************************
249  *           X11DRV_GetBitmapBits
250  * 
251  * RETURNS
252  *    Success: Number of bytes copied
253  *    Failure: 0
254  */
255 static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count)
256 {
257     LONG old_height, height;
258     XImage *image;
259     LPBYTE tbuf, startline;
260     int h, w;
261
262     TRACE(x11drv, "(bmp=%p, buffer=%p, count=0x%lx)\n", bmp, buffer, count);
263
264     EnterCriticalSection( &X11DRV_CritSection );
265
266     /* Hack: change the bitmap height temporarily to avoid */
267     /*       getting unnecessary bitmap rows. */
268
269     old_height = bmp->bitmap.bmHeight;
270     height = bmp->bitmap.bmHeight = count / bmp->bitmap.bmWidthBytes;
271
272     image = (XImage *)CALL_LARGE_STACK( X11DRV_BITMAP_GetXImage, bmp );
273
274     bmp->bitmap.bmHeight = old_height;
275
276     /* copy XImage to 16 bit padded image buffer with real bitsperpixel */
277
278     startline = buffer;
279     switch (bmp->bitmap.bmBitsPixel)
280     {
281     case 1:
282         for (h=0;h<height;h++)
283         {
284             tbuf = startline;
285             *tbuf = 0;
286             for (w=0;w<bmp->bitmap.bmWidth;w++)
287             {
288                 if ((w%8) == 0)
289                     *tbuf = 0;
290                 *tbuf |= XGetPixel(image,w,h)<<(7-(w&7));
291                 if ((w&7) == 7) ++tbuf;
292             }
293             startline += bmp->bitmap.bmWidthBytes;
294         }
295         break;
296     case 4:
297         for (h=0;h<height;h++)
298         {
299             tbuf = startline;
300             for (w=0;w<bmp->bitmap.bmWidth;w++)
301             {
302                 if (!(w & 1)) *tbuf = XGetPixel( image, w, h) << 4;
303                 else *tbuf++ |= XGetPixel( image, w, h) & 0x0f;
304             }
305             startline += bmp->bitmap.bmWidthBytes;
306         }
307         break;
308     case 8:
309         for (h=0;h<height;h++)
310         {
311             tbuf = startline;
312             for (w=0;w<bmp->bitmap.bmWidth;w++)
313                 *tbuf++ = XGetPixel(image,w,h);
314             startline += bmp->bitmap.bmWidthBytes;
315         }
316         break;
317     case 15:
318     case 16:
319         for (h=0;h<height;h++)
320         {
321             tbuf = startline;
322             for (w=0;w<bmp->bitmap.bmWidth;w++)
323             {
324                 long pixel = XGetPixel(image,w,h);
325
326                 *tbuf++ = pixel & 0xff;
327                 *tbuf++ = (pixel>>8) & 0xff;
328             }
329             startline += bmp->bitmap.bmWidthBytes;
330         }
331         break;
332     case 24:
333         for (h=0;h<height;h++)
334         {
335             tbuf = startline;
336             for (w=0;w<bmp->bitmap.bmWidth;w++)
337             {
338                 long pixel = XGetPixel(image,w,h);
339
340                 *tbuf++ = pixel & 0xff;
341                 *tbuf++ = (pixel>> 8) & 0xff;
342                 *tbuf++ = (pixel>>16) & 0xff;
343             }
344             startline += bmp->bitmap.bmWidthBytes;
345         }
346         break;
347
348     case 32:
349         for (h=0;h<height;h++)
350         {
351             tbuf = startline;
352             for (w=0;w<bmp->bitmap.bmWidth;w++)
353             {
354                 long pixel = XGetPixel(image,w,h);
355
356                 *tbuf++ = pixel & 0xff;
357                 *tbuf++ = (pixel>> 8) & 0xff;
358                 *tbuf++ = (pixel>>16) & 0xff;
359                 *tbuf++ = (pixel>>24) & 0xff;
360             }
361             startline += bmp->bitmap.bmWidthBytes;
362         }
363         break;
364     default:
365         FIXME(x11drv, "Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel);
366     }
367     XDestroyImage( image );
368     LeaveCriticalSection( &X11DRV_CritSection );
369
370     return count;
371 }
372
373
374
375 /******************************************************************************
376  *             X11DRV_SetBitmapBits
377  *
378  * RETURNS
379  *    Success: Number of bytes used in setting the bitmap bits
380  *    Failure: 0
381  */
382 static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count)
383 {
384     struct XPutImage_descr descr;
385     LONG height;
386     XImage *image;
387     LPBYTE sbuf, startline;
388     int w, h;
389
390     TRACE(x11drv, "(bmp=%p, bits=%p, count=0x%lx)\n", bmp, bits, count);
391     
392     height = count / bmp->bitmap.bmWidthBytes;
393
394     EnterCriticalSection( &X11DRV_CritSection );
395     image = XCreateImage( display, DefaultVisualOfScreen(X11DRV_GetXScreen()),
396                           bmp->bitmap.bmBitsPixel, ZPixmap, 0, NULL,
397                           bmp->bitmap.bmWidth, height, 32, 0 );
398     image->data = (LPBYTE)xmalloc(image->bytes_per_line * height);
399     
400     /* copy 16 bit padded image buffer with real bitsperpixel to XImage */
401     
402     startline = bits;
403
404     switch (bmp->bitmap.bmBitsPixel)
405     {
406     case 1:
407         for (h=0;h<height;h++)
408         {
409             sbuf = startline;
410             for (w=0;w<bmp->bitmap.bmWidth;w++)
411             {
412                 XPutPixel(image,w,h,(sbuf[0]>>(7-(w&7))) & 1);
413                 if ((w&7) == 7)
414                     sbuf++;
415             }
416             startline += bmp->bitmap.bmWidthBytes;
417         }
418         break;
419     case 4:
420         for (h=0;h<height;h++)
421         {
422             sbuf = startline;
423             for (w=0;w<bmp->bitmap.bmWidth;w++)
424             {
425                 if (!(w & 1)) XPutPixel( image, w, h, *sbuf >> 4 );
426                 else XPutPixel( image, w, h, *sbuf++ & 0xf );
427             }
428             startline += bmp->bitmap.bmWidthBytes;
429         }
430         break;
431     case 8:
432         for (h=0;h<height;h++)
433         {
434             sbuf = startline;
435             for (w=0;w<bmp->bitmap.bmWidth;w++)
436                 XPutPixel(image,w,h,*sbuf++);
437             startline += bmp->bitmap.bmWidthBytes;
438         }
439         break;
440     case 15:
441     case 16:
442         for (h=0;h<height;h++)
443         {
444             sbuf = startline;
445             for (w=0;w<bmp->bitmap.bmWidth;w++)
446             {
447                 XPutPixel(image,w,h,sbuf[1]*256+sbuf[0]);
448                 sbuf+=2;
449             }
450             startline += bmp->bitmap.bmWidthBytes;
451         }
452         break;
453     case 24:
454         for (h=0;h<height;h++)
455         {
456             sbuf = startline;
457             for (w=0;w<bmp->bitmap.bmWidth;w++)
458             {
459                 XPutPixel(image,w,h,(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
460                 sbuf += 3;
461             }
462             startline += bmp->bitmap.bmWidthBytes;
463         }
464         break;
465     case 32: 
466         for (h=0;h<height;h++)
467         {
468             sbuf = startline;
469             for (w=0;w<bmp->bitmap.bmWidth;w++)
470             {
471                 XPutPixel(image,w,h,(sbuf[3]<<24)+(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
472                 sbuf += 4;
473             }
474             startline += bmp->bitmap.bmWidthBytes;
475         }
476         break;
477     default:
478       FIXME(x11drv, "Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel);
479
480     }
481
482     descr.bmp    = bmp;
483     descr.image  = image;
484     descr.width  = bmp->bitmap.bmWidth;
485     descr.height = height;
486
487     CALL_LARGE_STACK( XPutImage_wrapper, &descr );
488     XDestroyImage( image ); /* frees image->data too */
489     LeaveCriticalSection( &X11DRV_CritSection );
490     
491     return count;
492 }
493
494 /***********************************************************************
495  *           X11DRV_BitmapBits
496  */
497 LONG X11DRV_BitmapBits(HBITMAP hbitmap, void *bits, LONG count, WORD flags)
498 {
499     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
500     LONG ret;
501     if(!bmp) {
502         WARN(x11drv, "Bad bitmap handle %08x\n", hbitmap);
503         return FALSE;
504     }
505
506     if(flags == DDB_GET)
507         ret = X11DRV_GetBitmapBits(bmp, bits, count);
508     else if(flags == DDB_SET)
509         ret = X11DRV_SetBitmapBits(bmp, bits, count);
510     else {
511         ERR(x11drv, "Unknown flags value %d\n", flags);
512         ret = 0;
513     }
514     
515     GDI_HEAP_UNLOCK( hbitmap );
516     return ret;
517 }
518
519 /***********************************************************************
520  *           X11DRV_BITMAP_DeleteObject
521  */
522 BOOL X11DRV_BITMAP_DeleteObject( HBITMAP hbitmap, BITMAPOBJ * bmp )
523 {
524     X11DRV_PHYSBITMAP *pbitmap = bmp->DDBitmap->physBitmap;
525
526     TSXFreePixmap( display, pbitmap->pixmap );
527
528     HeapFree( GetProcessHeap(), 0, bmp->DDBitmap->physBitmap );
529     HeapFree( GetProcessHeap(), 0, bmp->DDBitmap );
530     bmp->DDBitmap = NULL;
531
532     return TRUE;
533 }
534
535 /***********************************************************************
536  *           X11DRV_BITMAP_Pixmap
537  *
538  * This function exists solely for x11 driver of the window system.
539  */
540 BOOL X11DRV_BITMAP_Pixmap(HBITMAP hbitmap)
541 {
542     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
543     return ((X11DRV_PHYSBITMAP *)(bmp->DDBitmap->physBitmap))->pixmap;
544 }
545
546 #endif /* !defined(X_DISPLAY_MISSING) */