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