2 * X11 graphics driver graphics functions
4 * Copyright 1993,1994 Alexandre Julliard
8 * FIXME: none of these functions obey the GM_ADVANCED
14 #ifndef X_DISPLAY_MISSING
16 #include <X11/Intrinsic.h>
42 #include "debugtools.h"
45 DEFAULT_DEBUG_CHANNEL(graphics)
47 #define ABS(x) ((x)<0?(-(x)):(x))
49 /* ROP code to GC function conversion */
50 const int X11DRV_XROPfunction[16] =
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 */
63 GXorInverted, /* R2_MERGENOTPEN */
64 GXcopy, /* R2_COPYPEN */
65 GXorReverse, /* R2_MERGEPENNOT */
66 GXor, /* R2_MERGEPEN */
71 /***********************************************************************
72 * X11DRV_SetupGCForPatBlt
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.
78 BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors )
83 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
85 if (physDev->brush.style == BS_NULL) return FALSE;
86 if (physDev->brush.pixel == -1)
88 /* Special case used for monochrome pattern brushes.
89 * We need to swap foreground and background because
90 * Windows does it the wrong way...
92 val.foreground = physDev->backgroundPixel;
93 val.background = physDev->textPixel;
97 val.foreground = physDev->brush.pixel;
98 val.background = physDev->backgroundPixel;
100 if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
102 val.foreground = X11DRV_PALETTE_XPixelToPalette[val.foreground];
103 val.background = X11DRV_PALETTE_XPixelToPalette[val.background];
106 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
108 val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
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
114 if (val.function == GXinvert)
116 val.foreground = BlackPixelOfScreen(X11DRV_GetXScreen()) ^ WhitePixelOfScreen(X11DRV_GetXScreen());
117 val.function = GXxor;
119 val.fill_style = physDev->brush.fillStyle;
120 switch(val.fill_style)
123 case FillOpaqueStippled:
124 if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
125 val.stipple = physDev->brush.pixmap;
130 if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
134 EnterCriticalSection( &X11DRV_CritSection );
135 pixmap = XCreatePixmap( display,
136 X11DRV_GetXRootWindow(),
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 );
150 else val.tile = physDev->brush.pixmap;
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,
165 if (pixmap) TSXFreePixmap( display, pixmap );
170 /***********************************************************************
171 * X11DRV_SetupGCForBrush
173 * Setup physDev->gc for drawing operations using current brush.
174 * Return FALSE if brush is BS_NULL, TRUE otherwise.
176 BOOL X11DRV_SetupGCForBrush( DC * dc )
178 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
179 return X11DRV_SetupGCForPatBlt( dc, physDev->gc, FALSE );
183 /***********************************************************************
184 * X11DRV_SetupGCForPen
186 * Setup physDev->gc for drawing operations using current pen.
187 * Return FALSE if pen is PS_NULL, TRUE otherwise.
189 BOOL X11DRV_SetupGCForPen( DC * dc )
192 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
194 if (physDev->pen.style == PS_NULL) return FALSE;
196 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
198 switch (dc->w.ROPmode)
201 val.foreground = BlackPixelOfScreen( X11DRV_GetXScreen() );
202 val.function = GXcopy;
205 val.foreground = WhitePixelOfScreen( X11DRV_GetXScreen() );
206 val.function = GXcopy;
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;
218 val.foreground = physDev->pen.pixel;
219 val.function = X11DRV_XROPfunction[dc->w.ROPmode-1];
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))
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;
232 else val.line_style = LineSolid;
233 val.line_width = physDev->pen.width;
234 if (val.line_width <= 1) {
235 val.cap_style = CapNotLast;
237 switch (physDev->pen.endcap)
239 case PS_ENDCAP_SQUARE:
240 val.cap_style = CapProjecting;
243 val.cap_style = CapButt;
245 case PS_ENDCAP_ROUND:
247 val.cap_style = CapRound;
250 switch (physDev->pen.linejoin)
253 val.join_style = JoinBevel;
256 val.join_style = JoinMiter;
260 val.join_style = JoinRound;
262 TSXChangeGC( display, physDev->gc,
263 GCFunction | GCForeground | GCBackground | GCLineWidth |
264 GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
269 /***********************************************************************
270 * X11DRV_SetupGCForText
272 * Setup physDev->gc for text drawing operations.
273 * Return FALSE if the font is null, TRUE otherwise.
275 BOOL X11DRV_SetupGCForText( DC * dc )
277 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
278 XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
284 if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
286 val.function = GXcopy; /* Text is always GXcopy */
287 val.foreground = physDev->textPixel;
288 val.background = physDev->backgroundPixel;
289 val.fill_style = FillSolid;
292 TSXChangeGC( display, physDev->gc,
293 GCFunction | GCForeground | GCBackground | GCFillStyle |
297 WARN("Physical font failure\n" );
301 /***********************************************************************
305 X11DRV_LineTo( DC *dc, INT x, INT y )
307 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
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 ) );
320 /***********************************************************************
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.
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 )
332 INT xcenter, ycenter, istart_angle, idiff_angle;
333 INT width, oldwidth, oldendcap;
334 double start_angle, end_angle;
336 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
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 );
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;
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;
357 if ((physDev->pen.style == PS_INSIDEFRAME))
359 if (2*width > (right-left)) width=(right-left + 1)/2;
360 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
362 right -= (width - 1) / 2;
364 bottom -= (width - 1) / 2;
366 if(width == 0) width = 1; /* more accurate */
367 physDev->pen.width = width;
368 physDev->pen.endcap = PS_ENDCAP_SQUARE;
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) */
381 else /* notorious cases */
382 if ((start_angle == PI)&&( end_angle <0))
385 if ((end_angle == PI)&&( start_angle <0))
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;
391 /* Fill arc with brush if Chord() or Pie() */
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 );
401 /* Draw arc and lines */
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 );
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);
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)
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--;
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--;
444 if(dy1 < 0) points[0].y--;
445 if(((right-left) | -2) == -2) points[1].x--;
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--;
452 if( dy1>0) points[3].y--;
453 if(((right-left) | -2) == -2 ) points[2].x--;
456 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
460 TSXDrawLines( display, physDev->drawable, physDev->gc,
461 points, lines+1, CoordModeOrigin );
464 physDev->pen.width = oldwidth;
465 physDev->pen.endcap = oldendcap;
470 /***********************************************************************
474 X11DRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
475 INT xstart, INT ystart, INT xend, INT yend )
477 return X11DRV_DrawArc( dc, left, top, right, bottom,
478 xstart, ystart, xend, yend, 0 );
482 /***********************************************************************
486 X11DRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
487 INT xstart, INT ystart, INT xend, INT yend )
489 return X11DRV_DrawArc( dc, left, top, right, bottom,
490 xstart, ystart, xend, yend, 2 );
493 /***********************************************************************
497 X11DRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
498 INT xstart, INT ystart, INT xend, INT yend )
500 return X11DRV_DrawArc( dc, left, top, right, bottom,
501 xstart, ystart, xend, yend, 1 );
505 /***********************************************************************
509 X11DRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
512 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
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;
520 if (right < left) { INT tmp = right; right = left; left = tmp; }
521 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
523 oldwidth = width = physDev->pen.width;
524 if (!width) width = 1;
525 if(physDev->pen.style == PS_NULL) width = 0;
527 if ((physDev->pen.style == PS_INSIDEFRAME))
529 if (2*width > (right-left)) width=(right-left + 1)/2;
530 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
532 right -= (width - 1) / 2;
534 bottom -= (width - 1) / 2;
536 if(width == 0) width = 1; /* more accurate */
537 physDev->pen.width = width;
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;
552 /***********************************************************************
556 X11DRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
558 INT width, oldwidth, oldjoinstyle;
559 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
561 TRACE("(%d %d %d %d)\n",
562 left, top, right, bottom);
564 left = XLPTODP( dc, left );
565 top = YLPTODP( dc, top );
566 right = XLPTODP( dc, right );
567 bottom = YLPTODP( dc, bottom );
569 if ((left == right) || (top == bottom)) return TRUE;
571 if (right < left) { INT tmp = right; right = left; left = tmp; }
572 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
574 oldwidth = width = physDev->pen.width;
575 if (!width) width = 1;
576 if(physDev->pen.style == PS_NULL) width = 0;
578 if ((physDev->pen.style == PS_INSIDEFRAME))
580 if (2*width > (right-left)) width=(right-left + 1)/2;
581 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
583 right -= (width - 1) / 2;
585 bottom -= (width - 1) / 2;
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;
593 if ((right > left + width) && (bottom > top + width))
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);
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 );
606 physDev->pen.width = oldwidth;
607 physDev->pen.linejoin = oldjoinstyle;
611 /***********************************************************************
615 X11DRV_RoundRect( DC *dc, INT left, INT top, INT right,
616 INT bottom, INT ell_width, INT ell_height )
618 INT width, oldwidth, oldendcap;
619 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
621 TRACE("(%d %d %d %d %d %d\n",
622 left, top, right, bottom, ell_width, ell_height);
624 left = XLPTODP( dc, left );
625 top = YLPTODP( dc, top );
626 right = XLPTODP( dc, right );
627 bottom = YLPTODP( dc, bottom );
629 if ((left == right) || (top == bottom))
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);
637 /* Fix the coordinates */
639 if (right < left) { INT tmp = right; right = left; left = tmp; }
640 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
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;
647 if ((physDev->pen.style == PS_INSIDEFRAME))
649 if (2*width > (right-left)) width=(right-left + 1)/2;
650 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
652 right -= (width - 1) / 2;
654 bottom -= (width - 1) / 2;
656 if(width == 0) width = 1;
657 physDev->pen.width = width;
658 physDev->pen.endcap = PS_ENDCAP_SQUARE;
660 if (X11DRV_SetupGCForBrush( dc ))
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,
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,
674 dc->w.DCOrgY + bottom - ell_height - 1,
675 right - left - 1, ell_height, 180 * 64,
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 );
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,
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,
700 ell_width, ell_height, 0, 90 * 64 );
702 if (ell_width < right - left)
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,
715 if (ell_height < bottom - top)
717 TSXFillRectangle( display, physDev->drawable, physDev->gc,
718 dc->w.DCOrgX + left + 1,
719 dc->w.DCOrgY + top + (ell_height + 1) / 2,
721 bottom - top - ell_height - 1);
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.
730 * BTW this stuff is optimized for an Xfree86 server
731 * read the comments inside the X11DRV_DrawArc function
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 );
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,
745 dc->w.DCOrgY + bottom - ell_height,
746 right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
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,
755 ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
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 );
771 if (ell_width < right - left)
773 TSXDrawLine( display, physDev->drawable, physDev->gc,
774 dc->w.DCOrgX + left + ell_width / 2,
776 dc->w.DCOrgX + right - (ell_width+1) / 2,
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);
784 if (ell_height < bottom - top)
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,
793 dc->w.DCOrgY + top + ell_height / 2,
795 dc->w.DCOrgY + bottom - (ell_height+1) / 2);
798 physDev->pen.width = oldwidth;
799 physDev->pen.endcap = oldendcap;
804 /***********************************************************************
808 X11DRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
811 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
813 x = dc->w.DCOrgX + XLPTODP( dc, x );
814 y = dc->w.DCOrgY + YLPTODP( dc, y );
815 pixel = X11DRV_PALETTE_ToPhysical( dc, color );
817 TSXSetForeground( display, physDev->gc, pixel );
818 TSXSetFunction( display, physDev->gc, GXcopy );
819 TSXDrawPoint( display, physDev->drawable, physDev->gc, x, y );
821 /* inefficient but simple... */
823 return X11DRV_PALETTE_ToLogical(pixel);
827 /***********************************************************************
831 X11DRV_GetPixel( DC *dc, INT x, INT y )
833 static Pixmap pixmap = 0;
836 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
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)
843 image = XGetImage( display, physDev->drawable, x, y, 1, 1,
844 AllPlanes, ZPixmap );
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,
854 image = XGetImage( display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
856 pixel = XGetPixel( image, 0, 0 );
857 XDestroyImage( image );
858 LeaveCriticalSection( &X11DRV_CritSection );
860 return X11DRV_PALETTE_ToLogical(pixel);
864 /***********************************************************************
868 X11DRV_PaintRgn( DC *dc, HRGN hrgn )
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;
875 if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
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 );
884 /* Modify visible region */
885 if (!(prevVisRgn = SaveVisRgn16( hdc ))) {
886 DeleteObject( tmpVisRgn );
889 CombineRgn( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
890 SelectVisRgn16( hdc, tmpVisRgn );
891 DeleteObject( tmpVisRgn );
893 /* Fill the region */
895 GetRgnBox( dc->w.hGCClipRgn, &box );
896 if (X11DRV_SetupGCForBrush( dc ))
897 TSXFillRectangle( display, physDev->drawable, physDev->gc,
899 box.right-box.left, box.bottom-box.top );
901 /* Restore the visible region */
903 RestoreVisRgn16( hdc );
907 /**********************************************************************
911 X11DRV_Polyline( DC *dc, const POINT* pt, INT count )
916 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
918 if((oldwidth = physDev->pen.width) == 0) physDev->pen.width = 1;
920 points = (XPoint *) xmalloc (sizeof (XPoint) * (count));
921 for (i = 0; i < count; i++)
923 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
924 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
927 if (X11DRV_SetupGCForPen ( dc ))
928 TSXDrawLines( display, physDev->drawable, physDev->gc,
929 points, count, CoordModeOrigin );
932 physDev->pen.width = oldwidth;
937 /**********************************************************************
941 X11DRV_Polygon( DC *dc, const POINT* pt, INT count )
945 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
947 points = (XPoint *) xmalloc (sizeof (XPoint) * (count+1));
948 for (i = 0; i < count; i++)
950 points[i].x = dc->w.DCOrgX + XLPTODP( dc, pt[i].x );
951 points[i].y = dc->w.DCOrgY + YLPTODP( dc, pt[i].y );
953 points[count] = points[0];
955 if (X11DRV_SetupGCForBrush( dc ))
956 TSXFillPolygon( display, physDev->drawable, physDev->gc,
957 points, count+1, Complex, CoordModeOrigin);
959 if (X11DRV_SetupGCForPen ( dc ))
960 TSXDrawLines( display, physDev->drawable, physDev->gc,
961 points, count+1, CoordModeOrigin );
968 /**********************************************************************
972 X11DRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polygons)
975 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
977 /* FIXME: The points should be converted to device coords before */
978 /* creating the region. */
980 hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->w.polyFillMode );
981 X11DRV_PaintRgn( dc, hrgn );
982 DeleteObject( hrgn );
984 /* Draw the outline of the polygons */
986 if (X11DRV_SetupGCForPen ( dc ))
991 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
992 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
994 for (i = 0; i < polygons; i++)
996 for (j = 0; j < counts[i]; j++)
998 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
999 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1002 points[j] = points[0];
1003 TSXDrawLines( display, physDev->drawable, physDev->gc,
1004 points, j + 1, CoordModeOrigin );
1012 /**********************************************************************
1013 * X11DRV_PolyPolyline
1016 X11DRV_PolyPolyline( DC *dc, const POINT* pt, const DWORD* counts, DWORD polylines )
1018 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1019 if (X11DRV_SetupGCForPen ( dc ))
1024 for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1025 points = (XPoint *) xmalloc( sizeof(XPoint) * (max+1) );
1027 for (i = 0; i < polylines; i++)
1029 for (j = 0; j < counts[i]; j++)
1031 points[j].x = dc->w.DCOrgX + XLPTODP( dc, pt->x );
1032 points[j].y = dc->w.DCOrgY + YLPTODP( dc, pt->y );
1035 points[j] = points[0];
1036 TSXDrawLines( display, physDev->drawable, physDev->gc,
1037 points, j + 1, CoordModeOrigin );
1045 /**********************************************************************
1046 * X11DRV_InternalFloodFill
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.
1052 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
1055 Pixel pixel, WORD fillType )
1057 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1060 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1061 (XGetPixel(image,x,y) != pixel) : \
1062 (XGetPixel(image,x,y) == pixel))
1064 if (!TO_FLOOD(x,y)) return;
1066 /* Find left and right boundaries */
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 );
1074 /* Set the pixels of this line so we don't fill it again */
1076 for (x = left; x < right; x++)
1078 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1079 else XPutPixel( image, x, y, ~pixel );
1082 /* Fill the line above */
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 );
1097 /* Fill the line below */
1099 if ((y += 2) < image->height)
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 );
1115 /**********************************************************************
1116 * X11DRV_DoFloodFill
1118 * Main flood-fill routine.
1120 * The Xlib critical section must be entered before calling this function.
1123 struct FloodFill_params
1132 static BOOL X11DRV_DoFloodFill( const struct FloodFill_params *params )
1136 DC *dc = params->dc;
1137 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1139 if (GetRgnBox( dc->w.hGCClipRgn, &rect ) == ERROR) return FALSE;
1141 if (!(image = XGetImage( display, physDev->drawable,
1144 rect.right - rect.left,
1145 rect.bottom - rect.top,
1146 AllPlanes, ZPixmap ))) return FALSE;
1148 if (X11DRV_SetupGCForBrush( dc ))
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,
1157 X11DRV_PALETTE_ToPhysical( dc, params->color ),
1161 XDestroyImage( image );
1166 /**********************************************************************
1167 * X11DRV_ExtFloodFill
1170 X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color,
1174 struct FloodFill_params params;
1176 TRACE("X11DRV_ExtFloodFill %d,%d %06lx %d\n",
1177 x, y, color, fillType );
1182 params.color = color;
1183 params.fillType = fillType;
1185 if (!PtVisible( dc->hSelf, x, y )) return FALSE;
1186 EnterCriticalSection( &X11DRV_CritSection );
1187 result = CALL_LARGE_STACK( X11DRV_DoFloodFill, ¶ms );
1188 LeaveCriticalSection( &X11DRV_CritSection );
1192 /**********************************************************************
1196 X11DRV_SetBkColor( DC *dc, COLORREF color )
1198 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1201 oldColor = dc->w.backgroundColor;
1202 dc->w.backgroundColor = color;
1204 physDev->backgroundPixel = X11DRV_PALETTE_ToPhysical( dc, color );
1209 /**********************************************************************
1210 * X11DRV_SetTextColor
1213 X11DRV_SetTextColor( DC *dc, COLORREF color )
1215 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1218 oldColor = dc->w.textColor;
1219 dc->w.textColor = color;
1221 physDev->textPixel = X11DRV_PALETTE_ToPhysical( dc, color );
1226 #endif /* !defined(X_DISPLAY_MISSING) */