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