winex11: Fix the positioning of some graphics primitives on mirrored contexts.
[wine] / dlls / winex11.drv / graphics.c
1 /*
2  * X11 graphics driver graphics functions
3  *
4  * Copyright 1993,1994 Alexandre Julliard
5  * Copyright 1998 Huw Davies
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 /*
23  * FIXME: only some of these functions obey the GM_ADVANCED
24  * graphics mode
25  */
26
27 #include "config.h"
28
29 #include <stdarg.h>
30 #include <math.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include <stdlib.h>
35 #ifndef PI
36 #define PI M_PI
37 #endif
38 #include <string.h>
39 #include <limits.h>
40
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winreg.h"
44
45 #include "x11drv.h"
46 #include "x11font.h"
47 #include "wine/debug.h"
48 #include "wine/unicode.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(graphics);
51
52 #define ABS(x)    ((x)<0?(-(x)):(x))
53
54   /* ROP code to GC function conversion */
55 const int X11DRV_XROPfunction[16] =
56 {
57     GXclear,        /* R2_BLACK */
58     GXnor,          /* R2_NOTMERGEPEN */
59     GXandInverted,  /* R2_MASKNOTPEN */
60     GXcopyInverted, /* R2_NOTCOPYPEN */
61     GXandReverse,   /* R2_MASKPENNOT */
62     GXinvert,       /* R2_NOT */
63     GXxor,          /* R2_XORPEN */
64     GXnand,         /* R2_NOTMASKPEN */
65     GXand,          /* R2_MASKPEN */
66     GXequiv,        /* R2_NOTXORPEN */
67     GXnoop,         /* R2_NOP */
68     GXorInverted,   /* R2_MERGENOTPEN */
69     GXcopy,         /* R2_COPYPEN */
70     GXorReverse,    /* R2_MERGEPENNOT */
71     GXor,           /* R2_MERGEPEN */
72     GXset           /* R2_WHITE */
73 };
74
75
76 /* get the rectangle in device coordinates, with optional mirroring */
77 static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom )
78 {
79     RECT rect;
80
81     rect.left   = left;
82     rect.top    = top;
83     rect.right  = right;
84     rect.bottom = bottom;
85     LPtoDP( hdc, (POINT *)&rect, 2 );
86     if (GetLayout( hdc ) & LAYOUT_RTL)
87     {
88         int tmp = rect.left;
89         rect.left = rect.right + 1;
90         rect.right = tmp + 1;
91     }
92     if (rect.left > rect.right)
93     {
94         int tmp = rect.left;
95         rect.left = rect.right;
96         rect.right = tmp;
97     }
98     if (rect.top > rect.bottom)
99     {
100         int tmp = rect.top;
101         rect.top = rect.bottom;
102         rect.bottom = tmp;
103     }
104     return rect;
105 }
106
107 /***********************************************************************
108  *           X11DRV_GetRegionData
109  *
110  * Calls GetRegionData on the given region and converts the rectangle
111  * array to XRectangle format. The returned buffer must be freed by
112  * caller using HeapFree(GetProcessHeap(),...).
113  * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
114  */
115 RGNDATA *X11DRV_GetRegionData( HRGN hrgn, HDC hdc_lptodp )
116 {
117     RGNDATA *data;
118     DWORD size;
119     unsigned int i;
120     RECT *rect, tmp;
121     XRectangle *xrect;
122
123     if (!(size = GetRegionData( hrgn, 0, NULL ))) return NULL;
124     if (sizeof(XRectangle) > sizeof(RECT))
125     {
126         /* add extra size for XRectangle array */
127         int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
128         size += count * (sizeof(XRectangle) - sizeof(RECT));
129     }
130     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
131     if (!GetRegionData( hrgn, size, data ))
132     {
133         HeapFree( GetProcessHeap(), 0, data );
134         return NULL;
135     }
136
137     rect = (RECT *)data->Buffer;
138     xrect = (XRectangle *)data->Buffer;
139     if (hdc_lptodp)  /* map to device coordinates */
140     {
141         LPtoDP( hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2 );
142         for (i = 0; i < data->rdh.nCount; i++)
143         {
144             if (rect[i].right < rect[i].left)
145             {
146                 INT tmp = rect[i].right;
147                 rect[i].right = rect[i].left;
148                 rect[i].left = tmp;
149             }
150             if (rect[i].bottom < rect[i].top)
151             {
152                 INT tmp = rect[i].bottom;
153                 rect[i].bottom = rect[i].top;
154                 rect[i].top = tmp;
155             }
156         }
157     }
158
159     if (sizeof(XRectangle) > sizeof(RECT))
160     {
161         int j;
162         /* need to start from the end */
163         for (j = data->rdh.nCount-1; j >= 0; j--)
164         {
165             tmp = rect[j];
166             xrect[j].x      = max( min( tmp.left, SHRT_MAX), SHRT_MIN);
167             xrect[j].y      = max( min( tmp.top, SHRT_MAX), SHRT_MIN);
168             xrect[j].width  = max( min( tmp.right - xrect[j].x, USHRT_MAX), 0);
169             xrect[j].height = max( min( tmp.bottom - xrect[j].y, USHRT_MAX), 0);
170         }
171     }
172     else
173     {
174         for (i = 0; i < data->rdh.nCount; i++)
175         {
176             tmp = rect[i];
177             xrect[i].x      = max( min( tmp.left, SHRT_MAX), SHRT_MIN);
178             xrect[i].y      = max( min( tmp.top, SHRT_MAX), SHRT_MIN);
179             xrect[i].width  = max( min( tmp.right - xrect[i].x, USHRT_MAX), 0);
180             xrect[i].height = max( min( tmp.bottom - xrect[i].y, USHRT_MAX), 0);
181         }
182     }
183     return data;
184 }
185
186
187 /***********************************************************************
188  *           X11DRV_SetDeviceClipping
189  */
190 void CDECL X11DRV_SetDeviceClipping( X11DRV_PDEVICE *physDev, HRGN vis_rgn, HRGN clip_rgn )
191 {
192     RGNDATA *data;
193
194     CombineRgn( physDev->region, vis_rgn, clip_rgn, clip_rgn ? RGN_AND : RGN_COPY );
195     if (!(data = X11DRV_GetRegionData( physDev->region, 0 ))) return;
196
197     wine_tsx11_lock();
198     XSetClipRectangles( gdi_display, physDev->gc, physDev->dc_rect.left, physDev->dc_rect.top,
199                         (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
200     wine_tsx11_unlock();
201
202     if (physDev->xrender) X11DRV_XRender_SetDeviceClipping(physDev, data);
203
204     HeapFree( GetProcessHeap(), 0, data );
205 }
206
207
208 /***********************************************************************
209  *           X11DRV_SetupGCForPatBlt
210  *
211  * Setup the GC for a PatBlt operation using current brush.
212  * If fMapColors is TRUE, X pixels are mapped to Windows colors.
213  * Return FALSE if brush is BS_NULL, TRUE otherwise.
214  */
215 BOOL X11DRV_SetupGCForPatBlt( X11DRV_PDEVICE *physDev, GC gc, BOOL fMapColors )
216 {
217     XGCValues val;
218     unsigned long mask;
219     Pixmap pixmap = 0;
220     POINT pt;
221
222     if (physDev->brush.style == BS_NULL) return FALSE;
223     if (physDev->brush.pixel == -1)
224     {
225         /* Special case used for monochrome pattern brushes.
226          * We need to swap foreground and background because
227          * Windows does it the wrong way...
228          */
229         val.foreground = physDev->backgroundPixel;
230         val.background = physDev->textPixel;
231     }
232     else
233     {
234         val.foreground = physDev->brush.pixel;
235         val.background = physDev->backgroundPixel;
236     }
237     if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
238     {
239         val.foreground = X11DRV_PALETTE_XPixelToPalette[val.foreground];
240         val.background = X11DRV_PALETTE_XPixelToPalette[val.background];
241     }
242
243     val.function = X11DRV_XROPfunction[GetROP2(physDev->hdc)-1];
244     /*
245     ** Let's replace GXinvert by GXxor with (black xor white)
246     ** This solves the selection color and leak problems in excel
247     ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
248     */
249     if (val.function == GXinvert)
250     {
251         val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
252                           BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
253         val.function = GXxor;
254     }
255     val.fill_style = physDev->brush.fillStyle;
256     switch(val.fill_style)
257     {
258     case FillStippled:
259     case FillOpaqueStippled:
260         if (GetBkMode(physDev->hdc)==OPAQUE) val.fill_style = FillOpaqueStippled;
261         val.stipple = physDev->brush.pixmap;
262         mask = GCStipple;
263         break;
264
265     case FillTiled:
266         if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
267         {
268             register int x, y;
269             XImage *image;
270             wine_tsx11_lock();
271             pixmap = XCreatePixmap( gdi_display, root_window, 8, 8, physDev->depth );
272             image = XGetImage( gdi_display, physDev->brush.pixmap, 0, 0, 8, 8,
273                                AllPlanes, ZPixmap );
274             for (y = 0; y < 8; y++)
275                 for (x = 0; x < 8; x++)
276                     XPutPixel( image, x, y,
277                                X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] );
278             XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
279             XDestroyImage( image );
280             wine_tsx11_unlock();
281             val.tile = pixmap;
282         }
283         else val.tile = physDev->brush.pixmap;
284         mask = GCTile;
285         break;
286
287     default:
288         mask = 0;
289         break;
290     }
291     GetBrushOrgEx( physDev->hdc, &pt );
292     val.ts_x_origin = physDev->dc_rect.left + pt.x;
293     val.ts_y_origin = physDev->dc_rect.top + pt.y;
294     val.fill_rule = (GetPolyFillMode(physDev->hdc) == WINDING) ? WindingRule : EvenOddRule;
295     wine_tsx11_lock();
296     XChangeGC( gdi_display, gc,
297                GCFunction | GCForeground | GCBackground | GCFillStyle |
298                GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
299                &val );
300     if (pixmap) XFreePixmap( gdi_display, pixmap );
301     wine_tsx11_unlock();
302     return TRUE;
303 }
304
305
306 /***********************************************************************
307  *           X11DRV_SetupGCForBrush
308  *
309  * Setup physDev->gc for drawing operations using current brush.
310  * Return FALSE if brush is BS_NULL, TRUE otherwise.
311  */
312 BOOL X11DRV_SetupGCForBrush( X11DRV_PDEVICE *physDev )
313 {
314     return X11DRV_SetupGCForPatBlt( physDev, physDev->gc, FALSE );
315 }
316
317
318 /***********************************************************************
319  *           X11DRV_SetupGCForPen
320  *
321  * Setup physDev->gc for drawing operations using current pen.
322  * Return FALSE if pen is PS_NULL, TRUE otherwise.
323  */
324 static BOOL X11DRV_SetupGCForPen( X11DRV_PDEVICE *physDev )
325 {
326     XGCValues val;
327     UINT rop2 = GetROP2(physDev->hdc);
328
329     if (physDev->pen.style == PS_NULL) return FALSE;
330
331     switch (rop2)
332     {
333     case R2_BLACK :
334         val.foreground = BlackPixel( gdi_display, DefaultScreen(gdi_display) );
335         val.function = GXcopy;
336         break;
337     case R2_WHITE :
338         val.foreground = WhitePixel( gdi_display, DefaultScreen(gdi_display) );
339         val.function = GXcopy;
340         break;
341     case R2_XORPEN :
342         val.foreground = physDev->pen.pixel;
343         /* It is very unlikely someone wants to XOR with 0 */
344         /* This fixes the rubber-drawings in paintbrush */
345         if (val.foreground == 0)
346             val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
347                               BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
348         val.function = GXxor;
349         break;
350     default :
351         val.foreground = physDev->pen.pixel;
352         val.function   = X11DRV_XROPfunction[rop2-1];
353     }
354     val.background = physDev->backgroundPixel;
355     val.fill_style = FillSolid;
356     val.line_width = physDev->pen.width;
357     if (val.line_width <= 1) {
358         val.cap_style = CapNotLast;
359     } else {
360         switch (physDev->pen.endcap)
361         {
362         case PS_ENDCAP_SQUARE:
363             val.cap_style = CapProjecting;
364             break;
365         case PS_ENDCAP_FLAT:
366             val.cap_style = CapButt;
367             break;
368         case PS_ENDCAP_ROUND:
369         default:
370             val.cap_style = CapRound;
371         }
372     }
373     switch (physDev->pen.linejoin)
374     {
375     case PS_JOIN_BEVEL:
376         val.join_style = JoinBevel;
377         break;
378     case PS_JOIN_MITER:
379         val.join_style = JoinMiter;
380         break;
381     case PS_JOIN_ROUND:
382     default:
383         val.join_style = JoinRound;
384     }
385
386     if (physDev->pen.dash_len)
387         val.line_style = ((GetBkMode(physDev->hdc) == OPAQUE) && (!physDev->pen.ext))
388                          ? LineDoubleDash : LineOnOffDash;
389     else
390         val.line_style = LineSolid;
391
392     wine_tsx11_lock();
393     if (physDev->pen.dash_len)
394         XSetDashes( gdi_display, physDev->gc, 0, physDev->pen.dashes, physDev->pen.dash_len );
395     XChangeGC( gdi_display, physDev->gc,
396                GCFunction | GCForeground | GCBackground | GCLineWidth |
397                GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
398     wine_tsx11_unlock();
399     return TRUE;
400 }
401
402
403 /***********************************************************************
404  *           X11DRV_SetupGCForText
405  *
406  * Setup physDev->gc for text drawing operations.
407  * Return FALSE if the font is null, TRUE otherwise.
408  */
409 BOOL X11DRV_SetupGCForText( X11DRV_PDEVICE *physDev )
410 {
411     XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
412
413     if( xfs )
414     {
415         XGCValues val;
416
417         val.function   = GXcopy;  /* Text is always GXcopy */
418         val.foreground = physDev->textPixel;
419         val.background = physDev->backgroundPixel;
420         val.fill_style = FillSolid;
421         val.font       = xfs->fid;
422
423         wine_tsx11_lock();
424         XChangeGC( gdi_display, physDev->gc,
425                    GCFunction | GCForeground | GCBackground | GCFillStyle |
426                    GCFont, &val );
427         wine_tsx11_unlock();
428         return TRUE;
429     }
430     WARN("Physical font failure\n" );
431     return FALSE;
432 }
433
434 /***********************************************************************
435  *           X11DRV_XWStoDS
436  *
437  * Performs a world-to-viewport transformation on the specified width.
438  */
439 INT X11DRV_XWStoDS( X11DRV_PDEVICE *physDev, INT width )
440 {
441     POINT pt[2];
442
443     pt[0].x = 0;
444     pt[0].y = 0;
445     pt[1].x = width;
446     pt[1].y = 0;
447     LPtoDP( physDev->hdc, pt, 2 );
448     return pt[1].x - pt[0].x;
449 }
450
451 /***********************************************************************
452  *           X11DRV_YWStoDS
453  *
454  * Performs a world-to-viewport transformation on the specified height.
455  */
456 INT X11DRV_YWStoDS( X11DRV_PDEVICE *physDev, INT height )
457 {
458     POINT pt[2];
459
460     pt[0].x = 0;
461     pt[0].y = 0;
462     pt[1].x = 0;
463     pt[1].y = height;
464     LPtoDP( physDev->hdc, pt, 2 );
465     return pt[1].y - pt[0].y;
466 }
467
468 /***********************************************************************
469  *           X11DRV_LineTo
470  */
471 BOOL CDECL
472 X11DRV_LineTo( X11DRV_PDEVICE *physDev, INT x, INT y )
473 {
474     POINT pt[2];
475
476     if (X11DRV_SetupGCForPen( physDev )) {
477         /* Update the pixmap from the DIB section */
478         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
479
480         GetCurrentPositionEx( physDev->hdc, &pt[0] );
481         pt[1].x = x;
482         pt[1].y = y;
483         LPtoDP( physDev->hdc, pt, 2 );
484
485         wine_tsx11_lock();
486         XDrawLine(gdi_display, physDev->drawable, physDev->gc,
487                   physDev->dc_rect.left + pt[0].x, physDev->dc_rect.top + pt[0].y,
488                   physDev->dc_rect.left + pt[1].x, physDev->dc_rect.top + pt[1].y );
489         wine_tsx11_unlock();
490
491         /* Update the DIBSection from the pixmap */
492         X11DRV_UnlockDIBSection(physDev, TRUE);
493     }
494     return TRUE;
495 }
496
497
498
499 /***********************************************************************
500  *           X11DRV_DrawArc
501  *
502  * Helper functions for Arc(), Chord() and Pie().
503  * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
504  *
505  */
506 static BOOL
507 X11DRV_DrawArc( X11DRV_PDEVICE *physDev, INT left, INT top, INT right,
508                 INT bottom, INT xstart, INT ystart,
509                 INT xend, INT yend, INT lines )
510 {
511     INT xcenter, ycenter, istart_angle, idiff_angle;
512     INT width, oldwidth;
513     double start_angle, end_angle;
514     XPoint points[4];
515     BOOL update = FALSE;
516     POINT start, end;
517     RECT rc = get_device_rect( physDev->hdc, left, top, right, bottom );
518
519     start.x = xstart;
520     start.y = ystart;
521     end.x = xend;
522     end.y = yend;
523     LPtoDP(physDev->hdc, &start, 1);
524     LPtoDP(physDev->hdc, &end, 1);
525
526     if ((rc.left == rc.right) || (rc.top == rc.bottom)
527             ||(lines && ((rc.right-rc.left==1)||(rc.bottom-rc.top==1)))) return TRUE;
528
529     if (GetArcDirection( physDev->hdc ) == AD_CLOCKWISE)
530       { POINT tmp = start; start = end; end = tmp; }
531
532     oldwidth = width = physDev->pen.width;
533     if (!width) width = 1;
534     if(physDev->pen.style == PS_NULL) width = 0;
535
536     if ((physDev->pen.style == PS_INSIDEFRAME))
537     {
538         if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
539         if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
540         rc.left   += width / 2;
541         rc.right  -= (width - 1) / 2;
542         rc.top    += width / 2;
543         rc.bottom -= (width - 1) / 2;
544     }
545     if(width == 0) width = 1; /* more accurate */
546     physDev->pen.width = width;
547
548     xcenter = (rc.right + rc.left) / 2;
549     ycenter = (rc.bottom + rc.top) / 2;
550     start_angle = atan2( (double)(ycenter-start.y)*(rc.right-rc.left),
551                          (double)(start.x-xcenter)*(rc.bottom-rc.top) );
552     end_angle   = atan2( (double)(ycenter-end.y)*(rc.right-rc.left),
553                          (double)(end.x-xcenter)*(rc.bottom-rc.top) );
554     if ((start.x==end.x)&&(start.y==end.y))
555       { /* A lazy program delivers xstart=xend=ystart=yend=0) */
556         start_angle = 0;
557         end_angle = 2* PI;
558       }
559     else /* notorious cases */
560       if ((start_angle == PI)&&( end_angle <0))
561         start_angle = - PI;
562     else
563       if ((end_angle == PI)&&( start_angle <0))
564         end_angle = - PI;
565     istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
566     idiff_angle  = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
567     if (idiff_angle <= 0) idiff_angle += 360 * 64;
568
569     /* Update the pixmap from the DIB section */
570     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
571
572       /* Fill arc with brush if Chord() or Pie() */
573
574     if ((lines > 0) && X11DRV_SetupGCForBrush( physDev )) {
575         wine_tsx11_lock();
576         XSetArcMode( gdi_display, physDev->gc, (lines==1) ? ArcChord : ArcPieSlice);
577         XFillArc( gdi_display, physDev->drawable, physDev->gc,
578                   physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
579                   rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
580         wine_tsx11_unlock();
581         update = TRUE;
582     }
583
584       /* Draw arc and lines */
585
586     if (X11DRV_SetupGCForPen( physDev ))
587     {
588         wine_tsx11_lock();
589         XDrawArc( gdi_display, physDev->drawable, physDev->gc,
590                   physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
591                   rc.right-rc.left-1, rc.bottom-rc.top-1, istart_angle, idiff_angle );
592         if (lines) {
593             /* use the truncated values */
594             start_angle=(double)istart_angle*PI/64./180.;
595             end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
596             /* calculate the endpoints and round correctly */
597             points[0].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
598                     cos(start_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
599             points[0].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
600                     sin(start_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
601             points[1].x = (int) floor(physDev->dc_rect.left + (rc.right+rc.left)/2.0 +
602                     cos(end_angle) * (rc.right-rc.left-width*2+2) / 2. + 0.5);
603             points[1].y = (int) floor(physDev->dc_rect.top + (rc.top+rc.bottom)/2.0 -
604                     sin(end_angle) * (rc.bottom-rc.top-width*2+2) / 2. + 0.5);
605
606             /* OK, this stuff is optimized for Xfree86
607              * which is probably the server most used by
608              * wine users. Other X servers will not
609              * display correctly. (eXceed for instance)
610              * so if you feel you must make changes, make sure that
611              * you either use Xfree86 or separate your changes
612              * from these (compile switch or whatever)
613              */
614             if (lines == 2) {
615                 INT dx1,dy1;
616                 points[3] = points[1];
617                 points[1].x = physDev->dc_rect.left + xcenter;
618                 points[1].y = physDev->dc_rect.top + ycenter;
619                 points[2] = points[1];
620                 dx1=points[1].x-points[0].x;
621                 dy1=points[1].y-points[0].y;
622                 if(((rc.top-rc.bottom) | -2) == -2)
623                     if(dy1>0) points[1].y--;
624                 if(dx1<0) {
625                     if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
626                     if(((-dx1*9))<(dy1*16)) points[0].y--;
627                     if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
628                 } else {
629                     if(dy1 < 0)  points[0].y--;
630                     if(((rc.right-rc.left) | -2) == -2) points[1].x--;
631                 }
632                 dx1=points[3].x-points[2].x;
633                 dy1=points[3].y-points[2].y;
634                 if(((rc.top-rc.bottom) | -2 ) == -2)
635                     if(dy1 < 0) points[2].y--;
636                 if( dx1<0){
637                     if( dy1>0) points[3].y--;
638                     if(((rc.right-rc.left) | -2) == -2 ) points[2].x--;
639                 }else {
640                     points[3].y--;
641                     if( dx1 * 64 < dy1 * -37 ) points[3].x--;
642                 }
643                 lines++;
644             }
645             XDrawLines( gdi_display, physDev->drawable, physDev->gc,
646                         points, lines+1, CoordModeOrigin );
647         }
648         wine_tsx11_unlock();
649         update = TRUE;
650     }
651
652     /* Update the DIBSection of the pixmap */
653     X11DRV_UnlockDIBSection(physDev, update);
654
655     physDev->pen.width = oldwidth;
656     return TRUE;
657 }
658
659
660 /***********************************************************************
661  *           X11DRV_Arc
662  */
663 BOOL CDECL
664 X11DRV_Arc( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
665             INT xstart, INT ystart, INT xend, INT yend )
666 {
667     return X11DRV_DrawArc( physDev, left, top, right, bottom,
668                            xstart, ystart, xend, yend, 0 );
669 }
670
671
672 /***********************************************************************
673  *           X11DRV_Pie
674  */
675 BOOL CDECL
676 X11DRV_Pie( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
677             INT xstart, INT ystart, INT xend, INT yend )
678 {
679     return X11DRV_DrawArc( physDev, left, top, right, bottom,
680                            xstart, ystart, xend, yend, 2 );
681 }
682
683 /***********************************************************************
684  *           X11DRV_Chord
685  */
686 BOOL CDECL
687 X11DRV_Chord( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom,
688               INT xstart, INT ystart, INT xend, INT yend )
689 {
690     return X11DRV_DrawArc( physDev, left, top, right, bottom,
691                            xstart, ystart, xend, yend, 1 );
692 }
693
694
695 /***********************************************************************
696  *           X11DRV_Ellipse
697  */
698 BOOL CDECL
699 X11DRV_Ellipse( X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom )
700 {
701     INT width, oldwidth;
702     BOOL update = FALSE;
703     RECT rc = get_device_rect( physDev->hdc, left, top, right, bottom );
704
705     if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
706
707     oldwidth = width = physDev->pen.width;
708     if (!width) width = 1;
709     if(physDev->pen.style == PS_NULL) width = 0;
710
711     if ((physDev->pen.style == PS_INSIDEFRAME))
712     {
713         if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
714         if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
715         rc.left   += width / 2;
716         rc.right  -= (width - 1) / 2;
717         rc.top    += width / 2;
718         rc.bottom -= (width - 1) / 2;
719     }
720     if(width == 0) width = 1; /* more accurate */
721     physDev->pen.width = width;
722
723     /* Update the pixmap from the DIB section */
724     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
725
726     if (X11DRV_SetupGCForBrush( physDev ))
727     {
728         wine_tsx11_lock();
729         XFillArc( gdi_display, physDev->drawable, physDev->gc,
730                   physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
731                   rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
732         wine_tsx11_unlock();
733         update = TRUE;
734     }
735     if (X11DRV_SetupGCForPen( physDev ))
736     {
737         wine_tsx11_lock();
738         XDrawArc( gdi_display, physDev->drawable, physDev->gc,
739                   physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
740                   rc.right-rc.left-1, rc.bottom-rc.top-1, 0, 360*64 );
741         wine_tsx11_unlock();
742         update = TRUE;
743     }
744
745     /* Update the DIBSection from the pixmap */
746     X11DRV_UnlockDIBSection(physDev, update);
747
748     physDev->pen.width = oldwidth;
749     return TRUE;
750 }
751
752
753 /***********************************************************************
754  *           X11DRV_Rectangle
755  */
756 BOOL CDECL
757 X11DRV_Rectangle(X11DRV_PDEVICE *physDev, INT left, INT top, INT right, INT bottom)
758 {
759     INT width, oldwidth, oldjoinstyle;
760     BOOL update = FALSE;
761     RECT rc = get_device_rect( physDev->hdc, left, top, right, bottom );
762
763     TRACE("(%d %d %d %d)\n", left, top, right, bottom);
764
765     if ((rc.left == rc.right) || (rc.top == rc.bottom)) return TRUE;
766
767     oldwidth = width = physDev->pen.width;
768     if (!width) width = 1;
769     if(physDev->pen.style == PS_NULL) width = 0;
770
771     if ((physDev->pen.style == PS_INSIDEFRAME))
772     {
773         if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
774         if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
775         rc.left   += width / 2;
776         rc.right  -= (width - 1) / 2;
777         rc.top    += width / 2;
778         rc.bottom -= (width - 1) / 2;
779     }
780     if(width == 1) width = 0;
781     physDev->pen.width = width;
782     oldjoinstyle = physDev->pen.linejoin;
783     if(physDev->pen.type != PS_GEOMETRIC)
784         physDev->pen.linejoin = PS_JOIN_MITER;
785
786     /* Update the pixmap from the DIB section */
787     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
788
789     if ((rc.right > rc.left + width) && (rc.bottom > rc.top + width))
790     {
791         if (X11DRV_SetupGCForBrush( physDev ))
792         {
793             wine_tsx11_lock();
794             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
795                             physDev->dc_rect.left + rc.left + (width + 1) / 2,
796                             physDev->dc_rect.top + rc.top + (width + 1) / 2,
797                             rc.right-rc.left-width-1, rc.bottom-rc.top-width-1);
798             wine_tsx11_unlock();
799             update = TRUE;
800         }
801     }
802     if (X11DRV_SetupGCForPen( physDev ))
803     {
804         wine_tsx11_lock();
805         XDrawRectangle( gdi_display, physDev->drawable, physDev->gc,
806                         physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
807                         rc.right-rc.left-1, rc.bottom-rc.top-1 );
808         wine_tsx11_unlock();
809         update = TRUE;
810     }
811
812     /* Update the DIBSection from the pixmap */
813     X11DRV_UnlockDIBSection(physDev, update);
814
815     physDev->pen.width = oldwidth;
816     physDev->pen.linejoin = oldjoinstyle;
817     return TRUE;
818 }
819
820 /***********************************************************************
821  *           X11DRV_RoundRect
822  */
823 BOOL CDECL
824 X11DRV_RoundRect( X11DRV_PDEVICE *physDev, INT left, INT top, INT right,
825                   INT bottom, INT ell_width, INT ell_height )
826 {
827     INT width, oldwidth, oldendcap;
828     BOOL update = FALSE;
829     POINT pts[2];
830     RECT rc = get_device_rect( physDev->hdc, left, top, right, bottom );
831
832     TRACE("(%d %d %d %d  %d %d\n",
833         left, top, right, bottom, ell_width, ell_height);
834
835     if ((rc.left == rc.right) || (rc.top == rc.bottom))
836         return TRUE;
837
838     /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
839        called with width/height < 0 */
840     pts[0].x = pts[0].y = 0;
841     pts[1].x = ell_width;
842     pts[1].y = ell_height;
843     LPtoDP(physDev->hdc, pts, 2);
844     ell_width  = max(abs( pts[1].x - pts[0].x ), 1);
845     ell_height = max(abs( pts[1].y - pts[0].y ), 1);
846
847     oldwidth = width = physDev->pen.width;
848     oldendcap = physDev->pen.endcap;
849     if (!width) width = 1;
850     if(physDev->pen.style == PS_NULL) width = 0;
851
852     if ((physDev->pen.style == PS_INSIDEFRAME))
853     {
854         if (2*width > (rc.right-rc.left)) width=(rc.right-rc.left + 1)/2;
855         if (2*width > (rc.bottom-rc.top)) width=(rc.bottom-rc.top + 1)/2;
856         rc.left   += width / 2;
857         rc.right  -= (width - 1) / 2;
858         rc.top    += width / 2;
859         rc.bottom -= (width - 1) / 2;
860     }
861     if(width == 0) width = 1;
862     physDev->pen.width = width;
863     physDev->pen.endcap = PS_ENDCAP_SQUARE;
864
865     /* Update the pixmap from the DIB section */
866     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
867
868     if (X11DRV_SetupGCForBrush( physDev ))
869     {
870         wine_tsx11_lock();
871         if (ell_width > (rc.right-rc.left) )
872             if (ell_height > (rc.bottom-rc.top) )
873                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
874                           physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
875                           rc.right - rc.left - 1, rc.bottom - rc.top - 1,
876                           0, 360 * 64 );
877             else{
878                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
879                           physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
880                           rc.right - rc.left - 1, ell_height, 0, 180 * 64 );
881                 XFillArc( gdi_display, physDev->drawable, physDev->gc,
882                           physDev->dc_rect.left + rc.left,
883                           physDev->dc_rect.top + rc.bottom - ell_height - 1,
884                           rc.right - rc.left - 1, ell_height, 180 * 64,
885                           180 * 64 );
886             }
887         else if (ell_height > (rc.bottom-rc.top) ){
888             XFillArc( gdi_display, physDev->drawable, physDev->gc,
889                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
890                       ell_width, rc.bottom - rc.top - 1, 90 * 64, 180 * 64 );
891             XFillArc( gdi_display, physDev->drawable, physDev->gc,
892                       physDev->dc_rect.left + rc.right - ell_width - 1, physDev->dc_rect.top + rc.top,
893                       ell_width, rc.bottom - rc.top - 1, 270 * 64, 180 * 64 );
894         }else{
895             XFillArc( gdi_display, physDev->drawable, physDev->gc,
896                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
897                       ell_width, ell_height, 90 * 64, 90 * 64 );
898             XFillArc( gdi_display, physDev->drawable, physDev->gc,
899                       physDev->dc_rect.left + rc.left,
900                       physDev->dc_rect.top + rc.bottom - ell_height - 1,
901                       ell_width, ell_height, 180 * 64, 90 * 64 );
902             XFillArc( gdi_display, physDev->drawable, physDev->gc,
903                       physDev->dc_rect.left + rc.right - ell_width - 1,
904                       physDev->dc_rect.top + rc.bottom - ell_height - 1,
905                       ell_width, ell_height, 270 * 64, 90 * 64 );
906             XFillArc( gdi_display, physDev->drawable, physDev->gc,
907                       physDev->dc_rect.left + rc.right - ell_width - 1,
908                       physDev->dc_rect.top + rc.top,
909                       ell_width, ell_height, 0, 90 * 64 );
910         }
911         if (ell_width < rc.right - rc.left)
912         {
913             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
914                             physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
915                             physDev->dc_rect.top + rc.top + 1,
916                             rc.right - rc.left - ell_width - 1,
917                             (ell_height + 1) / 2 - 1);
918             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
919                             physDev->dc_rect.left + rc.left + (ell_width + 1) / 2,
920                             physDev->dc_rect.top + rc.bottom - (ell_height) / 2 - 1,
921                             rc.right - rc.left - ell_width - 1,
922                             (ell_height) / 2 );
923         }
924         if  (ell_height < rc.bottom - rc.top)
925         {
926             XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
927                             physDev->dc_rect.left + rc.left + 1,
928                             physDev->dc_rect.top + rc.top + (ell_height + 1) / 2,
929                             rc.right - rc.left - 2,
930                             rc.bottom - rc.top - ell_height - 1);
931         }
932         wine_tsx11_unlock();
933         update = TRUE;
934     }
935     /* FIXME: this could be done with on X call
936      * more efficient and probably more correct
937      * on any X server: XDrawArcs will draw
938      * straight horizontal and vertical lines
939      * if width or height are zero.
940      *
941      * BTW this stuff is optimized for an Xfree86 server
942      * read the comments inside the X11DRV_DrawArc function
943      */
944     if (X11DRV_SetupGCForPen( physDev ))
945     {
946         wine_tsx11_lock();
947         if (ell_width > (rc.right-rc.left) )
948             if (ell_height > (rc.bottom-rc.top) )
949                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
950                           physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
951                           rc.right - rc.left - 1, rc.bottom - rc.top - 1, 0 , 360 * 64 );
952             else{
953                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
954                           physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
955                           rc.right - rc.left - 1, ell_height - 1, 0 , 180 * 64 );
956                 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
957                           physDev->dc_rect.left + rc.left,
958                           physDev->dc_rect.top + rc.bottom - ell_height,
959                           rc.right - rc.left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
960             }
961         else if (ell_height > (rc.bottom-rc.top) ){
962             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
963                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
964                       ell_width - 1 , rc.bottom - rc.top - 1, 90 * 64 , 180 * 64 );
965             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
966                       physDev->dc_rect.left + rc.right - ell_width,
967                       physDev->dc_rect.top + rc.top,
968                       ell_width - 1 , rc.bottom - rc.top - 1, 270 * 64 , 180 * 64 );
969         }else{
970             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
971                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top,
972                       ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
973             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
974                       physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.bottom - ell_height,
975                       ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
976             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
977                       physDev->dc_rect.left + rc.right - ell_width,
978                       physDev->dc_rect.top + rc.bottom - ell_height,
979                       ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
980             XDrawArc( gdi_display, physDev->drawable, physDev->gc,
981                       physDev->dc_rect.left + rc.right - ell_width, physDev->dc_rect.top + rc.top,
982                       ell_width - 1, ell_height - 1, 0, 90 * 64 );
983         }
984         if (ell_width < rc.right - rc.left)
985         {
986             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
987                        physDev->dc_rect.left + rc.left + ell_width / 2,
988                        physDev->dc_rect.top + rc.top,
989                        physDev->dc_rect.left + rc.right - (ell_width+1) / 2,
990                        physDev->dc_rect.top + rc.top);
991             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
992                        physDev->dc_rect.left + rc.left + ell_width / 2 ,
993                        physDev->dc_rect.top + rc.bottom - 1,
994                        physDev->dc_rect.left + rc.right - (ell_width+1)/ 2,
995                        physDev->dc_rect.top + rc.bottom - 1);
996         }
997         if (ell_height < rc.bottom - rc.top)
998         {
999             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1000                        physDev->dc_rect.left + rc.right - 1,
1001                        physDev->dc_rect.top + rc.top + ell_height / 2,
1002                        physDev->dc_rect.left + rc.right - 1,
1003                        physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
1004             XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1005                        physDev->dc_rect.left + rc.left,
1006                        physDev->dc_rect.top + rc.top + ell_height / 2,
1007                        physDev->dc_rect.left + rc.left,
1008                        physDev->dc_rect.top + rc.bottom - (ell_height+1) / 2);
1009         }
1010         wine_tsx11_unlock();
1011         update = TRUE;
1012     }
1013     /* Update the DIBSection from the pixmap */
1014     X11DRV_UnlockDIBSection(physDev, update);
1015
1016     physDev->pen.width = oldwidth;
1017     physDev->pen.endcap = oldendcap;
1018     return TRUE;
1019 }
1020
1021
1022 /***********************************************************************
1023  *           X11DRV_SetPixel
1024  */
1025 COLORREF CDECL
1026 X11DRV_SetPixel( X11DRV_PDEVICE *physDev, INT x, INT y, COLORREF color )
1027 {
1028     unsigned long pixel;
1029     POINT pt;
1030
1031     pt.x = x;
1032     pt.y = y;
1033     LPtoDP( physDev->hdc, &pt, 1 );
1034     pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1035
1036     /* Update the pixmap from the DIB section */
1037     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1038
1039     /* inefficient but simple... */
1040     wine_tsx11_lock();
1041     XSetForeground( gdi_display, physDev->gc, pixel );
1042     XSetFunction( gdi_display, physDev->gc, GXcopy );
1043     XDrawPoint( gdi_display, physDev->drawable, physDev->gc,
1044                 physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y );
1045     wine_tsx11_unlock();
1046
1047     /* Update the DIBSection from the pixmap */
1048     X11DRV_UnlockDIBSection(physDev, TRUE);
1049
1050     return X11DRV_PALETTE_ToLogical(physDev, pixel);
1051 }
1052
1053
1054 /***********************************************************************
1055  *           X11DRV_GetPixel
1056  */
1057 COLORREF CDECL
1058 X11DRV_GetPixel( X11DRV_PDEVICE *physDev, INT x, INT y )
1059 {
1060     static Pixmap pixmap = 0;
1061     XImage * image;
1062     int pixel;
1063     POINT pt;
1064     BOOL memdc = (GetObjectType(physDev->hdc) == OBJ_MEMDC);
1065
1066     pt.x = x;
1067     pt.y = y;
1068     LPtoDP( physDev->hdc, &pt, 1 );
1069
1070     /* Update the pixmap from the DIB section */
1071     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1072
1073     wine_tsx11_lock();
1074     if (memdc)
1075     {
1076         image = XGetImage( gdi_display, physDev->drawable,
1077                            physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y,
1078                            1, 1, AllPlanes, ZPixmap );
1079     }
1080     else
1081     {
1082         /* If we are reading from the screen, use a temporary copy */
1083         /* to avoid a BadMatch error */
1084         if (!pixmap) pixmap = XCreatePixmap( gdi_display, root_window,
1085                                              1, 1, physDev->depth );
1086         XCopyArea( gdi_display, physDev->drawable, pixmap, get_bitmap_gc(physDev->depth),
1087                    physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y, 1, 1, 0, 0 );
1088         image = XGetImage( gdi_display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
1089     }
1090     pixel = XGetPixel( image, 0, 0 );
1091     XDestroyImage( image );
1092     wine_tsx11_unlock();
1093
1094     /* Update the DIBSection from the pixmap */
1095     X11DRV_UnlockDIBSection(physDev, FALSE);
1096     if( physDev->depth > 1)
1097         pixel = X11DRV_PALETTE_ToLogical(physDev, pixel);
1098     else
1099         /* monochrome bitmaps return black or white */
1100         if( pixel) pixel = 0xffffff;
1101     return pixel;
1102
1103 }
1104
1105
1106 /***********************************************************************
1107  *           X11DRV_PaintRgn
1108  */
1109 BOOL CDECL
1110 X11DRV_PaintRgn( X11DRV_PDEVICE *physDev, HRGN hrgn )
1111 {
1112     if (X11DRV_SetupGCForBrush( physDev ))
1113     {
1114         unsigned int i;
1115         XRectangle *rect;
1116         RGNDATA *data = X11DRV_GetRegionData( hrgn, physDev->hdc );
1117
1118         if (!data) return FALSE;
1119         rect = (XRectangle *)data->Buffer;
1120         for (i = 0; i < data->rdh.nCount; i++)
1121         {
1122             rect[i].x += physDev->dc_rect.left;
1123             rect[i].y += physDev->dc_rect.top;
1124         }
1125
1126         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1127         wine_tsx11_lock();
1128         XFillRectangles( gdi_display, physDev->drawable, physDev->gc, rect, data->rdh.nCount );
1129         wine_tsx11_unlock();
1130         X11DRV_UnlockDIBSection(physDev, TRUE);
1131         HeapFree( GetProcessHeap(), 0, data );
1132     }
1133     return TRUE;
1134 }
1135
1136 /**********************************************************************
1137  *          X11DRV_Polyline
1138  */
1139 BOOL CDECL
1140 X11DRV_Polyline( X11DRV_PDEVICE *physDev, const POINT* pt, INT count )
1141 {
1142     int i;
1143     XPoint *points;
1144
1145     if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * count )))
1146     {
1147         WARN("No memory to convert POINTs to XPoints!\n");
1148         return FALSE;
1149     }
1150     for (i = 0; i < count; i++)
1151     {
1152         POINT tmp = pt[i];
1153         LPtoDP(physDev->hdc, &tmp, 1);
1154         points[i].x = physDev->dc_rect.left + tmp.x;
1155         points[i].y = physDev->dc_rect.top + tmp.y;
1156     }
1157
1158     if (X11DRV_SetupGCForPen ( physDev ))
1159     {
1160         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1161         wine_tsx11_lock();
1162         XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1163                     points, count, CoordModeOrigin );
1164         wine_tsx11_unlock();
1165         X11DRV_UnlockDIBSection(physDev, TRUE);
1166     }
1167
1168     HeapFree( GetProcessHeap(), 0, points );
1169     return TRUE;
1170 }
1171
1172
1173 /**********************************************************************
1174  *          X11DRV_Polygon
1175  */
1176 BOOL CDECL
1177 X11DRV_Polygon( X11DRV_PDEVICE *physDev, const POINT* pt, INT count )
1178 {
1179     register int i;
1180     XPoint *points;
1181     BOOL update = FALSE;
1182
1183     if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) )))
1184     {
1185         WARN("No memory to convert POINTs to XPoints!\n");
1186         return FALSE;
1187     }
1188     for (i = 0; i < count; i++)
1189     {
1190         POINT tmp = pt[i];
1191         LPtoDP(physDev->hdc, &tmp, 1);
1192         points[i].x = physDev->dc_rect.left + tmp.x;
1193         points[i].y = physDev->dc_rect.top + tmp.y;
1194     }
1195     points[count] = points[0];
1196
1197     /* Update the pixmap from the DIB section */
1198     X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1199
1200     if (X11DRV_SetupGCForBrush( physDev ))
1201     {
1202         wine_tsx11_lock();
1203         XFillPolygon( gdi_display, physDev->drawable, physDev->gc,
1204                       points, count+1, Complex, CoordModeOrigin);
1205         wine_tsx11_unlock();
1206         update = TRUE;
1207     }
1208     if (X11DRV_SetupGCForPen ( physDev ))
1209     {
1210         wine_tsx11_lock();
1211         XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1212                     points, count+1, CoordModeOrigin );
1213         wine_tsx11_unlock();
1214         update = TRUE;
1215     }
1216
1217     /* Update the DIBSection from the pixmap */
1218     X11DRV_UnlockDIBSection(physDev, update);
1219
1220     HeapFree( GetProcessHeap(), 0, points );
1221     return TRUE;
1222 }
1223
1224
1225 /**********************************************************************
1226  *          X11DRV_PolyPolygon
1227  */
1228 BOOL CDECL
1229 X11DRV_PolyPolygon( X11DRV_PDEVICE *physDev, const POINT* pt, const INT* counts, UINT polygons)
1230 {
1231     HRGN hrgn;
1232
1233     /* FIXME: The points should be converted to device coords before */
1234     /* creating the region. */
1235
1236     hrgn = CreatePolyPolygonRgn( pt, counts, polygons, GetPolyFillMode( physDev->hdc ) );
1237     X11DRV_PaintRgn( physDev, hrgn );
1238     DeleteObject( hrgn );
1239
1240       /* Draw the outline of the polygons */
1241
1242     if (X11DRV_SetupGCForPen ( physDev ))
1243     {
1244         unsigned int i;
1245         int j, max = 0;
1246         XPoint *points;
1247
1248         /* Update the pixmap from the DIB section */
1249         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1250
1251         for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
1252         if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (max+1) )))
1253         {
1254             WARN("No memory to convert POINTs to XPoints!\n");
1255             return FALSE;
1256         }
1257         for (i = 0; i < polygons; i++)
1258         {
1259             for (j = 0; j < counts[i]; j++)
1260             {
1261                 POINT tmp = *pt;
1262                 LPtoDP(physDev->hdc, &tmp, 1);
1263                 points[j].x = physDev->dc_rect.left + tmp.x;
1264                 points[j].y = physDev->dc_rect.top + tmp.y;
1265                 pt++;
1266             }
1267             points[j] = points[0];
1268             wine_tsx11_lock();
1269             XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1270                         points, j + 1, CoordModeOrigin );
1271             wine_tsx11_unlock();
1272         }
1273
1274         /* Update the DIBSection of the dc's bitmap */
1275         X11DRV_UnlockDIBSection(physDev, TRUE);
1276
1277         HeapFree( GetProcessHeap(), 0, points );
1278     }
1279     return TRUE;
1280 }
1281
1282
1283 /**********************************************************************
1284  *          X11DRV_PolyPolyline
1285  */
1286 BOOL CDECL
1287 X11DRV_PolyPolyline( X11DRV_PDEVICE *physDev, const POINT* pt, const DWORD* counts, DWORD polylines )
1288 {
1289     if (X11DRV_SetupGCForPen ( physDev ))
1290     {
1291         unsigned int i, j, max = 0;
1292         XPoint *points;
1293
1294         /* Update the pixmap from the DIB section */
1295         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1296
1297         for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1298         if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * max )))
1299         {
1300             WARN("No memory to convert POINTs to XPoints!\n");
1301             return FALSE;
1302         }
1303         for (i = 0; i < polylines; i++)
1304         {
1305             for (j = 0; j < counts[i]; j++)
1306             {
1307                 POINT tmp = *pt;
1308                 LPtoDP(physDev->hdc, &tmp, 1);
1309                 points[j].x = physDev->dc_rect.left + tmp.x;
1310                 points[j].y = physDev->dc_rect.top + tmp.y;
1311                 pt++;
1312             }
1313             wine_tsx11_lock();
1314             XDrawLines( gdi_display, physDev->drawable, physDev->gc,
1315                         points, j, CoordModeOrigin );
1316             wine_tsx11_unlock();
1317         }
1318
1319         /* Update the DIBSection of the dc's bitmap */
1320         X11DRV_UnlockDIBSection(physDev, TRUE);
1321
1322         HeapFree( GetProcessHeap(), 0, points );
1323     }
1324     return TRUE;
1325 }
1326
1327
1328 /**********************************************************************
1329  *          X11DRV_InternalFloodFill
1330  *
1331  * Internal helper function for flood fill.
1332  * (xorg,yorg) is the origin of the X image relative to the drawable.
1333  * (x,y) is relative to the origin of the X image.
1334  */
1335 static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev,
1336                                      int x, int y,
1337                                      int xOrg, int yOrg,
1338                                      unsigned long pixel, WORD fillType )
1339 {
1340     int left, right;
1341
1342 #define TO_FLOOD(x,y)  ((fillType == FLOODFILLBORDER) ? \
1343                         (XGetPixel(image,x,y) != pixel) : \
1344                         (XGetPixel(image,x,y) == pixel))
1345
1346     if (!TO_FLOOD(x,y)) return;
1347
1348       /* Find left and right boundaries */
1349
1350     left = right = x;
1351     while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1352     while ((right < image->width) && TO_FLOOD( right, y )) right++;
1353     XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1354                     xOrg + left, yOrg + y, right-left, 1 );
1355
1356       /* Set the pixels of this line so we don't fill it again */
1357
1358     for (x = left; x < right; x++)
1359     {
1360         if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1361         else XPutPixel( image, x, y, ~pixel );
1362     }
1363
1364       /* Fill the line above */
1365
1366     if (--y >= 0)
1367     {
1368         x = left;
1369         while (x < right)
1370         {
1371             while ((x < right) && !TO_FLOOD(x,y)) x++;
1372             if (x >= right) break;
1373             while ((x < right) && TO_FLOOD(x,y)) x++;
1374             X11DRV_InternalFloodFill(image, physDev, x-1, y,
1375                                      xOrg, yOrg, pixel, fillType );
1376         }
1377     }
1378
1379       /* Fill the line below */
1380
1381     if ((y += 2) < image->height)
1382     {
1383         x = left;
1384         while (x < right)
1385         {
1386             while ((x < right) && !TO_FLOOD(x,y)) x++;
1387             if (x >= right) break;
1388             while ((x < right) && TO_FLOOD(x,y)) x++;
1389             X11DRV_InternalFloodFill(image, physDev, x-1, y,
1390                                      xOrg, yOrg, pixel, fillType );
1391         }
1392     }
1393 #undef TO_FLOOD
1394 }
1395
1396
1397 static int ExtFloodFillXGetImageErrorHandler( Display *dpy, XErrorEvent *event, void *arg )
1398 {
1399     return (event->request_code == X_GetImage && event->error_code == BadMatch);
1400 }
1401
1402 /**********************************************************************
1403  *          X11DRV_ExtFloodFill
1404  */
1405 BOOL CDECL
1406 X11DRV_ExtFloodFill( X11DRV_PDEVICE *physDev, INT x, INT y, COLORREF color,
1407                      UINT fillType )
1408 {
1409     XImage *image;
1410     RECT rect;
1411     POINT pt;
1412
1413     TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x, y, color, fillType );
1414
1415     pt.x = x;
1416     pt.y = y;
1417     LPtoDP( physDev->hdc, &pt, 1 );
1418     if (!PtInRegion( physDev->region, pt.x, pt.y )) return FALSE;
1419     GetRgnBox( physDev->region, &rect );
1420
1421     X11DRV_expect_error( gdi_display, ExtFloodFillXGetImageErrorHandler, NULL );
1422     image = XGetImage( gdi_display, physDev->drawable,
1423                        physDev->dc_rect.left + rect.left, physDev->dc_rect.top + rect.top,
1424                        rect.right - rect.left, rect.bottom - rect.top,
1425                        AllPlanes, ZPixmap );
1426     if(X11DRV_check_error()) image = NULL;
1427     if (!image) return FALSE;
1428
1429     if (X11DRV_SetupGCForBrush( physDev ))
1430     {
1431         unsigned long pixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1432
1433         /* Update the pixmap from the DIB section */
1434         X11DRV_LockDIBSection(physDev, DIB_Status_GdiMod);
1435
1436           /* ROP mode is always GXcopy for flood-fill */
1437         wine_tsx11_lock();
1438         XSetFunction( gdi_display, physDev->gc, GXcopy );
1439         X11DRV_InternalFloodFill(image, physDev,
1440                                  pt.x - rect.left,
1441                                  pt.y - rect.top,
1442                                  physDev->dc_rect.left + rect.left,
1443                                  physDev->dc_rect.top + rect.top,
1444                                  pixel, fillType );
1445         wine_tsx11_unlock();
1446         /* Update the DIBSection of the dc's bitmap */
1447         X11DRV_UnlockDIBSection(physDev, TRUE);
1448     }
1449
1450     wine_tsx11_lock();
1451     XDestroyImage( image );
1452     wine_tsx11_unlock();
1453     return TRUE;
1454 }
1455
1456 /**********************************************************************
1457  *          X11DRV_SetBkColor
1458  */
1459 COLORREF CDECL
1460 X11DRV_SetBkColor( X11DRV_PDEVICE *physDev, COLORREF color )
1461 {
1462     physDev->backgroundPixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1463     return color;
1464 }
1465
1466 /**********************************************************************
1467  *          X11DRV_SetTextColor
1468  */
1469 COLORREF CDECL
1470 X11DRV_SetTextColor( X11DRV_PDEVICE *physDev, COLORREF color )
1471 {
1472     physDev->textPixel = X11DRV_PALETTE_ToPhysical( physDev, color );
1473     return color;
1474 }
1475
1476
1477 static unsigned char *get_icm_profile( unsigned long *size )
1478 {
1479     Atom type;
1480     int format;
1481     unsigned long count, remaining;
1482     unsigned char *profile, *ret = NULL;
1483
1484     wine_tsx11_lock();
1485     XGetWindowProperty( gdi_display, DefaultRootWindow(gdi_display),
1486                         x11drv_atom(_ICC_PROFILE), 0, ~0UL, False, AnyPropertyType,
1487                         &type, &format, &count, &remaining, &profile );
1488     *size = get_property_size( format, count );
1489     if (format && count)
1490     {
1491         if ((ret = HeapAlloc( GetProcessHeap(), 0, *size ))) memcpy( ret, profile, *size );
1492         XFree( profile );
1493     }
1494     wine_tsx11_unlock();
1495     return ret;
1496 }
1497
1498 typedef struct
1499 {
1500     unsigned int unknown[6];
1501     unsigned int state[5];
1502     unsigned int count[2];
1503     unsigned char buffer[64];
1504 } sha_ctx;
1505
1506 extern void WINAPI A_SHAInit( sha_ctx * );
1507 extern void WINAPI A_SHAUpdate( sha_ctx *, const unsigned char *, unsigned int );
1508 extern void WINAPI A_SHAFinal( sha_ctx *, unsigned char * );
1509
1510 /***********************************************************************
1511  *              GetICMProfile (X11DRV.@)
1512  */
1513 BOOL CDECL X11DRV_GetICMProfile( X11DRV_PDEVICE *physDev, LPDWORD size, LPWSTR filename )
1514 {
1515     static const WCHAR path[] =
1516         {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s',
1517          '\\','c','o','l','o','r','\\',0};
1518     static const WCHAR srgb[] =
1519         {'s','R','G','B',' ','C','o','l','o','r',' ','S','p','a','c','e',' ',
1520          'P','r','o','f','i','l','e','.','i','c','m',0};
1521     static const WCHAR mntr[] =
1522         {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1523          'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t',
1524          'V','e','r','s','i','o','n','\\','I','C','M','\\','m','n','t','r',0};
1525
1526     HKEY hkey;
1527     DWORD required, len;
1528     WCHAR profile[MAX_PATH], fullname[2*MAX_PATH + sizeof(path)/sizeof(WCHAR)];
1529     unsigned char *buffer;
1530     unsigned long buflen;
1531
1532     if (!size) return FALSE;
1533
1534     GetSystemDirectoryW( fullname, MAX_PATH );
1535     strcatW( fullname, path );
1536
1537     len = sizeof(profile)/sizeof(WCHAR);
1538     if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, mntr, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL ) &&
1539         !RegEnumValueW( hkey, 0, profile, &len, NULL, NULL, NULL, NULL )) /* FIXME handle multiple values */
1540     {
1541         strcatW( fullname, profile );
1542         RegCloseKey( hkey );
1543     }
1544     else if ((buffer = get_icm_profile( &buflen )))
1545     {
1546         static const WCHAR fmt[] = {'%','0','2','x',0};
1547         static const WCHAR icm[] = {'.','i','c','m',0};
1548
1549         unsigned char sha1sum[20];
1550         unsigned int i;
1551         sha_ctx ctx;
1552         HANDLE file;
1553
1554         A_SHAInit( &ctx );
1555         A_SHAUpdate( &ctx, buffer, buflen );
1556         A_SHAFinal( &ctx, sha1sum );
1557
1558         for (i = 0; i < sizeof(sha1sum); i++) sprintfW( &profile[i * 2], fmt, sha1sum[i] );
1559         memcpy( &profile[i * 2], icm, sizeof(icm) );
1560
1561         strcatW( fullname, profile );
1562         file = CreateFileW( fullname, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0 );
1563         if (file != INVALID_HANDLE_VALUE)
1564         {
1565             DWORD written;
1566
1567             if (!WriteFile( file, buffer, buflen, &written, NULL ) || written != buflen)
1568                 ERR( "Unable to write color profile\n" );
1569             CloseHandle( file );
1570         }
1571         HeapFree( GetProcessHeap(), 0, buffer );
1572     }
1573     else strcatW( fullname, srgb );
1574
1575     required = strlenW( fullname ) + 1;
1576     if (*size < required)
1577     {
1578         *size = required;
1579         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1580         return FALSE;
1581     }
1582     if (filename)
1583     {
1584         strcpyW( filename, fullname );
1585         if (GetFileAttributesW( filename ) == INVALID_FILE_ATTRIBUTES)
1586             WARN( "color profile not found\n" );
1587     }
1588     *size = required;
1589     return TRUE;
1590 }