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