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