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