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