ddraw: Fix stupid bug when setting surface client memory.
[wine] / dlls / winex11.drv / bitmap.c
1 /*
2  * X11DRV bitmap objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1999 Noel Borthwick
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include "windef.h"
27 #include "wingdi.h"
28 #include "wine/debug.h"
29 #include "x11drv.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
32
33   /* GCs used for B&W and color bitmap operations */
34 GC BITMAP_monoGC = 0, BITMAP_colorGC = 0;
35 X_PHYSBITMAP BITMAP_stock_phys_bitmap = { 0 };  /* phys bitmap for the default stock bitmap */
36
37 static XContext bitmap_context;  /* X context to associate a phys bitmap to a handle */
38
39 /***********************************************************************
40  *           X11DRV_BITMAP_Init
41  */
42 void X11DRV_BITMAP_Init(void)
43 {
44     Pixmap tmpPixmap;
45
46       /* Create the necessary GCs */
47
48     wine_tsx11_lock();
49     bitmap_context = XUniqueContext();
50     BITMAP_stock_phys_bitmap.pixmap_depth = 1;
51     BITMAP_stock_phys_bitmap.pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 1 );
52     BITMAP_monoGC = XCreateGC( gdi_display, BITMAP_stock_phys_bitmap.pixmap, 0, NULL );
53     XSetGraphicsExposures( gdi_display, BITMAP_monoGC, False );
54     XSetSubwindowMode( gdi_display, BITMAP_monoGC, IncludeInferiors );
55
56     if (screen_depth != 1)
57     {
58         if ((tmpPixmap = XCreatePixmap( gdi_display, root_window, 1, 1, screen_depth )))
59         {
60             BITMAP_colorGC = XCreateGC( gdi_display, tmpPixmap, 0, NULL );
61             XSetGraphicsExposures( gdi_display, BITMAP_colorGC, False );
62             XSetSubwindowMode( gdi_display, BITMAP_colorGC, IncludeInferiors );
63             XFreePixmap( gdi_display, tmpPixmap );
64         }
65     }
66     wine_tsx11_unlock();
67 }
68
69 /***********************************************************************
70  *           SelectBitmap   (X11DRV.@)
71  */
72 HBITMAP X11DRV_SelectBitmap( X11DRV_PDEVICE *physDev, HBITMAP hbitmap )
73 {
74     X_PHYSBITMAP *physBitmap;
75     BITMAP bitmap;
76
77     if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return 0;
78
79     if(physDev->xrender)
80         X11DRV_XRender_UpdateDrawable( physDev );
81
82     if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap) physBitmap = &BITMAP_stock_phys_bitmap;
83     else if (!(physBitmap = X11DRV_get_phys_bitmap( hbitmap ))) return 0;
84
85     physDev->bitmap = physBitmap;
86     physDev->drawable = physBitmap->pixmap;
87     SetRect( &physDev->drawable_rect, 0, 0, bitmap.bmWidth, bitmap.bmHeight );
88     physDev->dc_rect = physDev->drawable_rect;
89
90       /* Change GC depth if needed */
91
92     if (physDev->depth != physBitmap->pixmap_depth)
93     {
94         physDev->depth = physBitmap->pixmap_depth;
95         wine_tsx11_lock();
96         XFreeGC( gdi_display, physDev->gc );
97         physDev->gc = XCreateGC( gdi_display, physDev->drawable, 0, NULL );
98         XSetGraphicsExposures( gdi_display, physDev->gc, False );
99         XSetSubwindowMode( gdi_display, physDev->gc, IncludeInferiors );
100         XFlush( gdi_display );
101         wine_tsx11_unlock();
102     }
103     return hbitmap;
104 }
105
106
107 /****************************************************************************
108  *        CreateBitmap   (X11DRV.@)
109  *
110  * Create a device dependent X11 bitmap
111  *
112  * Returns TRUE on success else FALSE
113  */
114 BOOL X11DRV_CreateBitmap( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, LPVOID bmBits )
115 {
116     X_PHYSBITMAP *physBitmap;
117     BITMAP bitmap;
118
119     if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
120
121       /* Check parameters */
122     if (bitmap.bmPlanes != 1) return FALSE;
123
124     /* check if bpp is compatible with screen depth */
125     if (!((bitmap.bmBitsPixel == 1) ||
126           (bitmap.bmBitsPixel == screen_depth) ||
127           (bitmap.bmBitsPixel == 24 && screen_depth == 32) ||
128           (bitmap.bmBitsPixel == 32 && screen_depth == 24) ||
129           (bitmap.bmBitsPixel == 15 && screen_depth == 16) ||
130           (bitmap.bmBitsPixel == 16 && screen_depth == 15)))
131     {
132         ERR("Trying to make bitmap with planes=%d, bpp=%d\n",
133             bitmap.bmPlanes, bitmap.bmBitsPixel);
134         return FALSE;
135     }
136     if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap)
137     {
138         ERR( "called for stock bitmap, please report\n" );
139         return FALSE;
140     }
141
142     TRACE("(%p) %dx%d %d bpp\n", hbitmap, bitmap.bmWidth, bitmap.bmHeight, bitmap.bmBitsPixel);
143
144     if (!(physBitmap = X11DRV_init_phys_bitmap( hbitmap ))) return FALSE;
145
146       /* Create the pixmap */
147     wine_tsx11_lock();
148     physBitmap->pixmap_depth = (bitmap.bmBitsPixel == 1) ? 1 : screen_depth;
149     physBitmap->pixmap = XCreatePixmap(gdi_display, root_window,
150                                        bitmap.bmWidth, bitmap.bmHeight, physBitmap->pixmap_depth);
151     wine_tsx11_unlock();
152     if (!physBitmap->pixmap)
153     {
154         WARN("Can't create Pixmap\n");
155         HeapFree( GetProcessHeap(), 0, physBitmap );
156         return FALSE;
157     }
158
159     if (bmBits) /* Set bitmap bits */
160     {
161         X11DRV_SetBitmapBits( hbitmap, bmBits, bitmap.bmHeight * bitmap.bmWidthBytes );
162     }
163     else  /* else clear the bitmap */
164     {
165         wine_tsx11_lock();
166         XSetFunction( gdi_display, BITMAP_GC(physBitmap), GXclear );
167         XFillRectangle( gdi_display, physBitmap->pixmap, BITMAP_GC(physBitmap), 0, 0,
168                         bitmap.bmWidth, bitmap.bmHeight );
169         XSetFunction( gdi_display, BITMAP_GC(physBitmap), GXcopy );
170         wine_tsx11_unlock();
171     }
172     return TRUE;
173 }
174
175
176 /***********************************************************************
177  *           GetBitmapBits   (X11DRV.@)
178  *
179  * RETURNS
180  *    Success: Number of bytes copied
181  *    Failure: 0
182  */
183 LONG X11DRV_GetBitmapBits( HBITMAP hbitmap, void *buffer, LONG count )
184 {
185     BITMAP bitmap;
186     X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
187     LONG height;
188     XImage *image;
189     LPBYTE tbuf, startline;
190     int h, w;
191
192     if (!physBitmap || !GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return 0;
193
194     TRACE("(bmp=%p, buffer=%p, count=0x%x)\n", hbitmap, buffer, count);
195
196     wine_tsx11_lock();
197     height = count / bitmap.bmWidthBytes;
198     image = XGetImage( gdi_display, physBitmap->pixmap, 0, 0,
199                        bitmap.bmWidth, height, AllPlanes, ZPixmap );
200
201     /* copy XImage to 16 bit padded image buffer with real bitsperpixel */
202
203     startline = buffer;
204     switch (bitmap.bmBitsPixel)
205     {
206     case 1:
207         for (h=0;h<height;h++)
208         {
209             tbuf = startline;
210             *tbuf = 0;
211             for (w=0;w<bitmap.bmWidth;w++)
212             {
213                 if ((w%8) == 0)
214                     *tbuf = 0;
215                 *tbuf |= XGetPixel(image,w,h)<<(7-(w&7));
216                 if ((w&7) == 7) ++tbuf;
217             }
218             startline += bitmap.bmWidthBytes;
219         }
220         break;
221     case 4:
222         for (h=0;h<height;h++)
223         {
224             tbuf = startline;
225             for (w=0;w<bitmap.bmWidth;w++)
226             {
227                 if (!(w & 1)) *tbuf = XGetPixel( image, w, h) << 4;
228                 else *tbuf++ |= XGetPixel( image, w, h) & 0x0f;
229             }
230             startline += bitmap.bmWidthBytes;
231         }
232         break;
233     case 8:
234         for (h=0;h<height;h++)
235         {
236             tbuf = startline;
237             for (w=0;w<bitmap.bmWidth;w++)
238                 *tbuf++ = XGetPixel(image,w,h);
239             startline += bitmap.bmWidthBytes;
240         }
241         break;
242     case 15:
243     case 16:
244         for (h=0;h<height;h++)
245         {
246             tbuf = startline;
247             for (w=0;w<bitmap.bmWidth;w++)
248             {
249                 long pixel = XGetPixel(image,w,h);
250
251                 *tbuf++ = pixel & 0xff;
252                 *tbuf++ = (pixel>>8) & 0xff;
253             }
254             startline += bitmap.bmWidthBytes;
255         }
256         break;
257     case 24:
258         for (h=0;h<height;h++)
259         {
260             tbuf = startline;
261             for (w=0;w<bitmap.bmWidth;w++)
262             {
263                 long pixel = XGetPixel(image,w,h);
264
265                 *tbuf++ = pixel & 0xff;
266                 *tbuf++ = (pixel>> 8) & 0xff;
267                 *tbuf++ = (pixel>>16) & 0xff;
268             }
269             startline += bitmap.bmWidthBytes;
270         }
271         break;
272
273     case 32:
274         for (h=0;h<height;h++)
275         {
276             tbuf = startline;
277             for (w=0;w<bitmap.bmWidth;w++)
278             {
279                 long pixel = XGetPixel(image,w,h);
280
281                 *tbuf++ = pixel & 0xff;
282                 *tbuf++ = (pixel>> 8) & 0xff;
283                 *tbuf++ = (pixel>>16) & 0xff;
284                 *tbuf++ = (pixel>>24) & 0xff;
285             }
286             startline += bitmap.bmWidthBytes;
287         }
288         break;
289     default:
290         FIXME("Unhandled bits:%d\n", bitmap.bmBitsPixel);
291     }
292     XDestroyImage( image );
293     wine_tsx11_unlock();
294     return count;
295 }
296
297
298
299 /******************************************************************************
300  *             SetBitmapBits   (X11DRV.@)
301  *
302  * RETURNS
303  *    Success: Number of bytes used in setting the bitmap bits
304  *    Failure: 0
305  */
306 LONG X11DRV_SetBitmapBits( HBITMAP hbitmap, const void *bits, LONG count )
307 {
308     BITMAP bitmap;
309     X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
310     LONG height;
311     XImage *image;
312     const BYTE *sbuf, *startline;
313     int w, h;
314
315     if (!physBitmap || !GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return 0;
316
317     TRACE("(bmp=%p, bits=%p, count=0x%x)\n", hbitmap, bits, count);
318
319     height = count / bitmap.bmWidthBytes;
320
321     wine_tsx11_lock();
322     image = XCreateImage( gdi_display, visual, physBitmap->pixmap_depth, ZPixmap, 0, NULL,
323                           bitmap.bmWidth, height, 32, 0 );
324     if (!(image->data = malloc(image->bytes_per_line * height)))
325     {
326         WARN("No memory to create image data.\n");
327         XDestroyImage( image );
328         wine_tsx11_unlock();
329         return 0;
330     }
331
332     /* copy 16 bit padded image buffer with real bitsperpixel to XImage */
333
334     startline = bits;
335
336     switch (bitmap.bmBitsPixel)
337     {
338     case 1:
339         for (h=0;h<height;h++)
340         {
341             sbuf = startline;
342             for (w=0;w<bitmap.bmWidth;w++)
343             {
344                 XPutPixel(image,w,h,(sbuf[0]>>(7-(w&7))) & 1);
345                 if ((w&7) == 7)
346                     sbuf++;
347             }
348             startline += bitmap.bmWidthBytes;
349         }
350         break;
351     case 4:
352         for (h=0;h<height;h++)
353         {
354             sbuf = startline;
355             for (w=0;w<bitmap.bmWidth;w++)
356             {
357                 if (!(w & 1)) XPutPixel( image, w, h, *sbuf >> 4 );
358                 else XPutPixel( image, w, h, *sbuf++ & 0xf );
359             }
360             startline += bitmap.bmWidthBytes;
361         }
362         break;
363     case 8:
364         for (h=0;h<height;h++)
365         {
366             sbuf = startline;
367             for (w=0;w<bitmap.bmWidth;w++)
368                 XPutPixel(image,w,h,*sbuf++);
369             startline += bitmap.bmWidthBytes;
370         }
371         break;
372     case 15:
373     case 16:
374         for (h=0;h<height;h++)
375         {
376             sbuf = startline;
377             for (w=0;w<bitmap.bmWidth;w++)
378             {
379                 XPutPixel(image,w,h,sbuf[1]*256+sbuf[0]);
380                 sbuf+=2;
381             }
382             startline += bitmap.bmWidthBytes;
383         }
384         break;
385     case 24:
386         for (h=0;h<height;h++)
387         {
388             sbuf = startline;
389             for (w=0;w<bitmap.bmWidth;w++)
390             {
391                 XPutPixel(image,w,h,(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
392                 sbuf += 3;
393             }
394             startline += bitmap.bmWidthBytes;
395         }
396         break;
397     case 32:
398         for (h=0;h<height;h++)
399         {
400             sbuf = startline;
401             for (w=0;w<bitmap.bmWidth;w++)
402             {
403                 XPutPixel(image,w,h,(sbuf[3]<<24)+(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
404                 sbuf += 4;
405             }
406             startline += bitmap.bmWidthBytes;
407         }
408         break;
409     default:
410       FIXME("Unhandled bits:%d\n", bitmap.bmBitsPixel);
411
412     }
413     XPutImage( gdi_display, physBitmap->pixmap, BITMAP_GC(physBitmap),
414                image, 0, 0, 0, 0, bitmap.bmWidth, height );
415     XDestroyImage( image ); /* frees image->data too */
416     wine_tsx11_unlock();
417     return count;
418 }
419
420 /***********************************************************************
421  *           DeleteBitmap   (X11DRV.@)
422  */
423 BOOL X11DRV_DeleteBitmap( HBITMAP hbitmap )
424 {
425     X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
426
427     if (physBitmap)
428     {
429         DIBSECTION dib;
430
431         if (GetObjectW( hbitmap, sizeof(dib), &dib ) == sizeof(dib))
432             X11DRV_DIB_DeleteDIBSection( physBitmap, &dib );
433
434         if (physBitmap->glxpixmap) destroy_glxpixmap(physBitmap->glxpixmap); 
435         wine_tsx11_lock();
436         if (physBitmap->pixmap) XFreePixmap( gdi_display, physBitmap->pixmap );
437         XDeleteContext( gdi_display, (XID)hbitmap, bitmap_context );
438         wine_tsx11_unlock();
439         HeapFree( GetProcessHeap(), 0, physBitmap );
440     }
441     return TRUE;
442 }
443
444
445 /***********************************************************************
446  *           X11DRV_get_phys_bitmap
447  *
448  * Retrieve the X physical bitmap info.
449  */
450 X_PHYSBITMAP *X11DRV_get_phys_bitmap( HBITMAP hbitmap )
451 {
452     X_PHYSBITMAP *ret;
453
454     wine_tsx11_lock();
455     if (XFindContext( gdi_display, (XID)hbitmap, bitmap_context, (char **)&ret )) ret = NULL;
456     wine_tsx11_unlock();
457     return ret;
458 }
459
460
461 /***********************************************************************
462  *           X11DRV_init_phys_bitmap
463  *
464  * Initialize the X physical bitmap info.
465  */
466 X_PHYSBITMAP *X11DRV_init_phys_bitmap( HBITMAP hbitmap )
467 {
468     X_PHYSBITMAP *ret;
469
470     if ((ret = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret) )) != NULL)
471     {
472         ret->hbitmap = hbitmap;
473         wine_tsx11_lock();
474         XSaveContext( gdi_display, (XID)hbitmap, bitmap_context, (char *)ret );
475         wine_tsx11_unlock();
476     }
477     return ret;
478 }
479
480
481 /***********************************************************************
482  *           X11DRV_get_pixmap
483  *
484  * Retrieve the pixmap associated to a bitmap.
485  */
486 Pixmap X11DRV_get_pixmap( HBITMAP hbitmap )
487 {
488     X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
489
490     if (!physBitmap) return 0;
491     return physBitmap->pixmap;
492 }