Added an unknown VxD error code.
[wine] / graphics / x11drv / graphics.c
1 /*
2  * X11 graphics driver graphics functions
3  *
4  * Copyright 1993,1994 Alexandre Julliard
5  */
6
7 /*
8  * FIXME: only some of these functions obey the GM_ADVANCED
9  * graphics mode
10  */
11
12 #include "config.h"
13
14 #include <X11/Intrinsic.h>
15
16 #include "ts_xlib.h"
17 #include "ts_xutil.h"
18
19 #include <math.h>
20 #ifdef HAVE_FLOAT_H
21 # include <float.h>
22 #endif
23 #include <stdlib.h>
24 #ifndef PI
25 #define PI M_PI
26 #endif
27 #include <string.h>
28
29 #include "x11drv.h"
30 #include "x11font.h"
31 #include "bitmap.h"
32 #include "gdi.h"
33 #include "metafile.h"
34 #include "palette.h"
35 #include "color.h"
36 #include "region.h"
37 #include "debugtools.h"
38
39 DEFAULT_DEBUG_CHANNEL(graphics);
40
41 #define ABS(x)    ((x)<0?(-(x)):(x))
42
43   /* ROP code to GC function conversion */
44 const int X11DRV_XROPfunction[16] =
45 {
46     GXclear,        /* R2_BLACK */
47     GXnor,          /* R2_NOTMERGEPEN */
48     GXandInverted,  /* R2_MASKNOTPEN */
49     GXcopyInverted, /* R2_NOTCOPYPEN */
50     GXandReverse,   /* R2_MASKPENNOT */
51     GXinvert,       /* R2_NOT */
52     GXxor,          /* R2_XORPEN */
53     GXnand,         /* R2_NOTMASKPEN */
54     GXand,          /* R2_MASKPEN */
55     GXequiv,        /* R2_NOTXORPEN */
56     GXnoop,         /* R2_NOP */
57     GXorInverted,   /* R2_MERGENOTPEN */
58     GXcopy,         /* R2_COPYPEN */
59     GXorReverse,    /* R2_MERGEPENNOT */
60     GXor,           /* R2_MERGEPEN */
61     GXset           /* R2_WHITE */
62 };
63
64
65 /***********************************************************************
66  *           X11DRV_SetupGCForPatBlt
67  *
68  * Setup the GC for a PatBlt operation using current brush.
69  * If fMapColors is TRUE, X pixels are mapped to Windows colors.
70  * Return FALSE if brush is BS_NULL, TRUE otherwise.
71  */
72 BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors )
73 {
74     XGCValues val;
75     unsigned long mask;
76     Pixmap pixmap = 0;
77     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
78
79     if (physDev->brush.style == BS_NULL) return FALSE;
80     if (physDev->brush.pixel == -1)
81     {
82         /* Special case used for monochrome pattern brushes.
83          * We need to swap foreground and background because
84          * Windows does it the wrong way...
85          */
86         val.foreground = physDev->backgroundPixel;
87         val.background = physDev->textPixel;
88     }
89     else
90     {
91         val.foreground = physDev->brush.pixel;
92         val.background = physDev->backgroundPixel;
93     }
94     if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
95     {
96         val.foreground = X11DRV_PALETTE_XPixelToPalette[val.foreground];
97         val.background = X11DRV_PALETTE_XPixelToPalette[val.background];
98     }
99
100     val.function = X11DRV_XROPfunction[dc->ROPmode-1];
101     /*
102     ** Let's replace GXinvert by GXxor with (black xor white)
103     ** This solves the selection color and leak problems in excel
104     ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
105     */
106     if (val.function == GXinvert)
107     {
108         val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
109                           BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
110         val.function = GXxor;
111     }
112     val.fill_style = physDev->brush.fillStyle;
113     switch(val.fill_style)
114     {
115     case FillStippled:
116     case FillOpaqueStippled:
117         if (dc->backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
118         val.stipple = physDev->brush.pixmap;
119         mask = GCStipple;
120         break;
121
122     case FillTiled:
123         if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
124         {
125             register int x, y;
126             XImage *image;
127             wine_tsx11_lock();
128             pixmap = XCreatePixmap( gdi_display, root_window, 8, 8, screen_depth );
129             image = XGetImage( gdi_display, physDev->brush.pixmap, 0, 0, 8, 8,
130                                AllPlanes, ZPixmap );
131             for (y = 0; y < 8; y++)
132                 for (x = 0; x < 8; x++)
133                     XPutPixel( image, x, y,
134                                X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] );
135             XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
136             XDestroyImage( image );
137             wine_tsx11_unlock();
138             val.tile = pixmap;
139         }
140         else val.tile = physDev->brush.pixmap;
141         mask = GCTile;
142         break;
143
144     default:
145         mask = 0;
146         break;
147     }
148     val.ts_x_origin = dc->DCOrgX + dc->brushOrgX;
149     val.ts_y_origin = dc->DCOrgY + dc->brushOrgY;
150     val.fill_rule = (dc->polyFillMode==WINDING) ? WindingRule : EvenOddRule;
151     TSXChangeGC( gdi_display, gc,
152                GCFunction | GCForeground | GCBackground | GCFillStyle |
153                GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
154                &val );
155     if (pixmap) TSXFreePixmap( gdi_display, pixmap );
156     return TRUE;
157 }
158
159
160 /***********************************************************************
161  *           X11DRV_SetupGCForBrush
162  *
163  * Setup physDev->gc for drawing operations using current brush.
164  * Return FALSE if brush is BS_NULL, TRUE otherwise.
165  */
166 BOOL X11DRV_SetupGCForBrush( DC * dc )
167 {
168     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
169     return X11DRV_SetupGCForPatBlt( dc, physDev->gc, FALSE );
170 }
171
172
173 /***********************************************************************
174  *           X11DRV_SetupGCForPen
175  *
176  * Setup physDev->gc for drawing operations using current pen.
177  * Return FALSE if pen is PS_NULL, TRUE otherwise.
178  */
179 BOOL X11DRV_SetupGCForPen( DC * dc )
180 {
181     XGCValues val;
182     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
183
184     if (physDev->pen.style == PS_NULL) return FALSE;
185
186     switch (dc->ROPmode)
187     {
188     case R2_BLACK :
189         val.foreground = BlackPixel( gdi_display, DefaultScreen(gdi_display) );
190         val.function = GXcopy;
191         break;
192     case R2_WHITE :
193         val.foreground = WhitePixel( gdi_display, DefaultScreen(gdi_display) );
194         val.function = GXcopy;
195         break;
196     case R2_XORPEN :
197         val.foreground = physDev->pen.pixel;
198         /* It is very unlikely someone wants to XOR with 0 */
199         /* This fixes the rubber-drawings in paintbrush */
200         if (val.foreground == 0)
201             val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
202                               BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
203         val.function = GXxor;
204         break;
205     default :
206         val.foreground = physDev->pen.pixel;
207         val.function   = X11DRV_XROPfunction[dc->ROPmode-1];
208     }
209     val.background = physDev->backgroundPixel;
210     val.fill_style = FillSolid;
211     if ((physDev->pen.width <= 1) &&
212         (physDev->pen.style != PS_SOLID) &&
213         (physDev->pen.style != PS_INSIDEFRAME))
214     {
215         TSXSetDashes( gdi_display, physDev->gc, 0, physDev->pen.dashes, physDev->pen.dash_len );
216         val.line_style = (dc->backgroundMode == OPAQUE) ?
217                               LineDoubleDash : LineOnOffDash;
218     }
219     else val.line_style = LineSolid;
220     val.line_width = physDev->pen.width;
221     if (val.line_width <= 1) {
222         val.cap_style = CapNotLast;
223     } else {
224         switch (physDev->pen.endcap)
225         {
226         case PS_ENDCAP_SQUARE:
227             val.cap_style = CapProjecting;
228             break;
229         case PS_ENDCAP_FLAT:
230             val.cap_style = CapButt;
231             break;
232         case PS_ENDCAP_ROUND:
233         default:
234             val.cap_style = CapRound;
235         }
236     }
237     switch (physDev->pen.linejoin)
238     {
239     case PS_JOIN_BEVEL:
240         val.join_style = JoinBevel;
241         break;
242     case PS_JOIN_MITER:
243         val.join_style = JoinMiter;
244         break;
245     case PS_JOIN_ROUND:
246     default:
247         val.join_style = JoinRound;
248     }
249     TSXChangeGC( gdi_display, physDev->gc,
250                GCFunction | GCForeground | GCBackground | GCLineWidth |
251                GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
252     return TRUE;
253 }
254
255
256 /***********************************************************************
257  *           X11DRV_SetupGCForText
258  *
259  * Setup physDev->gc for text drawing operations.
260  * Return FALSE if the font is null, TRUE otherwise.
261  */
262 BOOL X11DRV_SetupGCForText( DC * dc )
263 {
264     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
265     XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
266
267     if( xfs )
268     {
269         XGCValues val;
270
271         val.function   = GXcopy;  /* Text is always GXcopy */
272         val.foreground = physDev->textPixel;
273         val.background = physDev->backgroundPixel;
274         val.fill_style = FillSolid;
275         val.font       = xfs->fid;
276
277         TSXChangeGC( gdi_display, physDev->gc,
278                    GCFunction | GCForeground | GCBackground | GCFillStyle |
279                    GCFont, &val );
280         return TRUE;
281     } 
282     WARN("Physical font failure\n" );
283     return FALSE;
284 }
285
286 /***********************************************************************
287  *           X11DRV_LineTo
288  */
289 BOOL
290 X11DRV_LineTo( DC *dc, INT x, INT y )
291 {
292     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
293     POINT start;
294     POINT end;
295
296     if (X11DRV_SetupGCForPen( dc )) {
297         /* Update the pixmap from the DIB section */
298         X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
299
300         start.x = dc->CursPosX;
301         start.y = dc->CursPosY;
302         end.x = x;
303         end.y = y;
304         INTERNAL_LPTODP(dc,&start);
305         INTERNAL_LPTODP(dc,&end);
306
307         TSXDrawLine(gdi_display, physDev->drawable, physDev->gc,
308                   dc->DCOrgX + start.x,
309                   dc->DCOrgY + start.y,
310                   dc->DCOrgX + end.x,
311                   dc->DCOrgY + end.y);
312
313         /* Update the DIBSection from the pixmap */
314         X11DRV_UnlockDIBSection(dc, TRUE); 
315     }
316     return TRUE;
317 }
318
319
320
321 /***********************************************************************
322  *           X11DRV_DrawArc
323  *
324  * Helper functions for Arc(), Chord() and Pie().
325  * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
326  *
327  */
328 static BOOL
329 X11DRV_DrawArc( DC *dc, INT left, INT top, INT right,
330                 INT bottom, INT xstart, INT ystart,
331                 INT xend, INT yend, INT lines )
332 {
333     INT xcenter, ycenter, istart_angle, idiff_angle;
334     INT width, oldwidth, oldendcap;
335     double start_angle, end_angle;
336     XPoint points[4];
337     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
338     BOOL update = FALSE;
339
340     left   = XLPTODP( dc, left );
341     top    = YLPTODP( dc, top );
342     right  = XLPTODP( dc, right );
343     bottom = YLPTODP( dc, bottom );
344     xstart = XLPTODP( dc, xstart );
345     ystart = YLPTODP( dc, ystart );
346     xend   = XLPTODP( dc, xend );
347     yend   = YLPTODP( dc, yend );
348
349     if (right < left) { INT tmp = right; right = left; left = tmp; }
350     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
351     if ((left == right) || (top == bottom)
352             ||(lines && ((right-left==1)||(bottom-top==1)))) return TRUE;
353
354     if( dc->ArcDirection == AD_CLOCKWISE )
355         { INT tmp = xstart; xstart = xend; xend = tmp;
356           tmp = ystart; ystart = yend; yend = tmp; } 
357         
358     oldwidth = width = physDev->pen.width;
359     oldendcap = physDev->pen.endcap;
360     if (!width) width = 1;
361     if(physDev->pen.style == PS_NULL) width = 0;
362
363     if ((physDev->pen.style == PS_INSIDEFRAME))
364     {
365         if (2*width > (right-left)) width=(right-left + 1)/2;
366         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
367         left   += width / 2;
368         right  -= (width - 1) / 2;
369         top    += width / 2;
370         bottom -= (width - 1) / 2;
371     }
372     if(width == 0) width = 1; /* more accurate */
373     physDev->pen.width = width;
374     physDev->pen.endcap = PS_ENDCAP_SQUARE;
375
376     xcenter = (right + left) / 2;
377     ycenter = (bottom + top) / 2;
378     start_angle = atan2( (double)(ycenter-ystart)*(right-left),
379                          (double)(xstart-xcenter)*(bottom-top) );
380     end_angle   = atan2( (double)(ycenter-yend)*(right-left),
381                          (double)(xend-xcenter)*(bottom-top) );
382     if ((xstart==xend)&&(ystart==yend))
383       { /* A lazy program delivers xstart=xend=ystart=yend=0) */
384         start_angle = 0;
385         end_angle = 2* PI;
386       }
387     else /* notorious cases */
388       if ((start_angle == PI)&&( end_angle <0))
389         start_angle = - PI;
390     else
391       if ((end_angle == PI)&&( start_angle <0))
392         end_angle = - PI;
393     istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
394     idiff_angle  = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
395     if (idiff_angle <= 0) idiff_angle += 360 * 64;
396
397     /* Update the pixmap from the DIB section */
398     X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
399
400       /* Fill arc with brush if Chord() or Pie() */
401
402     if ((lines > 0) && X11DRV_SetupGCForBrush( dc )) {
403         TSXSetArcMode( gdi_display, physDev->gc, (lines==1) ? ArcChord : ArcPieSlice);
404         TSXFillArc( gdi_display, physDev->drawable, physDev->gc,
405                  dc->DCOrgX + left, dc->DCOrgY + top,
406                  right-left-1, bottom-top-1, istart_angle, idiff_angle );
407         update = TRUE;
408     }
409
410       /* Draw arc and lines */
411
412     if (X11DRV_SetupGCForPen( dc )){
413         TSXDrawArc( gdi_display, physDev->drawable, physDev->gc,
414                     dc->DCOrgX + left, dc->DCOrgY + top,
415                     right-left-1, bottom-top-1, istart_angle, idiff_angle );
416         if (lines) {
417             /* use the truncated values */
418             start_angle=(double)istart_angle*PI/64./180.;
419             end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
420             /* calculate the endpoints and round correctly */
421             points[0].x = (int) floor(dc->DCOrgX + (right+left)/2.0 +
422                     cos(start_angle) * (right-left-width*2+2) / 2. + 0.5);
423             points[0].y = (int) floor(dc->DCOrgY + (top+bottom)/2.0 -
424                     sin(start_angle) * (bottom-top-width*2+2) / 2. + 0.5);
425             points[1].x = (int) floor(dc->DCOrgX + (right+left)/2.0 +
426                     cos(end_angle) * (right-left-width*2+2) / 2. + 0.5);
427             points[1].y = (int) floor(dc->DCOrgY + (top+bottom)/2.0 -
428                     sin(end_angle) * (bottom-top-width*2+2) / 2. + 0.5);
429                     
430             /* OK, this stuff is optimized for Xfree86 
431              * which is probably the server most used by
432              * wine users. Other X servers will not 
433              * display correctly. (eXceed for instance)
434              * so if you feel you must make changes, make sure that
435              * you either use Xfree86 or separate your changes 
436              * from these (compile switch or whatever)
437              */
438             if (lines == 2) {
439                 INT dx1,dy1;
440                 points[3] = points[1];
441                 points[1].x = dc->DCOrgX + xcenter;
442                 points[1].y = dc->DCOrgY + ycenter;
443                 points[2] = points[1];
444                 dx1=points[1].x-points[0].x;
445                 dy1=points[1].y-points[0].y;
446                 if(((top-bottom) | -2) == -2)
447                     if(dy1>0) points[1].y--;
448                 if(dx1<0) {
449                     if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
450                     if(((-dx1*9))<(dy1*16)) points[0].y--;
451                     if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
452                 } else {
453                     if(dy1 < 0)  points[0].y--;
454                     if(((right-left) | -2) == -2) points[1].x--;
455                 }
456                 dx1=points[3].x-points[2].x;
457                 dy1=points[3].y-points[2].y;
458                 if(((top-bottom) | -2 ) == -2)
459                     if(dy1 < 0) points[2].y--;
460                 if( dx1<0){ 
461                     if( dy1>0) points[3].y--;
462                     if(((right-left) | -2) == -2 ) points[2].x--;
463                 }else {
464                     points[3].y--;
465                     if( dx1 * 64 < dy1 * -37 ) points[3].x--;
466                 }
467                 lines++;
468             }
469             TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
470                           points, lines+1, CoordModeOrigin );
471         }
472         update = TRUE;
473     }
474
475     /* Update the DIBSection of the pixmap */
476     X11DRV_UnlockDIBSection(dc, update);
477
478     physDev->pen.width = oldwidth;
479     physDev->pen.endcap = oldendcap;
480     return TRUE;
481 }
482
483
484 /***********************************************************************
485  *           X11DRV_Arc
486  */
487 BOOL
488 X11DRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
489             INT xstart, INT ystart, INT xend, INT yend )
490 {
491     return X11DRV_DrawArc( dc, left, top, right, bottom,
492                            xstart, ystart, xend, yend, 0 );
493 }
494
495
496 /***********************************************************************
497  *           X11DRV_Pie
498  */
499 BOOL
500 X11DRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
501             INT xstart, INT ystart, INT xend, INT yend )
502 {
503     return X11DRV_DrawArc( dc, left, top, right, bottom,
504                            xstart, ystart, xend, yend, 2 );
505 }
506
507 /***********************************************************************
508  *           X11DRV_Chord
509  */
510 BOOL
511 X11DRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
512               INT xstart, INT ystart, INT xend, INT yend )
513 {
514     return X11DRV_DrawArc( dc, left, top, right, bottom,
515                            xstart, ystart, xend, yend, 1 );
516 }
517
518
519 /***********************************************************************
520  *           X11DRV_Ellipse
521  */
522 BOOL
523 X11DRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
524 {
525     INT width, oldwidth;
526     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
527     BOOL update = FALSE;
528
529     left   = XLPTODP( dc, left );
530     top    = YLPTODP( dc, top );
531     right  = XLPTODP( dc, right );
532     bottom = YLPTODP( dc, bottom );
533     if ((left == right) || (top == bottom)) return TRUE;
534
535     if (right < left) { INT tmp = right; right = left; left = tmp; }
536     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
537     
538     oldwidth = width = physDev->pen.width;
539     if (!width) width = 1;
540     if(physDev->pen.style == PS_NULL) width = 0;
541
542     if ((physDev->pen.style == PS_INSIDEFRAME))
543     {
544         if (2*width > (right-left)) width=(right-left + 1)/2;
545         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
546         left   += width / 2;
547         right  -= (width - 1) / 2;
548         top    += width / 2;
549         bottom -= (width - 1) / 2;
550     }
551     if(width == 0) width = 1; /* more accurate */
552     physDev->pen.width = width;
553
554     /* Update the pixmap from the DIB section */
555     X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
556
557     if (X11DRV_SetupGCForBrush( dc ))
558     {
559         TSXFillArc( gdi_display, physDev->drawable, physDev->gc,
560                     dc->DCOrgX + left, dc->DCOrgY + top,
561                     right-left-1, bottom-top-1, 0, 360*64 );
562         update = TRUE;
563     }
564     if (X11DRV_SetupGCForPen( dc ))
565     {
566         TSXDrawArc( gdi_display, physDev->drawable, physDev->gc,
567                     dc->DCOrgX + left, dc->DCOrgY + top,
568                     right-left-1, bottom-top-1, 0, 360*64 );
569         update = TRUE;
570     }
571
572     /* Update the DIBSection from the pixmap */
573     X11DRV_UnlockDIBSection(dc, update);
574     
575     physDev->pen.width = oldwidth;
576     return TRUE;
577 }
578
579
580 /***********************************************************************
581  *           X11DRV_Rectangle
582  */
583 BOOL
584 X11DRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
585 {
586     INT width, oldwidth, oldjoinstyle;
587     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
588     BOOL update = FALSE;
589
590     TRACE("(%d %d %d %d)\n", 
591         left, top, right, bottom);
592
593     left   = INTERNAL_XWPTODP( dc, left, top );
594     top    = INTERNAL_YWPTODP( dc, left, top );
595     right  = INTERNAL_XWPTODP( dc, right, bottom );
596     bottom = INTERNAL_YWPTODP( dc, right, bottom );
597
598     if ((left == right) || (top == bottom)) return TRUE;
599
600     if (right < left) { INT tmp = right; right = left; left = tmp; }
601     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
602
603     oldwidth = width = physDev->pen.width;
604     if (!width) width = 1;
605     if(physDev->pen.style == PS_NULL) width = 0;
606
607     if ((physDev->pen.style == PS_INSIDEFRAME))
608     {
609         if (2*width > (right-left)) width=(right-left + 1)/2;
610         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
611         left   += width / 2;
612         right  -= (width - 1) / 2;
613         top    += width / 2;
614         bottom -= (width - 1) / 2;
615     }
616     if(width == 1) width = 0;
617     physDev->pen.width = width;
618     oldjoinstyle = physDev->pen.linejoin;
619     if(physDev->pen.type != PS_GEOMETRIC)
620         physDev->pen.linejoin = PS_JOIN_MITER;
621
622     /* Update the pixmap from the DIB section */
623     X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
624     
625     if ((right > left + width) && (bottom > top + width))
626         if (X11DRV_SetupGCForBrush( dc ))
627         {
628             TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
629                               dc->DCOrgX + left + (width + 1) / 2,
630                               dc->DCOrgY + top + (width + 1) / 2,
631                               right-left-width-1, bottom-top-width-1);
632             update = TRUE;
633         }
634     if (X11DRV_SetupGCForPen( dc ))
635     {
636         TSXDrawRectangle( gdi_display, physDev->drawable, physDev->gc,
637                           dc->DCOrgX + left, dc->DCOrgY + top,
638                           right-left-1, bottom-top-1 );
639         update = TRUE;
640     }
641
642     /* Update the DIBSection from the pixmap */
643     X11DRV_UnlockDIBSection(dc, update);
644    
645     physDev->pen.width = oldwidth;
646     physDev->pen.linejoin = oldjoinstyle;
647     return TRUE;
648 }
649
650 /***********************************************************************
651  *           X11DRV_RoundRect
652  */
653 BOOL
654 X11DRV_RoundRect( DC *dc, INT left, INT top, INT right,
655                   INT bottom, INT ell_width, INT ell_height )
656 {
657     INT width, oldwidth, oldendcap;
658     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
659     BOOL update = FALSE;
660
661     TRACE("(%d %d %d %d  %d %d\n", 
662         left, top, right, bottom, ell_width, ell_height);
663
664     left   = XLPTODP( dc, left );
665     top    = YLPTODP( dc, top );
666     right  = XLPTODP( dc, right );
667     bottom = YLPTODP( dc, bottom );
668
669     if ((left == right) || (top == bottom))
670         return TRUE;
671
672     /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
673        called with width/height < 0 */
674     ell_width  = max(abs( ell_width * dc->vportExtX / dc->wndExtX ), 1);
675     ell_height = max(abs( ell_height * dc->vportExtY / dc->wndExtY ), 1);
676
677     /* Fix the coordinates */
678
679     if (right < left) { INT tmp = right; right = left; left = tmp; }
680     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
681
682     oldwidth = width = physDev->pen.width;
683     oldendcap = physDev->pen.endcap;
684     if (!width) width = 1;
685     if(physDev->pen.style == PS_NULL) width = 0;
686
687     if ((physDev->pen.style == PS_INSIDEFRAME))
688     {
689         if (2*width > (right-left)) width=(right-left + 1)/2;
690         if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
691         left   += width / 2;
692         right  -= (width - 1) / 2;
693         top    += width / 2;
694         bottom -= (width - 1) / 2;
695     }
696     if(width == 0) width = 1;
697     physDev->pen.width = width;
698     physDev->pen.endcap = PS_ENDCAP_SQUARE;
699
700     /* Update the pixmap from the DIB section */
701     X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
702
703     wine_tsx11_lock();
704     if (X11DRV_SetupGCForBrush( dc ))
705     {
706         if (ell_width > (right-left) )
707             if (ell_height > (bottom-top) )
708                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
709                           dc->DCOrgX + left, dc->DCOrgY + top,
710                           right - left - 1, bottom - top - 1,
711                           0, 360 * 64 );
712             else{
713                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
714                           dc->DCOrgX + left, dc->DCOrgY + top,
715                           right - left - 1, ell_height, 0, 180 * 64 );
716                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
717                           dc->DCOrgX + left,
718                           dc->DCOrgY + bottom - ell_height - 1,
719                           right - left - 1, ell_height, 180 * 64,
720                           180 * 64 );
721             }
722         else if (ell_height > (bottom-top) ){
723             XFillArc( gdi_display, physDev->drawable, physDev->gc,
724                       dc->DCOrgX + left, dc->DCOrgY + top,
725                       ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
726             XFillArc( gdi_display, physDev->drawable, physDev->gc,
727                       dc->DCOrgX + right - ell_width -1, dc->DCOrgY + top,
728                       ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
729         }else{
730             XFillArc( gdi_display, physDev->drawable, physDev->gc,
731                       dc->DCOrgX + left, dc->DCOrgY + top,
732                       ell_width, ell_height, 90 * 64, 90 * 64 );
733             XFillArc( gdi_display, physDev->drawable, physDev->gc,
734                       dc->DCOrgX + left,
735                       dc->DCOrgY + bottom - ell_height - 1,
736                       ell_width, ell_height, 180 * 64, 90 * 64 );
737             XFillArc( gdi_display, physDev->drawable, physDev->gc,
738                       dc->DCOrgX + right - ell_width - 1,
739                       dc->DCOrgY + bottom - ell_height - 1,
740                       ell_width, ell_height, 270 * 64, 90 * 64 );
741             XFillArc( gdi_display, physDev->drawable, physDev->gc,
742                       dc->DCOrgX + right - ell_width - 1,
743                       dc->DCOrgY + top,
744                       ell_width, ell_height, 0, 90 * 64 );
745         }
746         if (ell_width < right - left)
747         {
748             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
749                             dc->DCOrgX + left + (ell_width + 1) / 2,
750                             dc->DCOrgY + top + 1,
751                             right - left - ell_width - 1,
752                             (ell_height + 1) / 2 - 1);
753             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
754                             dc->DCOrgX + left + (ell_width + 1) / 2,
755                             dc->DCOrgY + bottom - (ell_height) / 2 - 1,
756                             right - left - ell_width - 1,
757                             (ell_height) / 2 );
758         }
759         if  (ell_height < bottom - top)
760         {
761             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
762                             dc->DCOrgX + left + 1,
763                             dc->DCOrgY + top + (ell_height + 1) / 2,
764                             right - left - 2,
765                             bottom - top - ell_height - 1);
766         }
767         update = TRUE;
768     }
769     /* FIXME: this could be done with on X call
770      * more efficient and probably more correct
771      * on any X server: XDrawArcs will draw
772      * straight horizontal and vertical lines
773      * if width or height are zero.
774      *
775      * BTW this stuff is optimized for an Xfree86 server
776      * read the comments inside the X11DRV_DrawArc function
777      */
778     if (X11DRV_SetupGCForPen(dc)) {
779         if (ell_width > (right-left) )
780             if (ell_height > (bottom-top) )
781                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
782                           dc->DCOrgX + left, dc->DCOrgY + top,
783                           right - left - 1, bottom -top - 1, 0 , 360 * 64 );
784             else{
785                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
786                           dc->DCOrgX + left, dc->DCOrgY + top,
787                           right - left - 1, ell_height - 1, 0 , 180 * 64 );
788                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
789                           dc->DCOrgX + left,
790                           dc->DCOrgY + bottom - ell_height,
791                           right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
792             }
793         else if (ell_height > (bottom-top) ){
794             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
795                       dc->DCOrgX + left, dc->DCOrgY + top,
796                       ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
797             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
798                       dc->DCOrgX + right - ell_width,
799                       dc->DCOrgY + top,
800                       ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
801         }else{
802             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
803                       dc->DCOrgX + left, dc->DCOrgY + top,
804                       ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
805             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
806                       dc->DCOrgX + left, dc->DCOrgY + bottom - ell_height,
807                       ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
808             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
809                       dc->DCOrgX + right - ell_width,
810                       dc->DCOrgY + bottom - ell_height,
811                       ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
812             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
813                       dc->DCOrgX + right - ell_width, dc->DCOrgY + top,
814                       ell_width - 1, ell_height - 1, 0, 90 * 64 );
815         }
816         if (ell_width < right - left)
817         {
818             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
819                        dc->DCOrgX + left + ell_width / 2,
820                        dc->DCOrgY + top,
821                        dc->DCOrgX + right - (ell_width+1) / 2,
822                        dc->DCOrgY + top);
823             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
824                        dc->DCOrgX + left + ell_width / 2 ,
825                        dc->DCOrgY + bottom - 1,
826                        dc->DCOrgX + right - (ell_width+1)/ 2,
827                        dc->DCOrgY + bottom - 1);
828         }
829         if (ell_height < bottom - top)
830         {
831             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
832                        dc->DCOrgX + right - 1,
833                        dc->DCOrgY + top + ell_height / 2,
834                        dc->DCOrgX + right - 1,
835                        dc->DCOrgY + bottom - (ell_height+1) / 2);
836             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
837                        dc->DCOrgX + left,
838                        dc->DCOrgY + top + ell_height / 2,
839                        dc->DCOrgX + left,
840                        dc->DCOrgY + bottom - (ell_height+1) / 2);
841         }
842         update = TRUE;
843     }
844     wine_tsx11_unlock();
845     /* Update the DIBSection from the pixmap */
846     X11DRV_UnlockDIBSection(dc, update);
847
848     physDev->pen.width = oldwidth;
849     physDev->pen.endcap = oldendcap;
850     return TRUE;
851 }
852
853
854 /***********************************************************************
855  *           X11DRV_SetPixel
856  */
857 COLORREF
858 X11DRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
859 {
860     Pixel pixel;
861     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
862     
863     x = dc->DCOrgX + INTERNAL_XWPTODP( dc, x, y );
864     y = dc->DCOrgY + INTERNAL_YWPTODP( dc, x, y );
865     pixel = X11DRV_PALETTE_ToPhysical( dc, color );
866
867     /* Update the pixmap from the DIB section */
868     X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
869
870     /* inefficient but simple... */
871     wine_tsx11_lock();
872     XSetForeground( gdi_display, physDev->gc, pixel );
873     XSetFunction( gdi_display, physDev->gc, GXcopy );
874     XDrawPoint( gdi_display, physDev->drawable, physDev->gc, x, y );
875     wine_tsx11_unlock();
876
877     /* Update the DIBSection from the pixmap */
878     X11DRV_UnlockDIBSection(dc, TRUE);
879
880     return X11DRV_PALETTE_ToLogical(pixel);
881 }
882
883
884 /***********************************************************************
885  *           X11DRV_GetPixel
886  */
887 COLORREF
888 X11DRV_GetPixel( DC *dc, INT x, INT y )
889 {
890     static Pixmap pixmap = 0;
891     XImage * image;
892     int pixel;
893     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
894
895     /* Update the pixmap from the DIB section */
896     X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
897
898     x = dc->DCOrgX + INTERNAL_XWPTODP( dc, x, y );
899     y = dc->DCOrgY + INTERNAL_YWPTODP( dc, x, y );
900     wine_tsx11_lock();
901     if (dc->flags & DC_MEMORY)
902     {
903         image = XGetImage( gdi_display, physDev->drawable, x, y, 1, 1,
904                            AllPlanes, ZPixmap );
905     }
906     else
907     {
908         /* If we are reading from the screen, use a temporary copy */
909         /* to avoid a BadMatch error */
910         if (!pixmap) pixmap = XCreatePixmap( gdi_display, root_window,
911                                              1, 1, dc->bitsPerPixel );
912         XCopyArea( gdi_display, physDev->drawable, pixmap, BITMAP_colorGC,
913                    x, y, 1, 1, 0, 0 );
914         image = XGetImage( gdi_display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
915     }
916     pixel = XGetPixel( image, 0, 0 );
917     XDestroyImage( image );
918     wine_tsx11_unlock();
919
920     /* Update the DIBSection from the pixmap */
921     X11DRV_UnlockDIBSection(dc, FALSE);
922
923     return X11DRV_PALETTE_ToLogical(pixel);
924 }
925
926
927 /***********************************************************************
928  *           X11DRV_PaintRgn
929  */
930 BOOL
931 X11DRV_PaintRgn( DC *dc, HRGN hrgn )
932 {
933     RECT box;
934     HRGN tmpVisRgn, prevVisRgn;
935     HDC  hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
936     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
937
938     if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
939
940       /* Transform region into device co-ords */
941     if (  !REGION_LPTODP( hdc, tmpVisRgn, hrgn )
942         || OffsetRgn( tmpVisRgn, dc->DCOrgX, dc->DCOrgY ) == ERROR) {
943         DeleteObject( tmpVisRgn );
944         return FALSE;
945     }
946
947       /* Modify visible region */
948     if (!(prevVisRgn = SaveVisRgn16( hdc ))) {
949         DeleteObject( tmpVisRgn );
950         return FALSE;
951     }
952     CombineRgn( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
953     SelectVisRgn16( hdc, tmpVisRgn );
954     DeleteObject( tmpVisRgn );
955
956       /* Fill the region */
957
958     GetRgnBox( dc->hGCClipRgn, &box );
959     if (X11DRV_SetupGCForBrush( dc ))
960     {
961         /* Update the pixmap from the DIB section */
962         X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
963
964         TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
965                           box.left, box.top,
966                           box.right-box.left, box.bottom-box.top );
967     
968         /* Update the DIBSection from the pixmap */
969         X11DRV_UnlockDIBSection(dc, TRUE);
970     }
971
972       /* Restore the visible region */
973
974     RestoreVisRgn16( hdc );
975     return TRUE;
976 }
977
978 /**********************************************************************
979  *          X11DRV_Polyline
980  */
981 BOOL
982 X11DRV_Polyline( DC *dc, const POINT* pt, INT count )
983 {
984     INT oldwidth;
985     register int i;
986     XPoint *points;
987     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
988
989     if((oldwidth = physDev->pen.width) == 0) physDev->pen.width = 1;
990
991     if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * count )))
992     {
993         WARN("No memory to convert POINTs to XPoints!\n");
994         return FALSE;
995     }
996     for (i = 0; i < count; i++)
997     {
998         points[i].x = dc->DCOrgX + INTERNAL_XWPTODP( dc, pt[i].x, pt[i].y );
999         points[i].y = dc->DCOrgY + INTERNAL_YWPTODP( dc, pt[i].x, pt[i].y );
1000     }
1001
1002     if (X11DRV_SetupGCForPen ( dc ))
1003     {
1004         /* Update the pixmap from the DIB section */
1005         X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1006  
1007         TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
1008                       points, count, CoordModeOrigin );
1009
1010         /* Update the DIBSection from the pixmap */
1011         X11DRV_UnlockDIBSection(dc, TRUE);
1012     }
1013
1014     HeapFree( GetProcessHeap(), 0, points );
1015     physDev->pen.width = oldwidth;
1016     return TRUE;
1017 }
1018
1019
1020 /**********************************************************************
1021  *          X11DRV_Polygon
1022  */
1023 BOOL
1024 X11DRV_Polygon( DC *dc, const POINT* pt, INT count )
1025 {
1026     register int i;
1027     XPoint *points;
1028     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1029     BOOL update = FALSE;
1030
1031     if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) )))
1032     {
1033         WARN("No memory to convert POINTs to XPoints!\n");
1034         return FALSE;
1035     }
1036     for (i = 0; i < count; i++)
1037     {
1038         points[i].x = dc->DCOrgX + INTERNAL_XWPTODP( dc, pt[i].x, pt[i].y );
1039         points[i].y = dc->DCOrgY + INTERNAL_YWPTODP( dc, pt[i].x, pt[i].y );
1040     }
1041     points[count] = points[0];
1042
1043     /* Update the pixmap from the DIB section */
1044     X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1045  
1046     if (X11DRV_SetupGCForBrush( dc ))
1047     {
1048         TSXFillPolygon( gdi_display, physDev->drawable, physDev->gc,
1049                         points, count+1, Complex, CoordModeOrigin);
1050         update = TRUE;
1051     }
1052     if (X11DRV_SetupGCForPen ( dc ))
1053     {
1054         TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
1055                       points, count+1, CoordModeOrigin );
1056         update = TRUE;
1057     }
1058    
1059     /* Update the DIBSection from the pixmap */
1060     X11DRV_UnlockDIBSection(dc, update);
1061
1062     HeapFree( GetProcessHeap(), 0, points );
1063     return TRUE;
1064 }
1065
1066
1067 /**********************************************************************
1068  *          X11DRV_PolyPolygon
1069  */
1070 BOOL 
1071 X11DRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polygons)
1072 {
1073     HRGN hrgn;
1074     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1075
1076     /* FIXME: The points should be converted to device coords before */
1077     /* creating the region. */
1078
1079     hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->polyFillMode );
1080     X11DRV_PaintRgn( dc, hrgn );
1081     DeleteObject( hrgn );
1082
1083       /* Draw the outline of the polygons */
1084
1085     if (X11DRV_SetupGCForPen ( dc ))
1086     {
1087         int i, j, max = 0;
1088         XPoint *points;
1089
1090         /* Update the pixmap from the DIB section */
1091         X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1092  
1093         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
1094         if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (max+1) )))
1095         {
1096             WARN("No memory to convert POINTs to XPoints!\n");
1097             return FALSE;
1098         }
1099         for (i = 0; i < polygons; i++)
1100         {
1101             for (j = 0; j < counts[i]; j++)
1102             {
1103                 points[j].x = dc->DCOrgX + INTERNAL_XWPTODP( dc, pt->x, pt->y );
1104                 points[j].y = dc->DCOrgY + INTERNAL_YWPTODP( dc, pt->x, pt->y );
1105                 pt++;
1106             }
1107             points[j] = points[0];
1108             TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
1109                           points, j + 1, CoordModeOrigin );
1110         }
1111         
1112         /* Update the DIBSection of the dc's bitmap */
1113         X11DRV_UnlockDIBSection(dc, TRUE);
1114
1115         HeapFree( GetProcessHeap(), 0, points );
1116     }
1117     return TRUE;
1118 }
1119
1120
1121 /**********************************************************************
1122  *          X11DRV_PolyPolyline
1123  */
1124 BOOL 
1125 X11DRV_PolyPolyline( DC *dc, const POINT* pt, const DWORD* counts, DWORD polylines )
1126 {
1127     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1128     
1129     if (X11DRV_SetupGCForPen ( dc ))
1130     {
1131         int i, j, max = 0;
1132         XPoint *points;
1133
1134         /* Update the pixmap from the DIB section */
1135         X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1136  
1137         for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1138         if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * max )))
1139         {
1140             WARN("No memory to convert POINTs to XPoints!\n");
1141             return FALSE;
1142         }
1143         for (i = 0; i < polylines; i++)
1144         {
1145             for (j = 0; j < counts[i]; j++)
1146             {
1147                 points[j].x = dc->DCOrgX + INTERNAL_XWPTODP( dc, pt->x, pt->y );
1148                 points[j].y = dc->DCOrgY + INTERNAL_YWPTODP( dc, pt->x, pt->y );
1149                 pt++;
1150             }
1151             TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
1152                           points, j, CoordModeOrigin );
1153         }
1154         
1155         /* Update the DIBSection of the dc's bitmap */
1156         X11DRV_UnlockDIBSection(dc, TRUE);
1157
1158         HeapFree( GetProcessHeap(), 0, points );
1159     }
1160     return TRUE;
1161 }
1162
1163
1164 /**********************************************************************
1165  *          X11DRV_InternalFloodFill
1166  *
1167  * Internal helper function for flood fill.
1168  * (xorg,yorg) is the origin of the X image relative to the drawable.
1169  * (x,y) is relative to the origin of the X image.
1170  */
1171 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
1172                                      int x, int y,
1173                                      int xOrg, int yOrg,
1174                                      Pixel pixel, WORD fillType )
1175 {
1176     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1177     int left, right;
1178
1179 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
1180                         (XGetPixel(image,x,y) != pixel) : \
1181                         (XGetPixel(image,x,y) == pixel))
1182
1183     if (!TO_FLOOD(x,y)) return;
1184
1185       /* Find left and right boundaries */
1186
1187     left = right = x;
1188     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1189     while ((right < image->width) && TO_FLOOD( right, y )) right++;
1190     XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1191                     xOrg + left, yOrg + y, right-left, 1 );
1192
1193       /* Set the pixels of this line so we don't fill it again */
1194
1195     for (x = left; x < right; x++)
1196     {
1197         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1198         else XPutPixel( image, x, y, ~pixel );
1199     }
1200
1201       /* Fill the line above */
1202
1203     if (--y >= 0)
1204     {
1205         x = left;
1206         while (x < right)
1207         {
1208             while ((x < right) && !TO_FLOOD(x,y)) x++;
1209             if (x >= right) break;
1210             while ((x < right) && TO_FLOOD(x,y)) x++;
1211             X11DRV_InternalFloodFill(image, dc, x-1, y,
1212                                      xOrg, yOrg, pixel, fillType );
1213         }
1214     }
1215
1216       /* Fill the line below */
1217
1218     if ((y += 2) < image->height)
1219     {
1220         x = left;
1221         while (x < right)
1222         {
1223             while ((x < right) && !TO_FLOOD(x,y)) x++;
1224             if (x >= right) break;
1225             while ((x < right) && TO_FLOOD(x,y)) x++;
1226             X11DRV_InternalFloodFill(image, dc, x-1, y,
1227                                      xOrg, yOrg, pixel, fillType );
1228         }
1229     }
1230 #undef TO_FLOOD    
1231 }
1232
1233
1234 /**********************************************************************
1235  *          X11DRV_ExtFloodFill
1236  */
1237 BOOL
1238 X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color,
1239                      UINT fillType )
1240 {
1241     XImage *image;
1242     RECT rect;
1243     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1244
1245     TRACE("X11DRV_ExtFloodFill %d,%d %06lx %d\n", x, y, color, fillType );
1246
1247     if (!PtVisible( dc->hSelf, x, y )) return FALSE;
1248     if (GetRgnBox( dc->hGCClipRgn, &rect ) == ERROR) return FALSE;
1249
1250     if (!(image = TSXGetImage( gdi_display, physDev->drawable,
1251                                rect.left,
1252                                rect.top,
1253                                rect.right - rect.left,
1254                                rect.bottom - rect.top,
1255                                AllPlanes, ZPixmap ))) return FALSE;
1256
1257     wine_tsx11_lock();
1258     if (X11DRV_SetupGCForBrush( dc ))
1259     {
1260         /* Update the pixmap from the DIB section */
1261         X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1262
1263           /* ROP mode is always GXcopy for flood-fill */
1264         XSetFunction( gdi_display, physDev->gc, GXcopy );
1265         X11DRV_InternalFloodFill(image, dc,
1266                                  XLPTODP(dc,x) + dc->DCOrgX - rect.left,
1267                                  YLPTODP(dc,y) + dc->DCOrgY - rect.top,
1268                                  rect.left, rect.top,
1269                                  X11DRV_PALETTE_ToPhysical( dc, color ),
1270                                  fillType );
1271         /* Update the DIBSection of the dc's bitmap */
1272         X11DRV_UnlockDIBSection(dc, TRUE);
1273     }
1274
1275     XDestroyImage( image );
1276     wine_tsx11_unlock();
1277     return TRUE;
1278 }
1279
1280 /**********************************************************************
1281  *          X11DRV_SetBkColor
1282  */
1283 COLORREF
1284 X11DRV_SetBkColor( DC *dc, COLORREF color )
1285 {
1286     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1287     COLORREF oldColor;
1288
1289     oldColor = dc->backgroundColor;
1290     dc->backgroundColor = color;
1291
1292     physDev->backgroundPixel = X11DRV_PALETTE_ToPhysical( dc, color );
1293
1294     return oldColor;
1295 }
1296
1297 /**********************************************************************
1298  *          X11DRV_SetTextColor
1299  */
1300 COLORREF
1301 X11DRV_SetTextColor( DC *dc, COLORREF color )
1302 {
1303     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1304     COLORREF oldColor;
1305
1306     oldColor = dc->textColor;
1307     dc->textColor = color;
1308
1309     physDev->textPixel = X11DRV_PALETTE_ToPhysical( dc, color );
1310
1311     return oldColor;
1312 }
1313
1314 /***********************************************************************
1315  *           X11DRV_GetDCOrgEx
1316  */
1317 BOOL X11DRV_GetDCOrgEx( DC *dc, LPPOINT lpp )
1318 {
1319     if (!(dc->flags & DC_MEMORY))
1320     {
1321        X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *) dc->physDev;
1322        Window root;
1323        int x, y, w, h, border, depth;
1324
1325        /* FIXME: this is not correct for managed windows */
1326        TSXGetGeometry( gdi_display, physDev->drawable, &root,
1327                        &x, &y, &w, &h, &border, &depth );
1328        lpp->x = x;
1329        lpp->y = y;
1330     }
1331     else lpp->x = lpp->y = 0;
1332     return TRUE;
1333 }
1334