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