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