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