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