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