bitmap.c 13.9 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
2
 * X11DRV bitmap objects
Alexandre Julliard's avatar
Alexandre Julliard committed
3 4
 *
 * Copyright 1993 Alexandre Julliard
5
 *           1999 Noel Borthwick
6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
20 21
 */

Patrik Stridvall's avatar
Patrik Stridvall committed
22 23 24 25
#include "config.h"

#include <stdio.h>
#include <stdlib.h>
26 27
#include "windef.h"
#include "wingdi.h"
28
#include "wine/debug.h"
29 30
#include "x11drv.h"

31
WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
32

33 34
  /* GCs used for B&W and color bitmap operations */
GC BITMAP_monoGC = 0, BITMAP_colorGC = 0;
35
X_PHYSBITMAP BITMAP_stock_phys_bitmap = { 0 };  /* phys bitmap for the default stock bitmap */
36

37 38
static XContext bitmap_context;  /* X context to associate a phys bitmap to a handle */

Alexandre Julliard's avatar
Alexandre Julliard committed
39 40 41
/***********************************************************************
 *           X11DRV_BITMAP_Init
 */
42
void X11DRV_BITMAP_Init(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
43 44
{
    Pixmap tmpPixmap;
45

Alexandre Julliard's avatar
Alexandre Julliard committed
46
      /* Create the necessary GCs */
47 48

    wine_tsx11_lock();
49
    bitmap_context = XUniqueContext();
50 51 52
    BITMAP_stock_phys_bitmap.pixmap_depth = 1;
    BITMAP_stock_phys_bitmap.pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 1 );
    BITMAP_monoGC = XCreateGC( gdi_display, BITMAP_stock_phys_bitmap.pixmap, 0, NULL );
53 54
    XSetGraphicsExposures( gdi_display, BITMAP_monoGC, False );
    XSetSubwindowMode( gdi_display, BITMAP_monoGC, IncludeInferiors );
Alexandre Julliard's avatar
Alexandre Julliard committed
55

56
    if (screen_depth != 1)
Alexandre Julliard's avatar
Alexandre Julliard committed
57
    {
58 59 60 61
        if ((tmpPixmap = XCreatePixmap( gdi_display, root_window, 1, 1, screen_depth )))
        {
            BITMAP_colorGC = XCreateGC( gdi_display, tmpPixmap, 0, NULL );
            XSetGraphicsExposures( gdi_display, BITMAP_colorGC, False );
62
            XSetSubwindowMode( gdi_display, BITMAP_colorGC, IncludeInferiors );
63 64
            XFreePixmap( gdi_display, tmpPixmap );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
65
    }
66
    wine_tsx11_unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
67 68 69
}

/***********************************************************************
70
 *           SelectBitmap   (X11DRV.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
71
 */
72
HBITMAP X11DRV_SelectBitmap( X11DRV_PDEVICE *physDev, HBITMAP hbitmap )
Alexandre Julliard's avatar
Alexandre Julliard committed
73
{
74
    X_PHYSBITMAP *physBitmap;
75

76 77 78
    if(physDev->xrender)
        X11DRV_XRender_UpdateDrawable( physDev );

79 80 81 82 83
    if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap) physBitmap = &BITMAP_stock_phys_bitmap;
    else if (!(physBitmap = X11DRV_get_phys_bitmap( hbitmap ))) return 0;

    physDev->bitmap = physBitmap;
    physDev->drawable = physBitmap->pixmap;
84

Alexandre Julliard's avatar
Alexandre Julliard committed
85 86
      /* Change GC depth if needed */

87
    if (physDev->depth != physBitmap->pixmap_depth)
Alexandre Julliard's avatar
Alexandre Julliard committed
88
    {
89
        physDev->depth = physBitmap->pixmap_depth;
90 91 92 93
        wine_tsx11_lock();
        XFreeGC( gdi_display, physDev->gc );
        physDev->gc = XCreateGC( gdi_display, physDev->drawable, 0, NULL );
        XSetGraphicsExposures( gdi_display, physDev->gc, False );
94 95
        XSetSubwindowMode( gdi_display, physDev->gc, IncludeInferiors );
        XFlush( gdi_display );
96
        wine_tsx11_unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
97
    }
98
    return hbitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
99
}
100 101 102


/****************************************************************************
103
 *	  CreateBitmap   (X11DRV.@)
104 105 106 107 108
 *
 * Create a device dependent X11 bitmap
 *
 * Returns TRUE on success else FALSE
 */
109
BOOL X11DRV_CreateBitmap( X11DRV_PDEVICE *physDev, HBITMAP hbitmap )
110
{
111
    X_PHYSBITMAP *physBitmap;
112
    BITMAP bitmap;
113

114
    if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
115 116

      /* Check parameters */
117
    if (bitmap.bmPlanes != 1) return FALSE;
118

119
    if ((bitmap.bmBitsPixel != 1) && (bitmap.bmBitsPixel != screen_depth))
120
    {
121
        ERR("Trying to make bitmap with planes=%d, bpp=%d\n",
122 123
            bitmap.bmPlanes, bitmap.bmBitsPixel);
        return FALSE;
124
    }
125
    if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap)
126 127
    {
        ERR( "called for stock bitmap, please report\n" );
128
        return FALSE;
129
    }
130

131
    TRACE("(%p) %dx%d %d bpp\n", hbitmap, bitmap.bmWidth, bitmap.bmHeight, bitmap.bmBitsPixel);
Huw D M Davies's avatar
Huw D M Davies committed
132

133
    if (!(physBitmap = X11DRV_init_phys_bitmap( hbitmap ))) return FALSE;
134

135
      /* Create the pixmap */
136
    wine_tsx11_lock();
137
    physBitmap->pixmap_depth = bitmap.bmBitsPixel;
138
    physBitmap->pixmap = XCreatePixmap(gdi_display, root_window,
139
                                       bitmap.bmWidth, bitmap.bmHeight, bitmap.bmBitsPixel);
140
    wine_tsx11_unlock();
141
    if (!physBitmap->pixmap)
142
    {
143
        WARN("Can't create Pixmap\n");
144
        HeapFree( GetProcessHeap(), 0, physBitmap );
145
        return FALSE;
146 147
    }

148
    if (bitmap.bmBits) /* Set bitmap bits */
149
    {
150
        X11DRV_SetBitmapBits( hbitmap, bitmap.bmBits, bitmap.bmHeight * bitmap.bmWidthBytes );
151 152 153 154 155 156 157 158 159 160
    }
    else  /* else clear the bitmap */
    {
        wine_tsx11_lock();
        XSetFunction( gdi_display, BITMAP_GC(physBitmap), GXclear );
        XFillRectangle( gdi_display, physBitmap->pixmap, BITMAP_GC(physBitmap), 0, 0,
                        bitmap.bmWidth, bitmap.bmHeight );
        XSetFunction( gdi_display, BITMAP_GC(physBitmap), GXcopy );
        wine_tsx11_unlock();
    }
161
    return TRUE;
162 163 164 165
}


/***********************************************************************
166
 *           GetBitmapBits   (X11DRV.@)
167
 *
168 169 170 171
 * RETURNS
 *    Success: Number of bytes copied
 *    Failure: 0
 */
172
LONG X11DRV_GetBitmapBits( HBITMAP hbitmap, void *buffer, LONG count )
173
{
174 175
    BITMAP bitmap;
    X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
176 177
    LONG old_height, height;
    XImage *image;
178 179
    LPBYTE tbuf, startline;
    int	h, w;
180

181 182 183
    if (!physBitmap || !GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return 0;

    TRACE("(bmp=%p, buffer=%p, count=0x%lx)\n", hbitmap, buffer, count);
Huw D M Davies's avatar
Huw D M Davies committed
184

185
    wine_tsx11_lock();
186 187 188 189

    /* Hack: change the bitmap height temporarily to avoid */
    /*       getting unnecessary bitmap rows. */

190 191
    old_height = bitmap.bmHeight;
    height = bitmap.bmHeight = count / bitmap.bmWidthBytes;
192

193 194 195
    image = XGetImage( gdi_display, physBitmap->pixmap, 0, 0,
                       bitmap.bmWidth, bitmap.bmHeight, AllPlanes, ZPixmap );
    bitmap.bmHeight = old_height;
196 197 198

    /* copy XImage to 16 bit padded image buffer with real bitsperpixel */

199
    startline = buffer;
200
    switch (physBitmap->pixmap_depth)
201 202 203 204
    {
    case 1:
        for (h=0;h<height;h++)
        {
205
	    tbuf = startline;
206
            *tbuf = 0;
207
            for (w=0;w<bitmap.bmWidth;w++)
208 209 210 211 212 213
            {
                if ((w%8) == 0)
                    *tbuf = 0;
                *tbuf |= XGetPixel(image,w,h)<<(7-(w&7));
                if ((w&7) == 7) ++tbuf;
            }
214
            startline += bitmap.bmWidthBytes;
215 216 217 218 219
        }
        break;
    case 4:
        for (h=0;h<height;h++)
        {
220
	    tbuf = startline;
221
            for (w=0;w<bitmap.bmWidth;w++)
222 223 224 225
            {
                if (!(w & 1)) *tbuf = XGetPixel( image, w, h) << 4;
	    	else *tbuf++ |= XGetPixel( image, w, h) & 0x0f;
            }
226
            startline += bitmap.bmWidthBytes;
227 228 229 230 231
        }
        break;
    case 8:
        for (h=0;h<height;h++)
        {
232
	    tbuf = startline;
233
            for (w=0;w<bitmap.bmWidth;w++)
234
                *tbuf++ = XGetPixel(image,w,h);
235
            startline += bitmap.bmWidthBytes;
236 237 238 239 240 241
        }
        break;
    case 15:
    case 16:
        for (h=0;h<height;h++)
        {
242
	    tbuf = startline;
243
            for (w=0;w<bitmap.bmWidth;w++)
244 245 246 247 248 249
            {
	    	long pixel = XGetPixel(image,w,h);

		*tbuf++ = pixel & 0xff;
		*tbuf++ = (pixel>>8) & 0xff;
            }
250
            startline += bitmap.bmWidthBytes;
251 252 253 254 255
        }
        break;
    case 24:
        for (h=0;h<height;h++)
        {
256
	    tbuf = startline;
257
            for (w=0;w<bitmap.bmWidth;w++)
258 259 260 261 262 263 264
            {
	    	long pixel = XGetPixel(image,w,h);

		*tbuf++ = pixel & 0xff;
		*tbuf++ = (pixel>> 8) & 0xff;
		*tbuf++ = (pixel>>16) & 0xff;
	    }
265
            startline += bitmap.bmWidthBytes;
266 267 268 269 270 271
	}
        break;

    case 32:
        for (h=0;h<height;h++)
        {
272
	    tbuf = startline;
273
            for (w=0;w<bitmap.bmWidth;w++)
274 275 276 277 278 279 280 281
            {
	    	long pixel = XGetPixel(image,w,h);

		*tbuf++ = pixel & 0xff;
		*tbuf++ = (pixel>> 8) & 0xff;
		*tbuf++ = (pixel>>16) & 0xff;
		*tbuf++ = (pixel>>24) & 0xff;
	    }
282
            startline += bitmap.bmWidthBytes;
283 284 285
	}
        break;
    default:
286
        FIXME("Unhandled bits:%d\n", physBitmap->pixmap_depth);
287 288
    }
    XDestroyImage( image );
289
    wine_tsx11_unlock();
290 291 292 293 294 295
    return count;
}



/******************************************************************************
296
 *             SetBitmapBits   (X11DRV.@)
297 298 299 300 301
 *
 * RETURNS
 *    Success: Number of bytes used in setting the bitmap bits
 *    Failure: 0
 */
302
LONG X11DRV_SetBitmapBits( HBITMAP hbitmap, const void *bits, LONG count )
303
{
304 305
    BITMAP bitmap;
    X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
306 307
    LONG height;
    XImage *image;
308
    const BYTE *sbuf, *startline;
309
    int	w, h;
310

311 312 313
    if (!physBitmap || !GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return 0;

    TRACE("(bmp=%p, bits=%p, count=0x%lx)\n", hbitmap, bits, count);
314

315
    height = count / bitmap.bmWidthBytes;
316

317
    wine_tsx11_lock();
318 319 320
    image = XCreateImage( gdi_display, visual, physBitmap->pixmap_depth, ZPixmap, 0, NULL,
                          bitmap.bmWidth, height, 32, 0 );
    if (!(image->data = malloc(image->bytes_per_line * height)))
321 322 323
    {
        WARN("No memory to create image data.\n");
        XDestroyImage( image );
324
        wine_tsx11_unlock();
325 326
        return 0;
    }
327

328
    /* copy 16 bit padded image buffer with real bitsperpixel to XImage */
329

330 331
    startline = bits;

332
    switch (physBitmap->pixmap_depth)
333 334 335 336
    {
    case 1:
        for (h=0;h<height;h++)
        {
337
	    sbuf = startline;
338
            for (w=0;w<bitmap.bmWidth;w++)
339 340 341 342 343
            {
                XPutPixel(image,w,h,(sbuf[0]>>(7-(w&7))) & 1);
                if ((w&7) == 7)
                    sbuf++;
            }
344
            startline += bitmap.bmWidthBytes;
345 346 347 348 349
        }
        break;
    case 4:
        for (h=0;h<height;h++)
        {
350
	    sbuf = startline;
351
            for (w=0;w<bitmap.bmWidth;w++)
352 353 354 355
            {
                if (!(w & 1)) XPutPixel( image, w, h, *sbuf >> 4 );
                else XPutPixel( image, w, h, *sbuf++ & 0xf );
            }
356
            startline += bitmap.bmWidthBytes;
357 358 359 360 361
        }
        break;
    case 8:
        for (h=0;h<height;h++)
        {
362
	    sbuf = startline;
363
            for (w=0;w<bitmap.bmWidth;w++)
364
                XPutPixel(image,w,h,*sbuf++);
365
            startline += bitmap.bmWidthBytes;
366 367 368 369 370 371
        }
        break;
    case 15:
    case 16:
        for (h=0;h<height;h++)
        {
372
	    sbuf = startline;
373
            for (w=0;w<bitmap.bmWidth;w++)
374 375 376 377
            {
                XPutPixel(image,w,h,sbuf[1]*256+sbuf[0]);
                sbuf+=2;
            }
378
	    startline += bitmap.bmWidthBytes;
379 380
        }
        break;
381
    case 24:
382 383
        for (h=0;h<height;h++)
        {
384
	    sbuf = startline;
385
            for (w=0;w<bitmap.bmWidth;w++)
386 387 388 389
            {
                XPutPixel(image,w,h,(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
                sbuf += 3;
            }
390
            startline += bitmap.bmWidthBytes;
391 392
        }
        break;
393
    case 32:
394 395
        for (h=0;h<height;h++)
        {
396
	    sbuf = startline;
397
            for (w=0;w<bitmap.bmWidth;w++)
398 399 400 401
            {
                XPutPixel(image,w,h,(sbuf[3]<<24)+(sbuf[2]<<16)+(sbuf[1]<<8)+sbuf[0]);
                sbuf += 4;
            }
402
	    startline += bitmap.bmWidthBytes;
403 404 405
        }
        break;
    default:
406
      FIXME("Unhandled bits:%d\n", physBitmap->pixmap_depth);
407 408

    }
409 410
    XPutImage( gdi_display, physBitmap->pixmap, BITMAP_GC(physBitmap),
               image, 0, 0, 0, 0, bitmap.bmWidth, height );
Huw D M Davies's avatar
Huw D M Davies committed
411
    XDestroyImage( image ); /* frees image->data too */
412
    wine_tsx11_unlock();
413
    return count;
414 415 416
}

/***********************************************************************
417
 *           DeleteBitmap   (X11DRV.@)
418
 */
419
BOOL X11DRV_DeleteBitmap( HBITMAP hbitmap )
420
{
421
    X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );
422

423 424 425
    if (physBitmap)
    {
        DIBSECTION dib;
426

427 428
        if (GetObjectW( hbitmap, sizeof(dib), &dib ) == sizeof(dib))
            X11DRV_DIB_DeleteDIBSection( physBitmap, &dib );
429

430
        if (physBitmap->glxpixmap) destroy_glxpixmap(physBitmap->glxpixmap); 
431 432 433 434 435
        wine_tsx11_lock();
        if (physBitmap->pixmap) XFreePixmap( gdi_display, physBitmap->pixmap );
        XDeleteContext( gdi_display, (XID)hbitmap, bitmap_context );
        wine_tsx11_unlock();
        HeapFree( GetProcessHeap(), 0, physBitmap );
436
    }
437 438
    return TRUE;
}
Patrik Stridvall's avatar
Patrik Stridvall committed
439

440

441 442 443 444 445 446 447
/***********************************************************************
 *           X11DRV_get_phys_bitmap
 *
 * Retrieve the X physical bitmap info.
 */
X_PHYSBITMAP *X11DRV_get_phys_bitmap( HBITMAP hbitmap )
{
448 449 450 451 452
    X_PHYSBITMAP *ret;

    wine_tsx11_lock();
    if (XFindContext( gdi_display, (XID)hbitmap, bitmap_context, (char **)&ret )) ret = NULL;
    wine_tsx11_unlock();
453 454 455 456
    return ret;
}


457
/***********************************************************************
458
 *           X11DRV_init_phys_bitmap
459
 *
460
 * Initialize the X physical bitmap info.
461
 */
462
X_PHYSBITMAP *X11DRV_init_phys_bitmap( HBITMAP hbitmap )
463
{
464 465 466
    X_PHYSBITMAP *ret;

    if ((ret = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret) )) != NULL)
467
    {
468 469 470 471
        ret->hbitmap = hbitmap;
        wine_tsx11_lock();
        XSaveContext( gdi_display, (XID)hbitmap, bitmap_context, (char *)ret );
        wine_tsx11_unlock();
472
    }
473 474 475 476 477 478 479 480 481 482 483
    return ret;
}


/***********************************************************************
 *           X11DRV_get_pixmap
 *
 * Retrieve the pixmap associated to a bitmap.
 */
Pixmap X11DRV_get_pixmap( HBITMAP hbitmap )
{
484 485 486 487
    X_PHYSBITMAP *physBitmap = X11DRV_get_phys_bitmap( hbitmap );

    if (!physBitmap) return 0;
    return physBitmap->pixmap;
488
}