graphics.c 46.4 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * X11 graphics driver graphics functions
 *
 * Copyright 1993,1994 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
21
/*
22
 * FIXME: only some of these functions obey the GM_ADVANCED
Alexandre Julliard's avatar
Alexandre Julliard committed
23 24 25
 * graphics mode
 */

Patrik Stridvall's avatar
Patrik Stridvall committed
26 27
#include "config.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include <math.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
29 30
#ifdef HAVE_FLOAT_H
# include <float.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
31
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
32 33 34 35 36 37 38
#include <stdlib.h>
#ifndef PI
#define PI M_PI
#endif
#include <string.h>

#include "x11drv.h"
39
#include "x11font.h"
40
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
41

42
WINE_DEFAULT_DEBUG_CHANNEL(graphics);
43

Alexandre Julliard's avatar
Alexandre Julliard committed
44
#define ABS(x)    ((x)<0?(-(x)):(x))
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

  /* ROP code to GC function conversion */
const int X11DRV_XROPfunction[16] =
{
    GXclear,        /* R2_BLACK */
    GXnor,          /* R2_NOTMERGEPEN */
    GXandInverted,  /* R2_MASKNOTPEN */
    GXcopyInverted, /* R2_NOTCOPYPEN */
    GXandReverse,   /* R2_MASKPENNOT */
    GXinvert,       /* R2_NOT */
    GXxor,          /* R2_XORPEN */
    GXnand,         /* R2_NOTMASKPEN */
    GXand,          /* R2_MASKPEN */
    GXequiv,        /* R2_NOTXORPEN */
    GXnoop,         /* R2_NOP */
    GXorInverted,   /* R2_MERGENOTPEN */
    GXcopy,         /* R2_COPYPEN */
    GXorReverse,    /* R2_MERGEPENNOT */
    GXor,           /* R2_MERGEPEN */
    GXset           /* R2_WHITE */
};


/***********************************************************************
 *           X11DRV_SetupGCForPatBlt
 *
 * Setup the GC for a PatBlt operation using current brush.
 * If fMapColors is TRUE, X pixels are mapped to Windows colors.
 * Return FALSE if brush is BS_NULL, TRUE otherwise.
 */
75
BOOL X11DRV_SetupGCForPatBlt( X11DRV_PDEVICE *physDev, GC gc, BOOL fMapColors )
76 77 78 79
{
    XGCValues val;
    unsigned long mask;
    Pixmap pixmap = 0;
80
    POINT pt;
81

82 83
    if (physDev->brush.style == BS_NULL) return FALSE;
    if (physDev->brush.pixel == -1)
84 85 86 87 88
    {
	/* Special case used for monochrome pattern brushes.
	 * We need to swap foreground and background because
	 * Windows does it the wrong way...
	 */
89 90
	val.foreground = physDev->backgroundPixel;
	val.background = physDev->textPixel;
91 92 93
    }
    else
    {
94 95
	val.foreground = physDev->brush.pixel;
	val.background = physDev->backgroundPixel;
96
    }
97
    if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
98
    {
99 100
        val.foreground = X11DRV_PALETTE_XPixelToPalette[val.foreground];
        val.background = X11DRV_PALETTE_XPixelToPalette[val.background];
101 102
    }

103
    val.function = X11DRV_XROPfunction[GetROP2(physDev->hdc)-1];
104 105 106 107 108 109
    /*
    ** Let's replace GXinvert by GXxor with (black xor white)
    ** This solves the selection color and leak problems in excel
    ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
    */
    if (val.function == GXinvert)
110 111 112
    {
        val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
                          BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
113
	val.function = GXxor;
114
    }
115
    val.fill_style = physDev->brush.fillStyle;
116 117 118 119
    switch(val.fill_style)
    {
    case FillStippled:
    case FillOpaqueStippled:
120
	if (GetBkMode(physDev->hdc)==OPAQUE) val.fill_style = FillOpaqueStippled;
121
	val.stipple = physDev->brush.pixmap;
122 123 124 125
	mask = GCStipple;
        break;

    case FillTiled:
126
        if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
127 128 129
        {
            register int x, y;
            XImage *image;
130
            wine_tsx11_lock();
131 132
            pixmap = XCreatePixmap( gdi_display, root_window, 8, 8, screen_depth );
            image = XGetImage( gdi_display, physDev->brush.pixmap, 0, 0, 8, 8,
133 134 135 136
                               AllPlanes, ZPixmap );
            for (y = 0; y < 8; y++)
                for (x = 0; x < 8; x++)
                    XPutPixel( image, x, y,
137
                               X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] );
138
            XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
139
            XDestroyImage( image );
140
            wine_tsx11_unlock();
141 142
            val.tile = pixmap;
        }
143
        else val.tile = physDev->brush.pixmap;
144 145 146 147 148 149 150
	mask = GCTile;
        break;

    default:
        mask = 0;
        break;
    }
151
    GetBrushOrgEx( physDev->hdc, &pt );
152 153
    val.ts_x_origin = physDev->dc_rect.left + pt.x;
    val.ts_y_origin = physDev->dc_rect.top + pt.y;
154
    val.fill_rule = (GetPolyFillMode(physDev->hdc) == WINDING) ? WindingRule : EvenOddRule;
155 156
    wine_tsx11_lock();
    XChangeGC( gdi_display, gc,
157 158 159
	       GCFunction | GCForeground | GCBackground | GCFillStyle |
	       GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
	       &val );
160 161
    if (pixmap) XFreePixmap( gdi_display, pixmap );
    wine_tsx11_unlock();
162 163 164 165 166 167 168
    return TRUE;
}


/***********************************************************************
 *           X11DRV_SetupGCForBrush
 *
169
 * Setup physDev->gc for drawing operations using current brush.
170 171
 * Return FALSE if brush is BS_NULL, TRUE otherwise.
 */
172
BOOL X11DRV_SetupGCForBrush( X11DRV_PDEVICE *physDev )
173
{
174
    return X11DRV_SetupGCForPatBlt( physDev, physDev->gc, FALSE );
175 176 177 178 179 180
}


/***********************************************************************
 *           X11DRV_SetupGCForPen
 *
181
 * Setup physDev->gc for drawing operations using current pen.
182 183
 * Return FALSE if pen is PS_NULL, TRUE otherwise.
 */
184
BOOL X11DRV_SetupGCForPen( X11DRV_PDEVICE *physDev )
185 186
{
    XGCValues val;
187
    UINT rop2 = GetROP2(physDev->hdc);
188

189
    if (physDev->pen.style == PS_NULL) return FALSE;
190

191
    switch (rop2)
192 193
    {
    case R2_BLACK :
194
        val.foreground = BlackPixel( gdi_display, DefaultScreen(gdi_display) );
195 196 197
	val.function = GXcopy;
	break;
    case R2_WHITE :
198
        val.foreground = WhitePixel( gdi_display, DefaultScreen(gdi_display) );
199 200 201
	val.function = GXcopy;
	break;
    case R2_XORPEN :
202
	val.foreground = physDev->pen.pixel;
203 204 205
	/* It is very unlikely someone wants to XOR with 0 */
	/* This fixes the rubber-drawings in paintbrush */
	if (val.foreground == 0)
206 207
            val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
                              BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
208 209 210
	val.function = GXxor;
	break;
    default :
211
	val.foreground = physDev->pen.pixel;
212
	val.function   = X11DRV_XROPfunction[rop2-1];
213
    }
214
    val.background = physDev->backgroundPixel;
215
    val.fill_style = FillSolid;
216
    val.line_width = physDev->pen.width;
217 218 219
    if (val.line_width <= 1) {
	val.cap_style = CapNotLast;
    } else {
220
	switch (physDev->pen.endcap)
221 222 223 224 225 226 227 228 229 230 231 232
	{
	case PS_ENDCAP_SQUARE:
	    val.cap_style = CapProjecting;
	    break;
	case PS_ENDCAP_FLAT:
	    val.cap_style = CapButt;
	    break;
	case PS_ENDCAP_ROUND:
	default:
	    val.cap_style = CapRound;
	}
    }
233
    switch (physDev->pen.linejoin)
234 235 236 237 238 239 240 241 242 243 244
    {
    case PS_JOIN_BEVEL:
	val.join_style = JoinBevel;
        break;
    case PS_JOIN_MITER:
	val.join_style = JoinMiter;
        break;
    case PS_JOIN_ROUND:
    default:
	val.join_style = JoinRound;
    }
245

246 247 248
    if (physDev->pen.dash_len)
        val.line_style = ((GetBkMode(physDev->hdc) == OPAQUE) && (!physDev->pen.ext))
                         ? LineDoubleDash : LineOnOffDash;
249 250
    else
        val.line_style = LineSolid;
251

252 253 254
    wine_tsx11_lock();
    if (physDev->pen.dash_len)
        XSetDashes( gdi_display, physDev->gc, 0, physDev->pen.dashes, physDev->pen.dash_len );
255
    XChangeGC( gdi_display, physDev->gc,
256 257
	       GCFunction | GCForeground | GCBackground | GCLineWidth |
	       GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
258
    wine_tsx11_unlock();
259 260 261 262 263 264 265
    return TRUE;
}


/***********************************************************************
 *           X11DRV_SetupGCForText
 *
266
 * Setup physDev->gc for text drawing operations.
267 268
 * Return FALSE if the font is null, TRUE otherwise.
 */
269
BOOL X11DRV_SetupGCForText( X11DRV_PDEVICE *physDev )
270
{
271
    XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
272 273 274 275 276 277

    if( xfs )
    {
	XGCValues val;

	val.function   = GXcopy;  /* Text is always GXcopy */
278 279
	val.foreground = physDev->textPixel;
	val.background = physDev->backgroundPixel;
280 281 282
	val.fill_style = FillSolid;
	val.font       = xfs->fid;

283 284
        wine_tsx11_lock();
        XChangeGC( gdi_display, physDev->gc,
285 286
		   GCFunction | GCForeground | GCBackground | GCFillStyle |
		   GCFont, &val );
287
        wine_tsx11_unlock();
288
	return TRUE;
289
    }
290
    WARN("Physical font failure\n" );
291 292 293
    return FALSE;
}

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
/***********************************************************************
 *           X11DRV_XWStoDS
 *
 * Performs a world-to-viewport transformation on the specified width.
 */
INT X11DRV_XWStoDS( X11DRV_PDEVICE *physDev, INT width )
{
    POINT pt[2];

    pt[0].x = 0;
    pt[0].y = 0;
    pt[1].x = width;
    pt[1].y = 0;
    LPtoDP( physDev->hdc, pt, 2 );
    return pt[1].x - pt[0].x;
}

/***********************************************************************
 *           X11DRV_YWStoDS
 *
 * Performs a world-to-viewport transformation on the specified height.
 */
INT X11DRV_YWStoDS( X11DRV_PDEVICE *physDev, INT height )
{
    POINT pt[2];

    pt[0].x = 0;
    pt[0].y = 0;
    pt[1].x = 0;
    pt[1].y = height;
    LPtoDP( physDev->hdc, pt, 2 );
    return pt[1].y - pt[0].y;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
328 329 330
/***********************************************************************
 *           X11DRV_LineTo
 */
331
BOOL
332
X11DRV_LineTo( X11DRV_PDEVICE *physDev, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
333
{
334
    POINT pt[2];
335

336
    if (X11DRV_SetupGCForPen( physDev )) {
337
	/* Update the pixmap from the DIB section */
338
	X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
339

340 341 342 343
        GetCurrentPositionEx( physDev->hdc, &pt[0] );
        pt[1].x = x;
        pt[1].y = y;
        LPtoDP( physDev->hdc, pt, 2 );
344

345 346
        wine_tsx11_lock();
        XDrawLine(gdi_display, physDev->drawable, physDev->gc,
347 348
                  physDev->dc_rect.left + pt[0].x, physDev->dc_rect.top + pt[0].y,
                  physDev->dc_rect.left + pt[1].x, physDev->dc_rect.top + pt[1].y );
349
        wine_tsx11_unlock();
350

351
	/* Update the DIBSection from the pixmap */
352
	X11DRV_UnlockDIBSection(physDev, TRUE);
353
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
354 355 356 357 358 359
    return TRUE;
}



/***********************************************************************
360
 *           X11DRV_DrawArc
Alexandre Julliard's avatar
Alexandre Julliard committed
361 362 363
 *
 * Helper functions for Arc(), Chord() and Pie().
 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
Alexandre Julliard's avatar
Alexandre Julliard committed
364
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
365
 */
366
static BOOL
367
X11DRV_DrawArc( X11DRV_PDEVICE *physDev, INT left, INT top, INT right,
368 369
                INT bottom, INT xstart, INT ystart,
                INT xend, INT yend, INT lines )
Alexandre Julliard's avatar
Alexandre Julliard committed
370
{
371
    INT xcenter, ycenter, istart_angle, idiff_angle;
372
    INT width, oldwidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
373
    double start_angle, end_angle;
Alexandre Julliard's avatar
Alexandre Julliard committed
374
    XPoint points[4];
375
    BOOL update = FALSE;
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
    POINT start, end;
    RECT rc;

    SetRect(&rc, left, top, right, bottom);
    start.x = xstart;
    start.y = ystart;
    end.x = xend;
    end.y = yend;
    LPtoDP(physDev->hdc, (POINT*)&rc, 2);
    LPtoDP(physDev->hdc, &start, 1);
    LPtoDP(physDev->hdc, &end, 1);

    if (rc.right < rc.left) { INT tmp = rc.right; rc.right = rc.left; rc.left = tmp; }
    if (rc.bottom < rc.top) { INT tmp = rc.bottom; rc.bottom = rc.top; rc.top = tmp; }
    if ((rc.left == rc.right) || (rc.top == rc.bottom)
            ||(lines && ((rc.right-rc.left==1)||(rc.bottom-rc.top==1)))) return TRUE;

    if (GetArcDirection( physDev->hdc ) == AD_CLOCKWISE)
      { POINT tmp = start; start = end; end = tmp; }
395

396
    oldwidth = width = physDev->pen.width;
Alexandre Julliard's avatar
Alexandre Julliard committed
397
    if (!width) width = 1;
398
    if(physDev->pen.style == PS_NULL) width = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
399

400
    if ((physDev->pen.style == PS_INSIDEFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
401
    {
402 403 404 405 406 407
        if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
        if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
        rc.left   += width / 2;
        rc.right  -= (width - 1) / 2;
        rc.top    += width / 2;
        rc.bottom -= (width - 1) / 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
408
    }
409 410
    if(width == 0) width = 1; /* more accurate */
    physDev->pen.width = width;
Alexandre Julliard's avatar
Alexandre Julliard committed
411

412 413 414 415 416 417 418
    xcenter = (rc.right + rc.left) / 2;
    ycenter = (rc.bottom + rc.top) / 2;
    start_angle = atan2( (double)(ycenter-start.y)*(rc.right-rc.left),
			 (double)(start.x-xcenter)*(rc.bottom-rc.top) );
    end_angle   = atan2( (double)(ycenter-end.y)*(rc.right-rc.left),
			 (double)(end.x-xcenter)*(rc.bottom-rc.top) );
    if ((start.x==end.x)&&(start.y==end.y))
Alexandre Julliard's avatar
Alexandre Julliard committed
419 420 421 422 423 424 425 426 427 428
      { /* A lazy program delivers xstart=xend=ystart=yend=0) */
	start_angle = 0;
	end_angle = 2* PI;
      }
    else /* notorious cases */
      if ((start_angle == PI)&&( end_angle <0))
	start_angle = - PI;
    else
      if ((end_angle == PI)&&( start_angle <0))
	end_angle = - PI;
429 430
    istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
    idiff_angle  = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
Alexandre Julliard's avatar
Alexandre Julliard committed
431
    if (idiff_angle <= 0) idiff_angle += 360 * 64;
Alexandre Julliard's avatar
Alexandre Julliard committed
432

433
    /* Update the pixmap from the DIB section */
434
    X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
435

Alexandre Julliard's avatar
Alexandre Julliard committed
436 437
      /* Fill arc with brush if Chord() or Pie() */

438
    if ((lines > 0) && X11DRV_SetupGCForBrush( physDev )) {
439 440 441
        wine_tsx11_lock();
        XSetArcMode( gdi_display, physDev->gc, (lines==1) ? ArcChord : ArcPieSlice);
        XFillArc( gdi_display, physDev->drawable, physDev->gc,
442
                  physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
443 444
                  rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
        wine_tsx11_unlock();
445
	update = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
446 447 448 449
    }

      /* Draw arc and lines */

450 451 452 453
    if (X11DRV_SetupGCForPen( physDev ))
    {
        wine_tsx11_lock();
        XDrawArc( gdi_display, physDev->drawable, physDev->gc,
454
                  physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
455
                  rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
Alexandre Julliard's avatar
Alexandre Julliard committed
456 457 458 459 460
        if (lines) {
            /* use the truncated values */
            start_angle=(double)istart_angle*PI/64./180.;
            end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
            /* calculate the endpoints and round correctly */
461
            points[0].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
462
                    cos(start_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
463
            points[0].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
464
                    sin(start_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
465
            points[1].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
466
                    cos(end_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
467
            points[1].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
468
                    sin(end_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
469 470

            /* OK, this stuff is optimized for Xfree86
471
             * which is probably the server most used by
472
             * wine users. Other X servers will not
Alexandre Julliard's avatar
Alexandre Julliard committed
473
             * display correctly. (eXceed for instance)
474
             * so if you feel you must make changes, make sure that
475
             * you either use Xfree86 or separate your changes
Alexandre Julliard's avatar
Alexandre Julliard committed
476 477 478
             * from these (compile switch or whatever)
             */
            if (lines == 2) {
479
                INT dx1,dy1;
Alexandre Julliard's avatar
Alexandre Julliard committed
480
                points[3] = points[1];
481 482
                points[1].x = physDev->dc_rect.left + xcenter;
                points[1].y = physDev->dc_rect.top + ycenter;
Alexandre Julliard's avatar
Alexandre Julliard committed
483 484 485
                points[2] = points[1];
                dx1=points[1].x-points[0].x;
                dy1=points[1].y-points[0].y;
486
                if(((rc.top-rc.bottom) | -2) == -2)
Alexandre Julliard's avatar
Alexandre Julliard committed
487 488 489 490 491 492 493
                    if(dy1>0) points[1].y--;
                if(dx1<0) {
                    if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
                    if(((-dx1*9))<(dy1*16)) points[0].y--;
                    if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
                } else {
                    if(dy1 < 0)  points[0].y--;
494
                    if(((rc.right-rc.left) | -2) == -2) points[1].x--;
Alexandre Julliard's avatar
Alexandre Julliard committed
495 496 497
                }
                dx1=points[3].x-points[2].x;
                dy1=points[3].y-points[2].y;
498
                if(((rc.top-rc.bottom) | -2 ) == -2)
Alexandre Julliard's avatar
Alexandre Julliard committed
499
                    if(dy1 < 0) points[2].y--;
500
                if( dx1<0){
Alexandre Julliard's avatar
Alexandre Julliard committed
501
                    if( dy1>0) points[3].y--;
502
                    if(((rc.right-rc.left) | -2) == -2 ) points[2].x--;
Alexandre Julliard's avatar
Alexandre Julliard committed
503 504 505 506 507
                }else {
                    points[3].y--;
                    if( dx1 * 64 < dy1 * -37 ) points[3].x--;
                }
                lines++;
508
	    }
509 510
            XDrawLines( gdi_display, physDev->drawable, physDev->gc,
                        points, lines+1, CoordModeOrigin );
Alexandre Julliard's avatar
Alexandre Julliard committed
511
        }
512
        wine_tsx11_unlock();
513
	update = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
514
    }
515 516

    /* Update the DIBSection of the pixmap */
517
    X11DRV_UnlockDIBSection(physDev, update);
518

519
    physDev->pen.width = oldwidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
520 521 522 523 524 525 526
    return TRUE;
}


/***********************************************************************
 *           X11DRV_Arc
 */
527
BOOL
528
X11DRV_Arc( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
529
            INT xstart, INT ystart, INT xend, INT yend )
Alexandre Julliard's avatar
Alexandre Julliard committed
530
{
531
    return X11DRV_DrawArc( physDev, left, top, right, bottom,
Alexandre Julliard's avatar
Alexandre Julliard committed
532 533 534 535 536 537 538
			   xstart, ystart, xend, yend, 0 );
}


/***********************************************************************
 *           X11DRV_Pie
 */
539
BOOL
540
X11DRV_Pie( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
541
            INT xstart, INT ystart, INT xend, INT yend )
Alexandre Julliard's avatar
Alexandre Julliard committed
542
{
543
    return X11DRV_DrawArc( physDev, left, top, right, bottom,
Alexandre Julliard's avatar
Alexandre Julliard committed
544 545 546 547 548 549
			   xstart, ystart, xend, yend, 2 );
}

/***********************************************************************
 *           X11DRV_Chord
 */
550
BOOL
551
X11DRV_Chord( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
552
              INT xstart, INT ystart, INT xend, INT yend )
Alexandre Julliard's avatar
Alexandre Julliard committed
553
{
554
    return X11DRV_DrawArc( physDev, left, top, right, bottom,
Alexandre Julliard's avatar
Alexandre Julliard committed
555 556 557 558 559 560 561
		  	   xstart, ystart, xend, yend, 1 );
}


/***********************************************************************
 *           X11DRV_Ellipse
 */
562
BOOL
563
X11DRV_Ellipse( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom )
Alexandre Julliard's avatar
Alexandre Julliard committed
564
{
565
    INT width, oldwidth;
566
    BOOL update = FALSE;
567 568 569 570
    RECT rc;

    SetRect(&rc, left, top, right, bottom);
    LPtoDP(physDev->hdc, (POINT*)&rc, 2);
571

572
    if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
573

574 575
    if (rc.right < rc.left) { INT tmp = rc.right; rc.right = rc.left; rc.left = tmp; }
    if (rc.bottom < rc.top) { INT tmp = rc.bottom; rc.bottom = rc.top; rc.top = tmp; }
576

577
    oldwidth = width = physDev->pen.width;
Alexandre Julliard's avatar
Alexandre Julliard committed
578
    if (!width) width = 1;
579
    if(physDev->pen.style == PS_NULL) width = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
580

581
    if ((physDev->pen.style == PS_INSIDEFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
582
    {
583 584 585 586 587 588
        if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
        if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
        rc.left   += width / 2;
        rc.right  -= (width - 1) / 2;
        rc.top    += width / 2;
        rc.bottom -= (width - 1) / 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
589
    }
590 591
    if(width == 0) width = 1; /* more accurate */
    physDev->pen.width = width;
Alexandre Julliard's avatar
Alexandre Julliard committed
592

593
    /* Update the pixmap from the DIB section */
594
    X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
595

596
    if (X11DRV_SetupGCForBrush( physDev ))
597
    {
598 599
        wine_tsx11_lock();
        XFillArc( gdi_display, physDev->drawable, physDev->gc,
600
                  physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
601 602
                  rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
        wine_tsx11_unlock();
603 604
	update = TRUE;
    }
605
    if (X11DRV_SetupGCForPen( physDev ))
606
    {
607 608
        wine_tsx11_lock();
        XDrawArc( gdi_display, physDev->drawable, physDev->gc,
609
                  physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
610 611
                  rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
        wine_tsx11_unlock();
612 613 614 615
	update = TRUE;
    }

    /* Update the DIBSection from the pixmap */
616
    X11DRV_UnlockDIBSection(physDev, update);
617

618
    physDev->pen.width = oldwidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
619 620 621 622 623 624 625
    return TRUE;
}


/***********************************************************************
 *           X11DRV_Rectangle
 */
626
BOOL
627
X11DRV_Rectangle(X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom)
Alexandre Julliard's avatar
Alexandre Julliard committed
628
{
629
    INT width, oldwidth, oldjoinstyle;
630
    BOOL update = FALSE;
631
    RECT rc;
Alexandre Julliard's avatar
Alexandre Julliard committed
632

633
    TRACE("(%d %d %d %d)\n", left, top, right, bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
634

635 636
    SetRect(&rc, left, top, right, bottom);
    LPtoDP(physDev->hdc, (POINT*)&rc, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
637

638
    if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
639

640 641
    if (rc.right < rc.left) { INT tmp = rc.right; rc.right = rc.left; rc.left = tmp; }
    if (rc.bottom < rc.top) { INT tmp = rc.bottom; rc.bottom = rc.top; rc.top = tmp; }
Alexandre Julliard's avatar
Alexandre Julliard committed
642

643
    oldwidth = width = physDev->pen.width;
Alexandre Julliard's avatar
Alexandre Julliard committed
644
    if (!width) width = 1;
645
    if(physDev->pen.style == PS_NULL) width = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
646

647
    if ((physDev->pen.style == PS_INSIDEFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
648
    {
649 650 651 652 653 654
        if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
        if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
        rc.left   += width / 2;
        rc.right  -= (width - 1) / 2;
        rc.top    += width / 2;
        rc.bottom -= (width - 1) / 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
655
    }
656 657 658 659 660
    if(width == 1) width = 0;
    physDev->pen.width = width;
    oldjoinstyle = physDev->pen.linejoin;
    if(physDev->pen.type != PS_GEOMETRIC)
        physDev->pen.linejoin = PS_JOIN_MITER;
Alexandre Julliard's avatar
Alexandre Julliard committed
661

662
    /* Update the pixmap from the DIB section */
663
    X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
664

665 666
    if ((rc.right > rc.left + width) && (rc.bottom > rc.top + width))
    {
667
        if (X11DRV_SetupGCForBrush( physDev ))
668
	{
669 670
            wine_tsx11_lock();
            XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
671 672
                            physDev->dc_rect.left + rc.left + (width + 1) / 2,
                            physDev->dc_rect.top + rc.top + (width + 1) / 2,
673 674
                            rc.right-rc.left-width-1, rc.bottom-rc.top-width-1);
            wine_tsx11_unlock();
675 676
	    update = TRUE;
	}
677
    }
678
    if (X11DRV_SetupGCForPen( physDev ))
679
    {
680 681
        wine_tsx11_lock();
        XDrawRectangle( gdi_display, physDev->drawable, physDev->gc,
682
                        physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
683 684
                        rc.right-rc.left-1, rc.bottom-rc.top-1 );
        wine_tsx11_unlock();
685 686
	update = TRUE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
687

688
    /* Update the DIBSection from the pixmap */
689
    X11DRV_UnlockDIBSection(physDev, update);
690

691 692
    physDev->pen.width = oldwidth;
    physDev->pen.linejoin = oldjoinstyle;
Alexandre Julliard's avatar
Alexandre Julliard committed
693 694 695 696 697 698
    return TRUE;
}

/***********************************************************************
 *           X11DRV_RoundRect
 */
699
BOOL
700
X11DRV_RoundRect( X11DRV_PDEVICE *physDev, INT left, INT top, INT right,
701
                  INT bottom, INT ell_width, INT ell_height )
Alexandre Julliard's avatar
Alexandre Julliard committed
702
{
703
    INT width, oldwidth, oldendcap;
704
    BOOL update = FALSE;
705 706
    RECT rc;
    POINT pts[2];
Alexandre Julliard's avatar
Alexandre Julliard committed
707

708
    TRACE("(%d %d %d %d  %d %d\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
709 710
    	left, top, right, bottom, ell_width, ell_height);

711 712
    SetRect(&rc, left, top, right, bottom);
    LPtoDP(physDev->hdc, (POINT*)&rc, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
713

714
    if ((rc.left == rc.right) || (rc.top == rc.bottom))
Alexandre Julliard's avatar
Alexandre Julliard committed
715 716
	return TRUE;

717 718
    /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
       called with width/height < 0 */
719 720 721 722 723 724
    pts[0].x = pts[0].y = 0;
    pts[1].x = ell_width;
    pts[1].y = ell_height;
    LPtoDP(physDev->hdc, pts, 2);
    ell_width  = max(abs( pts[1].x - pts[0].x ), 1);
    ell_height = max(abs( pts[1].y - pts[0].y ), 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
725 726 727

    /* Fix the coordinates */

728 729
    if (rc.right < rc.left) { INT tmp = rc.right; rc.right = rc.left; rc.left = tmp; }
    if (rc.bottom < rc.top) { INT tmp = rc.bottom; rc.bottom = rc.top; rc.top = tmp; }
Alexandre Julliard's avatar
Alexandre Julliard committed
730

731 732
    oldwidth = width = physDev->pen.width;
    oldendcap = physDev->pen.endcap;
Alexandre Julliard's avatar
Alexandre Julliard committed
733
    if (!width) width = 1;
734
    if(physDev->pen.style == PS_NULL) width = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
735

736
    if ((physDev->pen.style == PS_INSIDEFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
737
    {
738 739 740 741 742 743
        if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
        if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
        rc.left   += width / 2;
        rc.right  -= (width - 1) / 2;
        rc.top    += width / 2;
        rc.bottom -= (width - 1) / 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
744
    }
745 746 747
    if(width == 0) width = 1;
    physDev->pen.width = width;
    physDev->pen.endcap = PS_ENDCAP_SQUARE;
Alexandre Julliard's avatar
Alexandre Julliard committed
748

749
    /* Update the pixmap from the DIB section */
750
    X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
751

752
    if (X11DRV_SetupGCForBrush( physDev ))
Alexandre Julliard's avatar
Alexandre Julliard committed
753
    {
754
        wine_tsx11_lock();
755 756
        if (ell_width > (rc.right-rc.left) )
            if (ell_height > (rc.bottom-rc.top) )
757
                XFillArc( gdi_display, physDev->drawable, physDev->gc,
758
                          physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
759
                          rc.right - rc.left - 1, rc.bottom - rc.top - 1,
760
                          0, 360 * 64 );
Alexandre Julliard's avatar
Alexandre Julliard committed
761
            else{
762
                XFillArc( gdi_display, physDev->drawable, physDev->gc,
763
                          physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
764
                          rc.right - rc.left - 1, ell_height, 0, 180 * 64 );
765
                XFillArc( gdi_display, physDev->drawable, physDev->gc,
766 767
                          physDev->dc_rect.left + rc.left,
                          physDev->dc_rect.top + rc.bottom - ell_height - 1,
768
                          rc.right - rc.left - 1, ell_height, 180 * 64,
769 770
                          180 * 64 );
            }
771
	else if (ell_height > (rc.bottom-rc.top) ){
772
            XFillArc( gdi_display, physDev->drawable, physDev->gc,
773
                      physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
774
                      ell_width, rc.bottom - rc.top - 1, 90 * 64, 180 * 64 );
775
            XFillArc( gdi_display, physDev->drawable, physDev->gc,
776
                      physDev->dc_rect.left + rc.right - ell_width - 1, physDev->dc_rect.top + rc.top,
777
                      ell_width, rc.bottom - rc.top - 1, 270 * 64, 180 * 64 );
Alexandre Julliard's avatar
Alexandre Julliard committed
778
        }else{
779
            XFillArc( gdi_display, physDev->drawable, physDev->gc,
780
                      physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
781
                      ell_width, ell_height, 90 * 64, 90 * 64 );
782
            XFillArc( gdi_display, physDev->drawable, physDev->gc,
783 784
                      physDev->dc_rect.left + rc.left,
                      physDev->dc_rect.top + rc.bottom - ell_height - 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
785
                      ell_width, ell_height, 180 * 64, 90 * 64 );
786
            XFillArc( gdi_display, physDev->drawable, physDev->gc,
787 788
                      physDev->dc_rect.left + rc.right - ell_width - 1,
                      physDev->dc_rect.top + rc.bottom - ell_height - 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
789
                      ell_width, ell_height, 270 * 64, 90 * 64 );
790
            XFillArc( gdi_display, physDev->drawable, physDev->gc,
791 792
                      physDev->dc_rect.left + rc.right - ell_width - 1,
                      physDev->dc_rect.top + rc.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
793 794
                      ell_width, ell_height, 0, 90 * 64 );
        }
795
        if (ell_width < rc.right - rc.left)
Alexandre Julliard's avatar
Alexandre Julliard committed
796
        {
797
            XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
798 799
                            physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
                            physDev->dc_rect.top + rc.top + 1,
800
                            rc.right - rc.left - ell_width - 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
801
                            (ell_height + 1) / 2 - 1);
802
            XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
803 804
                            physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
                            physDev->dc_rect.top + rc.bottom - (ell_height) / 2 - 1,
805
                            rc.right - rc.left - ell_width - 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
806
                            (ell_height) / 2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
807
        }
808
        if  (ell_height < rc.bottom - rc.top)
Alexandre Julliard's avatar
Alexandre Julliard committed
809
        {
810
            XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
811 812
                            physDev->dc_rect.left + rc.left + 1,
                            physDev->dc_rect.top + rc.top + (ell_height + 1) / 2,
813 814
                            rc.right - rc.left - 2,
                            rc.bottom - rc.top - ell_height - 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
815
        }
816
        wine_tsx11_unlock();
817
	update = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
818
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
819 820 821 822 823 824 825 826 827
    /* FIXME: this could be done with on X call
     * more efficient and probably more correct
     * on any X server: XDrawArcs will draw
     * straight horizontal and vertical lines
     * if width or height are zero.
     *
     * BTW this stuff is optimized for an Xfree86 server
     * read the comments inside the X11DRV_DrawArc function
     */
828 829
    if (X11DRV_SetupGCForPen( physDev ))
    {
830
        wine_tsx11_lock();
831 832
        if (ell_width > (rc.right-rc.left) )
            if (ell_height > (rc.bottom-rc.top) )
833
                XDrawArc( gdi_display, physDev->drawable, physDev->gc,
834
                          physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
835
                          rc.right - rc.left - 1, rc.bottom - rc.top - 1, 0 , 360 * 64 );
Alexandre Julliard's avatar
Alexandre Julliard committed
836
            else{
837
                XDrawArc( gdi_display, physDev->drawable, physDev->gc,
838
                          physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
839
                          rc.right - rc.left - 1, ell_height - 1, 0 , 180 * 64 );
840
                XDrawArc( gdi_display, physDev->drawable, physDev->gc,
841 842
                          physDev->dc_rect.left + rc.left,
                          physDev->dc_rect.top + rc.bottom - ell_height,
843
                          rc.right - rc.left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
Alexandre Julliard's avatar
Alexandre Julliard committed
844
            }
845
	else if (ell_height > (rc.bottom-rc.top) ){
846
            XDrawArc( gdi_display, physDev->drawable, physDev->gc,
847
                      physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
848
                      ell_width - 1 , rc.bottom - rc.top - 1, 90 * 64 , 180 * 64 );
849
            XDrawArc( gdi_display, physDev->drawable, physDev->gc,
850 851
                      physDev->dc_rect.left + rc.right - ell_width,
                      physDev->dc_rect.top + rc.top,
852
                      ell_width - 1 , rc.bottom - rc.top - 1, 270 * 64 , 180 * 64 );
Alexandre Julliard's avatar
Alexandre Julliard committed
853
	}else{
854
            XDrawArc( gdi_display, physDev->drawable, physDev->gc,
855
                      physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
856
                      ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
857
            XDrawArc( gdi_display, physDev->drawable, physDev->gc,
858
                      physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.bottom - ell_height,
Alexandre Julliard's avatar
Alexandre Julliard committed
859
                      ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
860
            XDrawArc( gdi_display, physDev->drawable, physDev->gc,
861 862
                      physDev->dc_rect.left + rc.right - ell_width,
                      physDev->dc_rect.top + rc.bottom - ell_height,
Alexandre Julliard's avatar
Alexandre Julliard committed
863
                      ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
864
            XDrawArc( gdi_display, physDev->drawable, physDev->gc,
865
                      physDev->dc_rect.left + rc.right - ell_width, physDev->dc_rect.top + rc.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
866 867
                      ell_width - 1, ell_height - 1, 0, 90 * 64 );
	}
868
	if (ell_width < rc.right - rc.left)
Alexandre Julliard's avatar
Alexandre Julliard committed
869
	{
870
            XDrawLine( gdi_display, physDev->drawable, physDev->gc,
871 872 873 874
                       physDev->dc_rect.left + rc.left + ell_width / 2,
                       physDev->dc_rect.top + rc.top,
                       physDev->dc_rect.left + rc.right - (ell_width+1) / 2,
                       physDev->dc_rect.top + rc.top);
875
            XDrawLine( gdi_display, physDev->drawable, physDev->gc,
876 877 878 879
                       physDev->dc_rect.left + rc.left + ell_width / 2 ,
                       physDev->dc_rect.top + rc.bottom - 1,
                       physDev->dc_rect.left + rc.right - (ell_width+1)/ 2,
                       physDev->dc_rect.top + rc.bottom - 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
880
	}
881
	if (ell_height < rc.bottom - rc.top)
Alexandre Julliard's avatar
Alexandre Julliard committed
882
	{
883
            XDrawLine( gdi_display, physDev->drawable, physDev->gc,
884 885 886 887
                       physDev->dc_rect.left + rc.right - 1,
                       physDev->dc_rect.top + rc.top + ell_height / 2,
                       physDev->dc_rect.left + rc.right - 1,
                       physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
888
            XDrawLine( gdi_display, physDev->drawable, physDev->gc,
889 890 891 892
                       physDev->dc_rect.left + rc.left,
                       physDev->dc_rect.top + rc.top + ell_height / 2,
                       physDev->dc_rect.left + rc.left,
                       physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
893
	}
894
        wine_tsx11_unlock();
895
	update = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
896
    }
897
    /* Update the DIBSection from the pixmap */
898
    X11DRV_UnlockDIBSection(physDev, update);
899

900 901
    physDev->pen.width = oldwidth;
    physDev->pen.endcap = oldendcap;
Alexandre Julliard's avatar
Alexandre Julliard committed
902 903 904 905 906 907 908 909
    return TRUE;
}


/***********************************************************************
 *           X11DRV_SetPixel
 */
COLORREF
910
X11DRV_SetPixel( X11DRV_PDEVICE *physDev, INT x, INT y, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
911
{
912
    unsigned long pixel;
913
    POINT pt;
914

915 916 917
    pt.x = x;
    pt.y = y;
    LPtoDP( physDev->hdc, &pt, 1 );
918
    pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
919 920

    /* Update the pixmap from the DIB section */
921
    X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
922 923

    /* inefficient but simple... */
924 925 926
    wine_tsx11_lock();
    XSetForeground( gdi_display, physDev->gc, pixel );
    XSetFunction( gdi_display, physDev->gc, GXcopy );
927
    XDrawPoint( gdi_display, physDev->drawable, physDev->gc,
928
                physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y );
929
    wine_tsx11_unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
930

931
    /* Update the DIBSection from the pixmap */
932
    X11DRV_UnlockDIBSection(physDev, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
933

934
    return X11DRV_PALETTE_ToLogical(pixel);
Alexandre Julliard's avatar
Alexandre Julliard committed
935 936 937 938 939 940 941
}


/***********************************************************************
 *           X11DRV_GetPixel
 */
COLORREF
942
X11DRV_GetPixel( X11DRV_PDEVICE *physDev, INT x, INT y )
Alexandre Julliard's avatar
Alexandre Julliard committed
943 944 945 946
{
    static Pixmap pixmap = 0;
    XImage * image;
    int pixel;
947
    POINT pt;
948
    BOOL memdc = (GetObjectType(physDev->hdc) == OBJ_MEMDC);
Alexandre Julliard's avatar
Alexandre Julliard committed
949

950 951 952 953
    pt.x = x;
    pt.y = y;
    LPtoDP( physDev->hdc, &pt, 1 );

954
    /* Update the pixmap from the DIB section */
955
    X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
956

957
    wine_tsx11_lock();
958
    if (memdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
959
    {
960
        image = XGetImage( gdi_display, physDev->drawable,
961
                           physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y,
962
                           1, 1, AllPlanes, ZPixmap );
Alexandre Julliard's avatar
Alexandre Julliard committed
963 964 965 966 967
    }
    else
    {
        /* If we are reading from the screen, use a temporary copy */
        /* to avoid a BadMatch error */
968
        if (!pixmap) pixmap = XCreatePixmap( gdi_display, root_window,
969
                                             1, 1, physDev->depth );
970
        XCopyArea( gdi_display, physDev->drawable, pixmap, BITMAP_colorGC,
971
                   physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y, 1, 1, 0, 0 );
972
        image = XGetImage( gdi_display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
Alexandre Julliard's avatar
Alexandre Julliard committed
973
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
974 975
    pixel = XGetPixel( image, 0, 0 );
    XDestroyImage( image );
976
    wine_tsx11_unlock();
977 978

    /* Update the DIBSection from the pixmap */
979
    X11DRV_UnlockDIBSection(physDev, FALSE);
980

981
    return X11DRV_PALETTE_ToLogical(pixel);
Alexandre Julliard's avatar
Alexandre Julliard committed
982 983 984 985 986 987
}


/***********************************************************************
 *           X11DRV_PaintRgn
 */
988
BOOL
989
X11DRV_PaintRgn( X11DRV_PDEVICE *physDev, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
990
{
991
    if (X11DRV_SetupGCForBrush( physDev ))
992
    {
993
        unsigned int i;
994 995
        XRectangle *rect;
        RGNDATA *data = X11DRV_GetRegionData( hrgn, physDev->hdc );
996

997 998 999 1000
        if (!data) return FALSE;
        rect = (XRectangle *)data->Buffer;
        for (i = 0; i < data->rdh.nCount; i++)
        {
1001 1002
            rect[i].x += physDev->dc_rect.left;
            rect[i].y += physDev->dc_rect.top;
1003
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1004

1005
        X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1006 1007 1008 1009 1010 1011
        wine_tsx11_lock();
        XFillRectangles( gdi_display, physDev->drawable, physDev->gc, rect, data->rdh.nCount );
        wine_tsx11_unlock();
        X11DRV_UnlockDIBSection(physDev, TRUE);
        HeapFree( GetProcessHeap(), 0, data );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1012 1013 1014 1015 1016 1017
    return TRUE;
}

/**********************************************************************
 *          X11DRV_Polyline
 */
1018
BOOL
1019
X11DRV_Polyline( X11DRV_PDEVICE *physDev, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
1020
{
1021
    int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1022
    XPoint *points;
1023

1024 1025 1026 1027 1028
    if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * count )))
    {
        WARN("No memory to convert POINTs to XPoints!\n");
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1029 1030
    for (i = 0; i < count; i++)
    {
1031 1032
        POINT tmp = pt[i];
        LPtoDP(physDev->hdc, &tmp, 1);
1033 1034
        points[i].x = physDev->dc_rect.left + tmp.x;
        points[i].y = physDev->dc_rect.top + tmp.y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1035 1036
    }

1037
    if (X11DRV_SetupGCForPen ( physDev ))
1038
    {
1039
        X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1040 1041 1042 1043 1044
        wine_tsx11_lock();
        XDrawLines( gdi_display, physDev->drawable, physDev->gc,
                    points, count, CoordModeOrigin );
        wine_tsx11_unlock();
        X11DRV_UnlockDIBSection(physDev, TRUE);
1045 1046
    }

1047
    HeapFree( GetProcessHeap(), 0, points );
Alexandre Julliard's avatar
Alexandre Julliard committed
1048 1049 1050 1051 1052 1053 1054
    return TRUE;
}


/**********************************************************************
 *          X11DRV_Polygon
 */
1055
BOOL
1056
X11DRV_Polygon( X11DRV_PDEVICE *physDev, const POINT* pt, INT count )
Alexandre Julliard's avatar
Alexandre Julliard committed
1057 1058 1059
{
    register int i;
    XPoint *points;
1060
    BOOL update = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1061

1062 1063 1064 1065 1066
    if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) )))
    {
        WARN("No memory to convert POINTs to XPoints!\n");
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1067 1068
    for (i = 0; i < count; i++)
    {
1069 1070
        POINT tmp = pt[i];
        LPtoDP(physDev->hdc, &tmp, 1);
1071 1072
        points[i].x = physDev->dc_rect.left + tmp.x;
        points[i].y = physDev->dc_rect.top + tmp.y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1073 1074 1075
    }
    points[count] = points[0];

1076
    /* Update the pixmap from the DIB section */
1077
    X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1078

1079
    if (X11DRV_SetupGCForBrush( physDev ))
1080
    {
1081 1082 1083 1084
        wine_tsx11_lock();
        XFillPolygon( gdi_display, physDev->drawable, physDev->gc,
                      points, count+1, Complex, CoordModeOrigin);
        wine_tsx11_unlock();
1085 1086
	update = TRUE;
    }
1087
    if (X11DRV_SetupGCForPen ( physDev ))
1088
    {
1089 1090 1091 1092
        wine_tsx11_lock();
        XDrawLines( gdi_display, physDev->drawable, physDev->gc,
                    points, count+1, CoordModeOrigin );
        wine_tsx11_unlock();
1093 1094
	update = TRUE;
    }
1095

1096
    /* Update the DIBSection from the pixmap */
1097
    X11DRV_UnlockDIBSection(physDev, update);
Alexandre Julliard's avatar
Alexandre Julliard committed
1098

1099
    HeapFree( GetProcessHeap(), 0, points );
Alexandre Julliard's avatar
Alexandre Julliard committed
1100 1101 1102 1103 1104 1105 1106
    return TRUE;
}


/**********************************************************************
 *          X11DRV_PolyPolygon
 */
1107
BOOL
1108
X11DRV_PolyPolygon( X11DRV_PDEVICE *physDev, const POINT* pt, const INT* counts, UINT polygons)
Alexandre Julliard's avatar
Alexandre Julliard committed
1109
{
1110
    HRGN hrgn;
1111 1112 1113

    /* FIXME: The points should be converted to device coords before */
    /* creating the region. */
Alexandre Julliard's avatar
Alexandre Julliard committed
1114

1115 1116
    hrgn = CreatePolyPolygonRgn( pt, counts, polygons, GetPolyFillMode( physDev->hdc ) );
    X11DRV_PaintRgn( physDev, hrgn );
1117
    DeleteObject( hrgn );
Alexandre Julliard's avatar
Alexandre Julliard committed
1118 1119 1120

      /* Draw the outline of the polygons */

1121
    if (X11DRV_SetupGCForPen ( physDev ))
Alexandre Julliard's avatar
Alexandre Julliard committed
1122
    {
1123 1124
	unsigned int i;
	int j, max = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1125 1126
	XPoint *points;

1127
	/* Update the pixmap from the DIB section */
1128
	X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1129

Alexandre Julliard's avatar
Alexandre Julliard committed
1130
	for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
1131 1132 1133 1134 1135
        if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (max+1) )))
        {
            WARN("No memory to convert POINTs to XPoints!\n");
            return FALSE;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1136 1137 1138 1139
	for (i = 0; i < polygons; i++)
	{
	    for (j = 0; j < counts[i]; j++)
	    {
1140 1141
                POINT tmp = *pt;
                LPtoDP(physDev->hdc, &tmp, 1);
1142 1143
                points[j].x = physDev->dc_rect.left + tmp.x;
                points[j].y = physDev->dc_rect.top + tmp.y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1144 1145 1146
		pt++;
	    }
	    points[j] = points[0];
1147 1148 1149 1150
            wine_tsx11_lock();
            XDrawLines( gdi_display, physDev->drawable, physDev->gc,
                        points, j + 1, CoordModeOrigin );
            wine_tsx11_unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
1151
	}
1152

1153
	/* Update the DIBSection of the dc's bitmap */
1154
	X11DRV_UnlockDIBSection(physDev, TRUE);
1155

1156
	HeapFree( GetProcessHeap(), 0, points );
Alexandre Julliard's avatar
Alexandre Julliard committed
1157 1158 1159 1160 1161
    }
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1162 1163 1164
/**********************************************************************
 *          X11DRV_PolyPolyline
 */
1165
BOOL
1166
X11DRV_PolyPolyline( X11DRV_PDEVICE *physDev, const POINT* pt, const DWORD* counts, DWORD polylines )
Alexandre Julliard's avatar
Alexandre Julliard committed
1167
{
1168
    if (X11DRV_SetupGCForPen ( physDev ))
Alexandre Julliard's avatar
Alexandre Julliard committed
1169
    {
1170
        unsigned int i, j, max = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1171 1172
        XPoint *points;

1173
	/* Update the pixmap from the DIB section */
1174
	X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1175

Alexandre Julliard's avatar
Alexandre Julliard committed
1176
        for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1177
        if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * max )))
1178 1179 1180 1181
        {
            WARN("No memory to convert POINTs to XPoints!\n");
            return FALSE;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1182 1183 1184 1185
        for (i = 0; i < polylines; i++)
        {
            for (j = 0; j < counts[i]; j++)
            {
1186 1187
                POINT tmp = *pt;
                LPtoDP(physDev->hdc, &tmp, 1);
1188 1189
                points[j].x = physDev->dc_rect.left + tmp.x;
                points[j].y = physDev->dc_rect.top + tmp.y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1190 1191
                pt++;
            }
1192 1193 1194 1195
            wine_tsx11_lock();
            XDrawLines( gdi_display, physDev->drawable, physDev->gc,
                        points, j, CoordModeOrigin );
            wine_tsx11_unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
1196
        }
1197

1198
	/* Update the DIBSection of the dc's bitmap */
1199
    	X11DRV_UnlockDIBSection(physDev, TRUE);
1200

1201
	HeapFree( GetProcessHeap(), 0, points );
Alexandre Julliard's avatar
Alexandre Julliard committed
1202 1203 1204 1205 1206
    }
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1207 1208 1209 1210 1211 1212 1213
/**********************************************************************
 *          X11DRV_InternalFloodFill
 *
 * Internal helper function for flood fill.
 * (xorg,yorg) is the origin of the X image relative to the drawable.
 * (x,y) is relative to the origin of the X image.
 */
1214
static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev,
Alexandre Julliard's avatar
Alexandre Julliard committed
1215 1216
                                     int x, int y,
                                     int xOrg, int yOrg,
1217
                                     unsigned long pixel, WORD fillType )
Alexandre Julliard's avatar
Alexandre Julliard committed
1218 1219 1220 1221
{
    int left, right;

#define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
Alexandre Julliard's avatar
Alexandre Julliard committed
1222 1223
                        (XGetPixel(image,x,y) != pixel) : \
                        (XGetPixel(image,x,y) == pixel))
Alexandre Julliard's avatar
Alexandre Julliard committed
1224 1225 1226 1227 1228 1229 1230 1231

    if (!TO_FLOOD(x,y)) return;

      /* Find left and right boundaries */

    left = right = x;
    while ((left > 0) && TO_FLOOD( left-1, y )) left--;
    while ((right < image->width) && TO_FLOOD( right, y )) right++;
1232
    XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
Alexandre Julliard's avatar
Alexandre Julliard committed
1233 1234 1235 1236 1237 1238
                    xOrg + left, yOrg + y, right-left, 1 );

      /* Set the pixels of this line so we don't fill it again */

    for (x = left; x < right; x++)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1239 1240
        if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
        else XPutPixel( image, x, y, ~pixel );
Alexandre Julliard's avatar
Alexandre Julliard committed
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
    }

      /* Fill the line above */

    if (--y >= 0)
    {
        x = left;
        while (x < right)
        {
            while ((x < right) && !TO_FLOOD(x,y)) x++;
            if (x >= right) break;
            while ((x < right) && TO_FLOOD(x,y)) x++;
1253
            X11DRV_InternalFloodFill(image, physDev, x-1, y,
Alexandre Julliard's avatar
Alexandre Julliard committed
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
                                     xOrg, yOrg, pixel, fillType );
        }
    }

      /* Fill the line below */

    if ((y += 2) < image->height)
    {
        x = left;
        while (x < right)
        {
            while ((x < right) && !TO_FLOOD(x,y)) x++;
            if (x >= right) break;
            while ((x < right) && TO_FLOOD(x,y)) x++;
1268
            X11DRV_InternalFloodFill(image, physDev, x-1, y,
Alexandre Julliard's avatar
Alexandre Julliard committed
1269 1270 1271
                                     xOrg, yOrg, pixel, fillType );
        }
    }
1272
#undef TO_FLOOD
Alexandre Julliard's avatar
Alexandre Julliard committed
1273 1274 1275
}


1276 1277 1278 1279 1280
static int ExtFloodFillXGetImageErrorHandler( Display *dpy, XErrorEvent *event, void *arg )
{
    return (event->request_code == X_GetImage && event->error_code == BadMatch);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1281
/**********************************************************************
1282
 *          X11DRV_ExtFloodFill
Alexandre Julliard's avatar
Alexandre Julliard committed
1283
 */
1284
BOOL
1285
X11DRV_ExtFloodFill( X11DRV_PDEVICE *physDev, INT x, INT y, COLORREF color,
1286
                     UINT fillType )
Alexandre Julliard's avatar
Alexandre Julliard committed
1287 1288
{
    XImage *image;
1289
    RECT rect;
1290
    POINT pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1291

1292
    TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x, y, color, fillType );
1293

1294 1295 1296 1297 1298
    pt.x = x;
    pt.y = y;
    LPtoDP( physDev->hdc, &pt, 1 );
    if (!PtInRegion( physDev->region, pt.x, pt.y )) return FALSE;
    GetRgnBox( physDev->region, &rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1299

1300
    X11DRV_expect_error( gdi_display, ExtFloodFillXGetImageErrorHandler, NULL );
1301
    image = XGetImage( gdi_display, physDev->drawable,
1302
                       physDev->dc_rect.left + rect.left, physDev->dc_rect.top + rect.top,
1303 1304
                       rect.right - rect.left, rect.bottom - rect.top,
                       AllPlanes, ZPixmap );
1305
    if(X11DRV_check_error()) image = NULL;
1306
    if (!image) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1307

1308
    if (X11DRV_SetupGCForBrush( physDev ))
Alexandre Julliard's avatar
Alexandre Julliard committed
1309
    {
1310 1311
        unsigned long pixel = X11DRV_PALETTE_ToPhysical( physDev, color );

1312
	/* Update the pixmap from the DIB section */
1313
	X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1314

Alexandre Julliard's avatar
Alexandre Julliard committed
1315
          /* ROP mode is always GXcopy for flood-fill */
1316
        wine_tsx11_lock();
1317
        XSetFunction( gdi_display, physDev->gc, GXcopy );
1318
        X11DRV_InternalFloodFill(image, physDev,
1319 1320 1321 1322
                                 pt.x - rect.left,
                                 pt.y - rect.top,
                                 physDev->dc_rect.left + rect.left,
                                 physDev->dc_rect.top + rect.top,
1323
                                 pixel, fillType );
1324
        wine_tsx11_unlock();
1325
        /* Update the DIBSection of the dc's bitmap */
1326
        X11DRV_UnlockDIBSection(physDev, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1327 1328
    }

1329 1330 1331
    wine_tsx11_lock();
    XDestroyImage( image );
    wine_tsx11_unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
1332 1333 1334
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1335 1336 1337 1338
/**********************************************************************
 *          X11DRV_SetBkColor
 */
COLORREF
1339
X11DRV_SetBkColor( X11DRV_PDEVICE *physDev, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
1340
{
1341 1342
    physDev->backgroundPixel = X11DRV_PALETTE_ToPhysical( physDev, color );
    return color;
Alexandre Julliard's avatar
Alexandre Julliard committed
1343 1344 1345 1346 1347 1348
}

/**********************************************************************
 *          X11DRV_SetTextColor
 */
COLORREF
1349
X11DRV_SetTextColor( X11DRV_PDEVICE *physDev, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
1350
{
1351 1352
    physDev->textPixel = X11DRV_PALETTE_ToPhysical( physDev, color );
    return color;
Alexandre Julliard's avatar
Alexandre Julliard committed
1353
}
Patrik Stridvall's avatar
Patrik Stridvall committed
1354

1355
/***********************************************************************
1356
 *           GetDCOrgEx   (X11DRV.@)
1357
 */
1358
BOOL X11DRV_GetDCOrgEx( X11DRV_PDEVICE *physDev, LPPOINT lpp )
1359
{
1360 1361
    lpp->x = physDev->dc_rect.left + physDev->drawable_rect.left;
    lpp->y = physDev->dc_rect.top + physDev->drawable_rect.top;
1362 1363 1364
    return TRUE;
}

1365 1366 1367 1368 1369 1370

/***********************************************************************
 *           SetDCOrg   (X11DRV.@)
 */
DWORD X11DRV_SetDCOrg( X11DRV_PDEVICE *physDev, INT x, INT y )
{
1371 1372 1373 1374
    DWORD ret = MAKELONG( physDev->dc_rect.left + physDev->drawable_rect.left,
                          physDev->dc_rect.top + physDev->drawable_rect.top );
    physDev->dc_rect.left = x - physDev->drawable_rect.left;
    physDev->dc_rect.top = y - physDev->drawable_rect.top;
1375 1376
    return ret;
}