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