Made sleep_on usable from all requests.
[wine] / graphics / x11drv / bitmap.c
1 /*
2  * X11DRV bitmap objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1999 Noel Borthwick
6  */
7
8 #include "config.h"
9
10 #ifndef X_DISPLAY_MISSING
11
12 #include "ts_xlib.h"
13 #include "ts_xutil.h"
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include "gdi.h"
18 #include "callback.h"
19 #include "dc.h"
20 #include "bitmap.h"
21 #include "heap.h"
22 #include "monitor.h"
23 #include "debugtools.h"
24 #include "xmalloc.h"
25 #include "local.h"
26 #include "x11drv.h"
27 #include "wine/winuser16.h"
28
29 DEFAULT_DEBUG_CHANNEL(x11drv)
30
31   /* GCs used for B&W and color bitmap operations */
32 GC BITMAP_monoGC = 0, BITMAP_colorGC = 0;
33
34
35 /***********************************************************************
36  *           X11DRV_BITMAP_Init
37  */
38 BOOL X11DRV_BITMAP_Init(void)
39 {
40     Pixmap tmpPixmap;
41     
42       /* Create the necessary GCs */
43     
44     if ((tmpPixmap = TSXCreatePixmap(display, 
45                                      X11DRV_GetXRootWindow(), 
46                                      1, 1, 
47                                      1)))
48     {
49         BITMAP_monoGC = TSXCreateGC( display, tmpPixmap, 0, NULL );
50         TSXSetGraphicsExposures( display, BITMAP_monoGC, False );
51         TSXFreePixmap( display, tmpPixmap );
52     }
53
54     if (MONITOR_GetDepth(&MONITOR_PrimaryMonitor) != 1)
55     {
56         if ((tmpPixmap = TSXCreatePixmap(display, 
57                                          X11DRV_GetXRootWindow(),
58                                          1, 1,
59                                          MONITOR_GetDepth(&MONITOR_PrimaryMonitor))))
60         {
61             BITMAP_colorGC = TSXCreateGC( display, tmpPixmap, 0, NULL );
62             TSXSetGraphicsExposures( display, BITMAP_colorGC, False );
63             TSXFreePixmap( display, tmpPixmap );
64         }
65     }
66     return TRUE;
67 }
68
69 /***********************************************************************
70  *           X11DRV_BITMAP_SelectObject
71  */
72 HBITMAP X11DRV_BITMAP_SelectObject( DC * dc, HBITMAP hbitmap,
73                                       BITMAPOBJ * bmp )
74 {
75     HRGN hrgn;
76     HBITMAP prevHandle = dc->w.hBitmap;
77     X11DRV_PHYSBITMAP *pbitmap;
78     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
79
80
81     if (!(dc->w.flags & DC_MEMORY)) return 0;
82
83     if(!bmp->DDBitmap)
84         if(!X11DRV_CreateBitmap(hbitmap))
85             return 0;
86
87     if(bmp->DDBitmap->funcs != dc->funcs) {
88         WARN("Trying to select non-X11 DDB into an X11 dc\n");
89         return 0;
90     }
91
92     pbitmap = bmp->DDBitmap->physBitmap;
93
94     dc->w.totalExtent.left   = 0;
95     dc->w.totalExtent.top    = 0;
96     dc->w.totalExtent.right  = bmp->bitmap.bmWidth;
97     dc->w.totalExtent.bottom = bmp->bitmap.bmHeight;
98
99     if (dc->w.hVisRgn)
100        SetRectRgn( dc->w.hVisRgn, 0, 0,
101                      bmp->bitmap.bmWidth, bmp->bitmap.bmHeight );
102     else
103     { 
104        hrgn = CreateRectRgn(0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight);
105        if (!hrgn) return 0;
106        dc->w.hVisRgn    = hrgn;
107     }
108
109     physDev->drawable = pbitmap->pixmap;
110     dc->w.hBitmap     = hbitmap;
111
112       /* Change GC depth if needed */
113
114     if (dc->w.bitsPerPixel != bmp->bitmap.bmBitsPixel)
115     {
116         TSXFreeGC( display, physDev->gc );
117         physDev->gc = TSXCreateGC( display, physDev->drawable, 0, NULL );
118         TSXSetGraphicsExposures( display, physDev->gc, False );
119         dc->w.bitsPerPixel = bmp->bitmap.bmBitsPixel;
120         DC_InitDC( dc );
121     }
122     else CLIPPING_UpdateGCRegion( dc );  /* Just update GC clip region */
123     return prevHandle;
124 }
125
126
127 /***********************************************************************
128  *           XPutImage_wrapper
129  *
130  * Wrapper to call XPutImage with CALL_LARGE_STACK.
131  */
132
133 struct XPutImage_descr
134 {
135     BITMAPOBJ *bmp;
136     XImage    *image;
137     INT      width;
138     INT      height;
139 };
140
141 static int XPutImage_wrapper( const struct XPutImage_descr *descr )
142 {
143     return XPutImage( display,
144                ((X11DRV_PHYSBITMAP *)descr->bmp->DDBitmap->physBitmap)->pixmap,
145                BITMAP_GC(descr->bmp),
146                descr->image, 0, 0, 0, 0, descr->width, descr->height );
147 }
148
149
150 /***************************************************************************
151  *
152  *      X11DRV_AllocBitmap
153  *
154  * Allocate DDBitmap and physBitmap
155  *
156  */
157 X11DRV_PHYSBITMAP *X11DRV_AllocBitmap( BITMAPOBJ *bmp )
158 {
159     X11DRV_PHYSBITMAP *pbitmap;
160
161     if(!(bmp->DDBitmap = HeapAlloc(GetProcessHeap(), 0, sizeof(DDBITMAP)))) {
162         WARN("Can't alloc DDBITMAP\n");
163         return NULL;
164     }
165
166     if(!(pbitmap = HeapAlloc(GetProcessHeap(), 0,sizeof(X11DRV_PHYSBITMAP)))) {
167         WARN("Can't alloc X11DRV_PHYSBITMAP\n");
168         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap);
169         return NULL;
170     }
171
172     bmp->DDBitmap->physBitmap = pbitmap;
173     bmp->DDBitmap->funcs = DRIVER_FindDriver( "DISPLAY" );
174     return pbitmap;
175 }
176
177
178 /****************************************************************************
179  *
180  *        X11DRV_CreateBitmap
181  *
182  * Create a device dependent X11 bitmap
183  *
184  * Returns TRUE on success else FALSE
185  *
186  */
187
188 BOOL X11DRV_CreateBitmap( HBITMAP hbitmap )
189 {
190     X11DRV_PHYSBITMAP *pbitmap;
191     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
192
193     if(!bmp) {
194         WARN("Bad bitmap handle %08x\n", hbitmap);
195         return FALSE;
196     }
197
198       /* Check parameters */
199     if (bmp->bitmap.bmPlanes != 1) return 0;
200     if ((bmp->bitmap.bmBitsPixel != 1) && 
201         (bmp->bitmap.bmBitsPixel != MONITOR_GetDepth(&MONITOR_PrimaryMonitor))) {
202         ERR("Trying to make bitmap with planes=%d, bpp=%d\n",
203             bmp->bitmap.bmPlanes, bmp->bitmap.bmBitsPixel);
204         GDI_HEAP_UNLOCK( hbitmap );
205         return FALSE;
206     }
207
208     TRACE("(%08x) %dx%d %d bpp\n", hbitmap, bmp->bitmap.bmWidth,
209           bmp->bitmap.bmHeight, bmp->bitmap.bmBitsPixel);
210
211     pbitmap = X11DRV_AllocBitmap( bmp );
212     if(!pbitmap) return FALSE;
213
214       /* Create the pixmap */
215     pbitmap->pixmap = TSXCreatePixmap(display, X11DRV_GetXRootWindow(), bmp->bitmap.bmWidth,
216                               bmp->bitmap.bmHeight, bmp->bitmap.bmBitsPixel);
217     if (!pbitmap->pixmap) {
218         WARN("Can't create Pixmap\n");
219         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap->physBitmap);
220         HeapFree(GetProcessHeap(), 0, bmp->DDBitmap);
221         GDI_HEAP_UNLOCK( hbitmap );
222         return FALSE;
223     }
224
225     if (bmp->bitmap.bmBits) /* Set bitmap bits */
226         X11DRV_BitmapBits( hbitmap, bmp->bitmap.bmBits,
227                            bmp->bitmap.bmHeight * bmp->bitmap.bmWidthBytes,
228                            DDB_SET );
229
230     GDI_HEAP_UNLOCK( hbitmap );
231     return TRUE;
232 }
233
234
235 /***********************************************************************
236  *           X11DRV_BITMAP_GetXImage
237  *
238  * Get an X image for a bitmap. For use with CALL_LARGE_STACK.
239  */
240 XImage *X11DRV_BITMAP_GetXImage( const BITMAPOBJ *bmp )
241 {
242     return XGetImage( display,
243                       ((X11DRV_PHYSBITMAP *)bmp->DDBitmap->physBitmap)->pixmap,
244                       0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
245                       AllPlanes, ZPixmap );
246 }
247
248
249 /***********************************************************************
250  *           X11DRV_GetBitmapBits
251  * 
252  * RETURNS
253  *    Success: Number of bytes copied
254  *    Failure: 0
255  */
256 static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count)
257 {
258     LONG old_height, height;
259     XImage *image;
260     LPBYTE tbuf, startline;
261     int h, w;
262
263     TRACE("(bmp=%p, buffer=%p, count=0x%lx)\n", bmp, buffer, count);
264
265     EnterCriticalSection( &X11DRV_CritSection );
266
267     /* Hack: change the bitmap height temporarily to avoid */
268     /*       getting unnecessary bitmap rows. */
269
270     old_height = bmp->bitmap.bmHeight;
271     height = bmp->bitmap.bmHeight = count / bmp->bitmap.bmWidthBytes;
272
273     image = (XImage *)CALL_LARGE_STACK( X11DRV_BITMAP_GetXImage, bmp );
274
275     bmp->bitmap.bmHeight = old_height;
276
277     /* copy XImage to 16 bit padded image buffer with real bitsperpixel */
278
279     startline = buffer;
280     switch (bmp->bitmap.bmBitsPixel)
281     {
282     case 1:
283         for (h=0;h<height;h++)
284         {
285             tbuf = startline;
286             *tbuf = 0;
287             for (w=0;w<bmp->bitmap.bmWidth;w++)
288             {
289                 if ((w%8) == 0)
290                     *tbuf = 0;
291                 *tbuf |= XGetPixel(image,w,h)<<(7-(w&7));
292                 if ((w&7) == 7) ++tbuf;
293             }
294             startline += bmp->bitmap.bmWidthBytes;
295         }
296         break;
297     case 4:
298         for (h=0;h<height;h++)
299         {
300             tbuf = startline;
301             for (w=0;w<bmp->bitmap.bmWidth;w++)
302             {
303                 if (!(w & 1)) *tbuf = XGetPixel( image, w, h) << 4;
304                 else *tbuf++ |= XGetPixel( image, w, h) & 0x0f;
305             }
306             startline += bmp->bitmap.bmWidthBytes;
307         }
308         break;
309     case 8:
310         for (h=0;h<height;h++)
311         {
312             tbuf = startline;
313             for (w=0;w<bmp->bitmap.bmWidth;w++)
314                 *tbuf++ = XGetPixel(image,w,h);
315             startline += bmp->bitmap.bmWidthBytes;
316         }
317         break;
318     case 15:
319     case 16:
320         for (h=0;h<height;h++)
321         {
322             tbuf = startline;
323             for (w=0;w<bmp->bitmap.bmWidth;w++)
324             {
325                 long pixel = XGetPixel(image,w,h);
326
327                 *tbuf++ = pixel & 0xff;
328                 *tbuf++ = (pixel>>8) & 0xff;
329             }
330             startline += bmp->bitmap.bmWidthBytes;
331         }
332         break;
333     case 24:
334         for (h=0;h<height;h++)
335         {
336             tbuf = startline;
337             for (w=0;w<bmp->bitmap.bmWidth;w++)
338             {
339                 long pixel = XGetPixel(image,w,h);
340
341                 *tbuf++ = pixel & 0xff;
342                 *tbuf++ = (pixel>> 8) & 0xff;
343                 *tbuf++ = (pixel>>16) & 0xff;
344             }
345             startline += bmp->bitmap.bmWidthBytes;
346         }
347         break;
348
349     case 32:
350         for (h=0;h<height;h++)
351         {
352             tbuf = startline;
353             for (w=0;w<bmp->bitmap.bmWidth;w++)
354             {
355                 long pixel = XGetPixel(image,w,h);
356
357                 *tbuf++ = pixel & 0xff;
358                 *tbuf++ = (pixel>> 8) & 0xff;
359                 *tbuf++ = (pixel>>16) & 0xff;
360                 *tbuf++ = (pixel>>24) & 0xff;
361             }
362             startline += bmp->bitmap.bmWidthBytes;
363         }
364         break;
365     default:
366         FIXME("Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel);
367     }
368     XDestroyImage( image );
369     LeaveCriticalSection( &X11DRV_CritSection );
370
371     return count;
372 }
373
374
375
376 /******************************************************************************
377  *             X11DRV_SetBitmapBits
378  *
379  * RETURNS
380  *    Success: Number of bytes used in setting the bitmap bits
381  *    Failure: 0
382  */
383 static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count)
384 {
385     struct XPutImage_descr descr;
386     LONG height;
387     XImage *image;
388     LPBYTE sbuf, startline;
389     int w, h;
390
391     TRACE("(bmp=%p, bits=%p, count=0x%lx)\n", bmp, bits, count);
392     
393     height = count / bmp->bitmap.bmWidthBytes;
394
395     EnterCriticalSection( &X11DRV_CritSection );
396     image = XCreateImage( display, DefaultVisualOfScreen(X11DRV_GetXScreen()),
397                           bmp->bitmap.bmBitsPixel, ZPixmap, 0, NULL,
398                           bmp->bitmap.bmWidth, height, 32, 0 );
399     image->data = (LPBYTE)xmalloc(image->bytes_per_line * height);
400     
401     /* copy 16 bit padded image buffer with real bitsperpixel to XImage */
402     
403     startline = bits;
404
405     switch (bmp->bitmap.bmBitsPixel)
406     {
407     case 1:
408         for (h=0;h<height;h++)
409         {
410             sbuf = startline;
411             for (w=0;w<bmp->bitmap.bmWidth;w++)
412             {
413                 XPutPixel(image,w,h,(sbuf[0]>>(7-(w&7))) & 1);
414                 if ((w&7) == 7)
415                     sbuf++;
416             }
417             startline += bmp->bitmap.bmWidthBytes;
418         }
419         break;
420     case 4:
421         for (h=0;h<height;h++)
422         {
423             sbuf = startline;
424             for (w=0;w<bmp->bitmap.bmWidth;w++)
425             {
426                 if (!(w & 1)) XPutPixel( image, w, h, *sbuf >> 4 );
427                 else XPutPixel( image, w, h, *sbuf++ & 0xf );
428             }
429             startline += bmp->bitmap.bmWidthBytes;
430         }
431         break;
432     case 8:
433         for (h=0;h<height;h++)
434         {
435             sbuf = startline;
436             for (w=0;w<bmp->bitmap.bmWidth;w++)
437                 XPutPixel(image,w,h,*sbuf++);
438             startline += bmp->bitmap.bmWidthBytes;
439         }
440         break;
441     case 15:
442     case 16:
443         for (h=0;h<height;h++)
444         {
445             sbuf = startline;
446             for (w=0;w<bmp->bitmap.bmWidth;w++)
447             {
448                 XPutPixel(image,w,h,sbuf[1]*256+sbuf[0]);
449                 sbuf+=2;
450             }
451             startline += bmp->bitmap.bmWidthBytes;
452         }
453         break;
454     case 24:
455         for (h=0;h<height;h++)
456         {
457             sbuf = startline;
458             for (w=0;w<bmp->bitmap.bmWidth;w++)
459             {
460                 XPutPixel(image,w,h,(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
461                 sbuf += 3;
462             }
463             startline += bmp->bitmap.bmWidthBytes;
464         }
465         break;
466     case 32: 
467         for (h=0;h<height;h++)
468         {
469             sbuf = startline;
470             for (w=0;w<bmp->bitmap.bmWidth;w++)
471             {
472                 XPutPixel(image,w,h,(sbuf[3]<<24)+(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
473                 sbuf += 4;
474             }
475             startline += bmp->bitmap.bmWidthBytes;
476         }
477         break;
478     default:
479       FIXME("Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel);
480
481     }
482
483     descr.bmp    = bmp;
484     descr.image  = image;
485     descr.width  = bmp->bitmap.bmWidth;
486     descr.height = height;
487
488     CALL_LARGE_STACK( XPutImage_wrapper, &descr );
489     XDestroyImage( image ); /* frees image->data too */
490     LeaveCriticalSection( &X11DRV_CritSection );
491     
492     return count;
493 }
494
495 /***********************************************************************
496  *           X11DRV_BitmapBits
497  */
498 LONG X11DRV_BitmapBits(HBITMAP hbitmap, void *bits, LONG count, WORD flags)
499 {
500     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
501     LONG ret;
502     if(!bmp) {
503         WARN("Bad bitmap handle %08x\n", hbitmap);
504         return FALSE;
505     }
506
507     if(flags == DDB_GET)
508         ret = X11DRV_GetBitmapBits(bmp, bits, count);
509     else if(flags == DDB_SET)
510         ret = X11DRV_SetBitmapBits(bmp, bits, count);
511     else {
512         ERR("Unknown flags value %d\n", flags);
513         ret = 0;
514     }
515     
516     GDI_HEAP_UNLOCK( hbitmap );
517     return ret;
518 }
519
520 /***********************************************************************
521  *           X11DRV_BITMAP_DeleteObject
522  */
523 BOOL X11DRV_BITMAP_DeleteObject( HBITMAP hbitmap, BITMAPOBJ * bmp )
524 {
525     X11DRV_PHYSBITMAP *pbitmap = bmp->DDBitmap->physBitmap;
526
527     TSXFreePixmap( display, pbitmap->pixmap );
528
529     HeapFree( GetProcessHeap(), 0, bmp->DDBitmap->physBitmap );
530     HeapFree( GetProcessHeap(), 0, bmp->DDBitmap );
531     bmp->DDBitmap = NULL;
532
533     return TRUE;
534 }
535
536 /**************************************************************************
537  *              X11DRV_BITMAP_CreateBitmapHeaderFromPixmap
538  *
539  *  Allocates an HBITMAP which references the Pixmap passed in.
540  *  Note: This function makes the bitmap an owner of the Pixmap so subsequently
541  *  calling DeleteObject on this will free the Pixmap as well.
542  */
543 HBITMAP X11DRV_BITMAP_CreateBitmapHeaderFromPixmap(Pixmap pixmap)
544 {
545     HBITMAP hBmp = 0;
546     BITMAPOBJ *pBmp = NULL;
547     X11DRV_PHYSBITMAP *pPhysBmp = NULL;
548     Window root;
549     int x,y;               /* Unused */
550     unsigned border_width; /* Unused */
551     unsigned int depth, width, height;
552
553     /* Get the Pixmap dimensions and bit depth */
554     if ( 0 == TSXGetGeometry(display, pixmap, &root, &x, &y, &width, &height,
555                              &border_width, &depth) )
556         goto END;
557
558     TRACE("\tPixmap properties: width=%d, height=%d, depth=%d\n",
559           width, height, depth);
560     
561     /*
562      * Create an HBITMAP with the same dimensions and BPP as the pixmap,
563      * and make it a container for the pixmap passed.
564      */
565     hBmp = CreateBitmap( width, height, 1, depth, NULL );
566
567     /* Allocate DDBitmap and physBitmap structures in BITMAPOBJ.
568      * The hBmp is just a filled in BITMAPOBJ header at this point.
569      */
570     pBmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
571     pPhysBmp = X11DRV_AllocBitmap( pBmp );
572     if( !pPhysBmp )
573     {
574         DeleteObject(hBmp);
575         hBmp = NULL;
576         goto END;
577     }
578     
579     /* Point to our Pixmap in the physical bitmap structure */
580     pPhysBmp->pixmap = pixmap;
581
582 END:
583     TRACE("\tReturning HBITMAP %x\n", hBmp);
584     return hBmp;
585 }
586
587
588 /**************************************************************************
589  *              X11DRV_BITMAP_CreateBitmapFromPixmap
590  *
591  *  Allocates an HBITMAP and copies the Pixmap data into it.
592  *  If bDeletePixmap is TRUE, the Pixmap passed in is deleted after the conversion.
593  */
594 HBITMAP X11DRV_BITMAP_CreateBitmapFromPixmap(Pixmap pixmap, BOOL bDeletePixmap)
595 {
596     HBITMAP hBmp = 0, hBmpCopy = 0;
597     BITMAPOBJ *pBmp = NULL;
598     unsigned int width, height;
599
600     /* Allocate an HBITMAP which references the Pixmap passed to us */
601     hBmp = X11DRV_BITMAP_CreateBitmapHeaderFromPixmap(pixmap);
602     if (!hBmp)
603     {
604         TRACE("\tCould not create bitmap header for Pixmap\n");
605         goto END;
606     }
607
608     /* Get the bitmap dimensions */
609     width = pBmp->bitmap.bmWidth;
610     height = pBmp->bitmap.bmHeight;
611                  
612     hBmpCopy = CopyImage(hBmp, IMAGE_BITMAP, width, height, LR_CREATEDIBSECTION);
613
614     /* We can now get rid of the HBITMAP wrapper we created earlier.
615      * Note: Simply calling DeleteObject will free the embedded Pixmap as well.
616      */
617     if (!bDeletePixmap)
618     {
619         /* Manually free the DDBitmap internals to prevent the Pixmap 
620          * from being deleted by DeleteObject.
621          */
622         pBmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC );
623         HeapFree( GetProcessHeap(), 0, pBmp->DDBitmap->physBitmap );
624         HeapFree( GetProcessHeap(), 0, pBmp->DDBitmap );
625         pBmp->DDBitmap = NULL;
626     }
627     DeleteObject(hBmp);  
628
629 END:
630     TRACE("\tReturning HBITMAP %x\n", hBmpCopy);
631     return hBmpCopy;
632 }
633
634
635 /**************************************************************************
636  *                 X11DRV_BITMAP_CreatePixmapFromBitmap
637  *
638  *    Creates a Pixmap from a bitmap
639  */
640 Pixmap X11DRV_BITMAP_CreatePixmapFromBitmap( HBITMAP hBmp, HDC hdc )
641 {
642     HGLOBAL hPackedDIB = NULL;
643     Pixmap pixmap = NULL;
644
645     /*
646      * Create a packed DIB from the bitmap passed to us.
647      * A packed DIB contains a BITMAPINFO structure followed immediately by
648      * an optional color palette and the pixel data.
649      */
650     hPackedDIB = DIB_CreateDIBFromBitmap(hdc, hBmp);
651
652     /* Create a Pixmap from the packed DIB */
653     pixmap = X11DRV_DIB_CreatePixmapFromDIB( hPackedDIB, hdc );
654
655     /* Free the temporary packed DIB */
656     GlobalFree(hPackedDIB);
657
658     return pixmap;
659 }
660
661
662 /***********************************************************************
663  *           X11DRV_BITMAP_Pixmap
664  *
665  * This function exists solely for x11 driver of the window system.
666  */
667 BOOL X11DRV_BITMAP_Pixmap(HBITMAP hbitmap)
668 {
669     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
670     return ((X11DRV_PHYSBITMAP *)(bmp->DDBitmap->physBitmap))->pixmap;
671 }
672
673 #endif /* !defined(X_DISPLAY_MISSING) */