2 * X11 graphics driver graphics functions
4 * Copyright 1993,1994 Alexandre Julliard
8 * FIXME: only some of these functions obey the GM_ADVANCED
14 #include <X11/Intrinsic.h>
37 #include "debugtools.h"
39 DEFAULT_DEBUG_CHANNEL(graphics);
41 #define ABS(x) ((x)<0?(-(x)):(x))
43 /* ROP code to GC function conversion */
44 const int X11DRV_XROPfunction[16] =
46 GXclear, /* R2_BLACK */
47 GXnor, /* R2_NOTMERGEPEN */
48 GXandInverted, /* R2_MASKNOTPEN */
49 GXcopyInverted, /* R2_NOTCOPYPEN */
50 GXandReverse, /* R2_MASKPENNOT */
51 GXinvert, /* R2_NOT */
52 GXxor, /* R2_XORPEN */
53 GXnand, /* R2_NOTMASKPEN */
54 GXand, /* R2_MASKPEN */
55 GXequiv, /* R2_NOTXORPEN */
57 GXorInverted, /* R2_MERGENOTPEN */
58 GXcopy, /* R2_COPYPEN */
59 GXorReverse, /* R2_MERGEPENNOT */
60 GXor, /* R2_MERGEPEN */
65 /***********************************************************************
66 * X11DRV_SetupGCForPatBlt
68 * Setup the GC for a PatBlt operation using current brush.
69 * If fMapColors is TRUE, X pixels are mapped to Windows colors.
70 * Return FALSE if brush is BS_NULL, TRUE otherwise.
72 BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors )
77 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
79 if (physDev->brush.style == BS_NULL) return FALSE;
80 if (physDev->brush.pixel == -1)
82 /* Special case used for monochrome pattern brushes.
83 * We need to swap foreground and background because
84 * Windows does it the wrong way...
86 val.foreground = physDev->backgroundPixel;
87 val.background = physDev->textPixel;
91 val.foreground = physDev->brush.pixel;
92 val.background = physDev->backgroundPixel;
94 if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
96 val.foreground = X11DRV_PALETTE_XPixelToPalette[val.foreground];
97 val.background = X11DRV_PALETTE_XPixelToPalette[val.background];
100 val.function = X11DRV_XROPfunction[dc->ROPmode-1];
102 ** Let's replace GXinvert by GXxor with (black xor white)
103 ** This solves the selection color and leak problems in excel
104 ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
106 if (val.function == GXinvert)
108 val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
109 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
110 val.function = GXxor;
112 val.fill_style = physDev->brush.fillStyle;
113 switch(val.fill_style)
116 case FillOpaqueStippled:
117 if (dc->backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
118 val.stipple = physDev->brush.pixmap;
123 if (fMapColors && X11DRV_PALETTE_XPixelToPalette)
128 pixmap = XCreatePixmap( gdi_display, root_window, 8, 8, screen_depth );
129 image = XGetImage( gdi_display, physDev->brush.pixmap, 0, 0, 8, 8,
130 AllPlanes, ZPixmap );
131 for (y = 0; y < 8; y++)
132 for (x = 0; x < 8; x++)
133 XPutPixel( image, x, y,
134 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] );
135 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
136 XDestroyImage( image );
140 else val.tile = physDev->brush.pixmap;
148 val.ts_x_origin = dc->DCOrgX + dc->brushOrgX;
149 val.ts_y_origin = dc->DCOrgY + dc->brushOrgY;
150 val.fill_rule = (dc->polyFillMode==WINDING) ? WindingRule : EvenOddRule;
151 TSXChangeGC( gdi_display, gc,
152 GCFunction | GCForeground | GCBackground | GCFillStyle |
153 GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
155 if (pixmap) TSXFreePixmap( gdi_display, pixmap );
160 /***********************************************************************
161 * X11DRV_SetupGCForBrush
163 * Setup physDev->gc for drawing operations using current brush.
164 * Return FALSE if brush is BS_NULL, TRUE otherwise.
166 BOOL X11DRV_SetupGCForBrush( DC * dc )
168 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
169 return X11DRV_SetupGCForPatBlt( dc, physDev->gc, FALSE );
173 /***********************************************************************
174 * X11DRV_SetupGCForPen
176 * Setup physDev->gc for drawing operations using current pen.
177 * Return FALSE if pen is PS_NULL, TRUE otherwise.
179 BOOL X11DRV_SetupGCForPen( DC * dc )
182 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
184 if (physDev->pen.style == PS_NULL) return FALSE;
189 val.foreground = BlackPixel( gdi_display, DefaultScreen(gdi_display) );
190 val.function = GXcopy;
193 val.foreground = WhitePixel( gdi_display, DefaultScreen(gdi_display) );
194 val.function = GXcopy;
197 val.foreground = physDev->pen.pixel;
198 /* It is very unlikely someone wants to XOR with 0 */
199 /* This fixes the rubber-drawings in paintbrush */
200 if (val.foreground == 0)
201 val.foreground = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
202 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
203 val.function = GXxor;
206 val.foreground = physDev->pen.pixel;
207 val.function = X11DRV_XROPfunction[dc->ROPmode-1];
209 val.background = physDev->backgroundPixel;
210 val.fill_style = FillSolid;
211 if ((physDev->pen.width <= 1) &&
212 (physDev->pen.style != PS_SOLID) &&
213 (physDev->pen.style != PS_INSIDEFRAME))
215 TSXSetDashes( gdi_display, physDev->gc, 0, physDev->pen.dashes, physDev->pen.dash_len );
216 val.line_style = (dc->backgroundMode == OPAQUE) ?
217 LineDoubleDash : LineOnOffDash;
219 else val.line_style = LineSolid;
220 val.line_width = physDev->pen.width;
221 if (val.line_width <= 1) {
222 val.cap_style = CapNotLast;
224 switch (physDev->pen.endcap)
226 case PS_ENDCAP_SQUARE:
227 val.cap_style = CapProjecting;
230 val.cap_style = CapButt;
232 case PS_ENDCAP_ROUND:
234 val.cap_style = CapRound;
237 switch (physDev->pen.linejoin)
240 val.join_style = JoinBevel;
243 val.join_style = JoinMiter;
247 val.join_style = JoinRound;
249 TSXChangeGC( gdi_display, physDev->gc,
250 GCFunction | GCForeground | GCBackground | GCLineWidth |
251 GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
256 /***********************************************************************
257 * X11DRV_SetupGCForText
259 * Setup physDev->gc for text drawing operations.
260 * Return FALSE if the font is null, TRUE otherwise.
262 BOOL X11DRV_SetupGCForText( DC * dc )
264 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
265 XFontStruct* xfs = XFONT_GetFontStruct( physDev->font );
271 val.function = GXcopy; /* Text is always GXcopy */
272 val.foreground = physDev->textPixel;
273 val.background = physDev->backgroundPixel;
274 val.fill_style = FillSolid;
277 TSXChangeGC( gdi_display, physDev->gc,
278 GCFunction | GCForeground | GCBackground | GCFillStyle |
282 WARN("Physical font failure\n" );
286 /***********************************************************************
290 X11DRV_LineTo( DC *dc, INT x, INT y )
292 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
296 if (X11DRV_SetupGCForPen( dc )) {
297 /* Update the pixmap from the DIB section */
298 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
300 start.x = dc->CursPosX;
301 start.y = dc->CursPosY;
304 INTERNAL_LPTODP(dc,&start);
305 INTERNAL_LPTODP(dc,&end);
307 TSXDrawLine(gdi_display, physDev->drawable, physDev->gc,
308 dc->DCOrgX + start.x,
309 dc->DCOrgY + start.y,
313 /* Update the DIBSection from the pixmap */
314 X11DRV_UnlockDIBSection(dc, TRUE);
321 /***********************************************************************
324 * Helper functions for Arc(), Chord() and Pie().
325 * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie.
329 X11DRV_DrawArc( DC *dc, INT left, INT top, INT right,
330 INT bottom, INT xstart, INT ystart,
331 INT xend, INT yend, INT lines )
333 INT xcenter, ycenter, istart_angle, idiff_angle;
334 INT width, oldwidth, oldendcap;
335 double start_angle, end_angle;
337 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
340 left = XLPTODP( dc, left );
341 top = YLPTODP( dc, top );
342 right = XLPTODP( dc, right );
343 bottom = YLPTODP( dc, bottom );
344 xstart = XLPTODP( dc, xstart );
345 ystart = YLPTODP( dc, ystart );
346 xend = XLPTODP( dc, xend );
347 yend = YLPTODP( dc, yend );
349 if (right < left) { INT tmp = right; right = left; left = tmp; }
350 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
351 if ((left == right) || (top == bottom)
352 ||(lines && ((right-left==1)||(bottom-top==1)))) return TRUE;
354 if( dc->ArcDirection == AD_CLOCKWISE )
355 { INT tmp = xstart; xstart = xend; xend = tmp;
356 tmp = ystart; ystart = yend; yend = tmp; }
358 oldwidth = width = physDev->pen.width;
359 oldendcap = physDev->pen.endcap;
360 if (!width) width = 1;
361 if(physDev->pen.style == PS_NULL) width = 0;
363 if ((physDev->pen.style == PS_INSIDEFRAME))
365 if (2*width > (right-left)) width=(right-left + 1)/2;
366 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
368 right -= (width - 1) / 2;
370 bottom -= (width - 1) / 2;
372 if(width == 0) width = 1; /* more accurate */
373 physDev->pen.width = width;
374 physDev->pen.endcap = PS_ENDCAP_SQUARE;
376 xcenter = (right + left) / 2;
377 ycenter = (bottom + top) / 2;
378 start_angle = atan2( (double)(ycenter-ystart)*(right-left),
379 (double)(xstart-xcenter)*(bottom-top) );
380 end_angle = atan2( (double)(ycenter-yend)*(right-left),
381 (double)(xend-xcenter)*(bottom-top) );
382 if ((xstart==xend)&&(ystart==yend))
383 { /* A lazy program delivers xstart=xend=ystart=yend=0) */
387 else /* notorious cases */
388 if ((start_angle == PI)&&( end_angle <0))
391 if ((end_angle == PI)&&( start_angle <0))
393 istart_angle = (INT)(start_angle * 180 * 64 / PI + 0.5);
394 idiff_angle = (INT)((end_angle - start_angle) * 180 * 64 / PI + 0.5);
395 if (idiff_angle <= 0) idiff_angle += 360 * 64;
397 /* Update the pixmap from the DIB section */
398 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
400 /* Fill arc with brush if Chord() or Pie() */
402 if ((lines > 0) && X11DRV_SetupGCForBrush( dc )) {
403 TSXSetArcMode( gdi_display, physDev->gc, (lines==1) ? ArcChord : ArcPieSlice);
404 TSXFillArc( gdi_display, physDev->drawable, physDev->gc,
405 dc->DCOrgX + left, dc->DCOrgY + top,
406 right-left-1, bottom-top-1, istart_angle, idiff_angle );
410 /* Draw arc and lines */
412 if (X11DRV_SetupGCForPen( dc )){
413 TSXDrawArc( gdi_display, physDev->drawable, physDev->gc,
414 dc->DCOrgX + left, dc->DCOrgY + top,
415 right-left-1, bottom-top-1, istart_angle, idiff_angle );
417 /* use the truncated values */
418 start_angle=(double)istart_angle*PI/64./180.;
419 end_angle=(double)(istart_angle+idiff_angle)*PI/64./180.;
420 /* calculate the endpoints and round correctly */
421 points[0].x = (int) floor(dc->DCOrgX + (right+left)/2.0 +
422 cos(start_angle) * (right-left-width*2+2) / 2. + 0.5);
423 points[0].y = (int) floor(dc->DCOrgY + (top+bottom)/2.0 -
424 sin(start_angle) * (bottom-top-width*2+2) / 2. + 0.5);
425 points[1].x = (int) floor(dc->DCOrgX + (right+left)/2.0 +
426 cos(end_angle) * (right-left-width*2+2) / 2. + 0.5);
427 points[1].y = (int) floor(dc->DCOrgY + (top+bottom)/2.0 -
428 sin(end_angle) * (bottom-top-width*2+2) / 2. + 0.5);
430 /* OK, this stuff is optimized for Xfree86
431 * which is probably the server most used by
432 * wine users. Other X servers will not
433 * display correctly. (eXceed for instance)
434 * so if you feel you must make changes, make sure that
435 * you either use Xfree86 or separate your changes
436 * from these (compile switch or whatever)
440 points[3] = points[1];
441 points[1].x = dc->DCOrgX + xcenter;
442 points[1].y = dc->DCOrgY + ycenter;
443 points[2] = points[1];
444 dx1=points[1].x-points[0].x;
445 dy1=points[1].y-points[0].y;
446 if(((top-bottom) | -2) == -2)
447 if(dy1>0) points[1].y--;
449 if (((-dx1)*64)<=ABS(dy1)*37) points[0].x--;
450 if(((-dx1*9))<(dy1*16)) points[0].y--;
451 if( dy1<0 && ((dx1*9)) < (dy1*16)) points[0].y--;
453 if(dy1 < 0) points[0].y--;
454 if(((right-left) | -2) == -2) points[1].x--;
456 dx1=points[3].x-points[2].x;
457 dy1=points[3].y-points[2].y;
458 if(((top-bottom) | -2 ) == -2)
459 if(dy1 < 0) points[2].y--;
461 if( dy1>0) points[3].y--;
462 if(((right-left) | -2) == -2 ) points[2].x--;
465 if( dx1 * 64 < dy1 * -37 ) points[3].x--;
469 TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
470 points, lines+1, CoordModeOrigin );
475 /* Update the DIBSection of the pixmap */
476 X11DRV_UnlockDIBSection(dc, update);
478 physDev->pen.width = oldwidth;
479 physDev->pen.endcap = oldendcap;
484 /***********************************************************************
488 X11DRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
489 INT xstart, INT ystart, INT xend, INT yend )
491 return X11DRV_DrawArc( dc, left, top, right, bottom,
492 xstart, ystart, xend, yend, 0 );
496 /***********************************************************************
500 X11DRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
501 INT xstart, INT ystart, INT xend, INT yend )
503 return X11DRV_DrawArc( dc, left, top, right, bottom,
504 xstart, ystart, xend, yend, 2 );
507 /***********************************************************************
511 X11DRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
512 INT xstart, INT ystart, INT xend, INT yend )
514 return X11DRV_DrawArc( dc, left, top, right, bottom,
515 xstart, ystart, xend, yend, 1 );
519 /***********************************************************************
523 X11DRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
526 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
529 left = XLPTODP( dc, left );
530 top = YLPTODP( dc, top );
531 right = XLPTODP( dc, right );
532 bottom = YLPTODP( dc, bottom );
533 if ((left == right) || (top == bottom)) return TRUE;
535 if (right < left) { INT tmp = right; right = left; left = tmp; }
536 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
538 oldwidth = width = physDev->pen.width;
539 if (!width) width = 1;
540 if(physDev->pen.style == PS_NULL) width = 0;
542 if ((physDev->pen.style == PS_INSIDEFRAME))
544 if (2*width > (right-left)) width=(right-left + 1)/2;
545 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
547 right -= (width - 1) / 2;
549 bottom -= (width - 1) / 2;
551 if(width == 0) width = 1; /* more accurate */
552 physDev->pen.width = width;
554 /* Update the pixmap from the DIB section */
555 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
557 if (X11DRV_SetupGCForBrush( dc ))
559 TSXFillArc( gdi_display, physDev->drawable, physDev->gc,
560 dc->DCOrgX + left, dc->DCOrgY + top,
561 right-left-1, bottom-top-1, 0, 360*64 );
564 if (X11DRV_SetupGCForPen( dc ))
566 TSXDrawArc( gdi_display, physDev->drawable, physDev->gc,
567 dc->DCOrgX + left, dc->DCOrgY + top,
568 right-left-1, bottom-top-1, 0, 360*64 );
572 /* Update the DIBSection from the pixmap */
573 X11DRV_UnlockDIBSection(dc, update);
575 physDev->pen.width = oldwidth;
580 /***********************************************************************
584 X11DRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
586 INT width, oldwidth, oldjoinstyle;
587 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
590 TRACE("(%d %d %d %d)\n",
591 left, top, right, bottom);
593 left = INTERNAL_XWPTODP( dc, left, top );
594 top = INTERNAL_YWPTODP( dc, left, top );
595 right = INTERNAL_XWPTODP( dc, right, bottom );
596 bottom = INTERNAL_YWPTODP( dc, right, bottom );
598 if ((left == right) || (top == bottom)) return TRUE;
600 if (right < left) { INT tmp = right; right = left; left = tmp; }
601 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
603 oldwidth = width = physDev->pen.width;
604 if (!width) width = 1;
605 if(physDev->pen.style == PS_NULL) width = 0;
607 if ((physDev->pen.style == PS_INSIDEFRAME))
609 if (2*width > (right-left)) width=(right-left + 1)/2;
610 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
612 right -= (width - 1) / 2;
614 bottom -= (width - 1) / 2;
616 if(width == 1) width = 0;
617 physDev->pen.width = width;
618 oldjoinstyle = physDev->pen.linejoin;
619 if(physDev->pen.type != PS_GEOMETRIC)
620 physDev->pen.linejoin = PS_JOIN_MITER;
622 /* Update the pixmap from the DIB section */
623 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
625 if ((right > left + width) && (bottom > top + width))
626 if (X11DRV_SetupGCForBrush( dc ))
628 TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
629 dc->DCOrgX + left + (width + 1) / 2,
630 dc->DCOrgY + top + (width + 1) / 2,
631 right-left-width-1, bottom-top-width-1);
634 if (X11DRV_SetupGCForPen( dc ))
636 TSXDrawRectangle( gdi_display, physDev->drawable, physDev->gc,
637 dc->DCOrgX + left, dc->DCOrgY + top,
638 right-left-1, bottom-top-1 );
642 /* Update the DIBSection from the pixmap */
643 X11DRV_UnlockDIBSection(dc, update);
645 physDev->pen.width = oldwidth;
646 physDev->pen.linejoin = oldjoinstyle;
650 /***********************************************************************
654 X11DRV_RoundRect( DC *dc, INT left, INT top, INT right,
655 INT bottom, INT ell_width, INT ell_height )
657 INT width, oldwidth, oldendcap;
658 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
661 TRACE("(%d %d %d %d %d %d\n",
662 left, top, right, bottom, ell_width, ell_height);
664 left = XLPTODP( dc, left );
665 top = YLPTODP( dc, top );
666 right = XLPTODP( dc, right );
667 bottom = YLPTODP( dc, bottom );
669 if ((left == right) || (top == bottom))
672 /* Make sure ell_width and ell_height are >= 1 otherwise XDrawArc gets
673 called with width/height < 0 */
674 ell_width = max(abs( ell_width * dc->vportExtX / dc->wndExtX ), 1);
675 ell_height = max(abs( ell_height * dc->vportExtY / dc->wndExtY ), 1);
677 /* Fix the coordinates */
679 if (right < left) { INT tmp = right; right = left; left = tmp; }
680 if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
682 oldwidth = width = physDev->pen.width;
683 oldendcap = physDev->pen.endcap;
684 if (!width) width = 1;
685 if(physDev->pen.style == PS_NULL) width = 0;
687 if ((physDev->pen.style == PS_INSIDEFRAME))
689 if (2*width > (right-left)) width=(right-left + 1)/2;
690 if (2*width > (bottom-top)) width=(bottom-top + 1)/2;
692 right -= (width - 1) / 2;
694 bottom -= (width - 1) / 2;
696 if(width == 0) width = 1;
697 physDev->pen.width = width;
698 physDev->pen.endcap = PS_ENDCAP_SQUARE;
700 /* Update the pixmap from the DIB section */
701 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
704 if (X11DRV_SetupGCForBrush( dc ))
706 if (ell_width > (right-left) )
707 if (ell_height > (bottom-top) )
708 XFillArc( gdi_display, physDev->drawable, physDev->gc,
709 dc->DCOrgX + left, dc->DCOrgY + top,
710 right - left - 1, bottom - top - 1,
713 XFillArc( gdi_display, physDev->drawable, physDev->gc,
714 dc->DCOrgX + left, dc->DCOrgY + top,
715 right - left - 1, ell_height, 0, 180 * 64 );
716 XFillArc( gdi_display, physDev->drawable, physDev->gc,
718 dc->DCOrgY + bottom - ell_height - 1,
719 right - left - 1, ell_height, 180 * 64,
722 else if (ell_height > (bottom-top) ){
723 XFillArc( gdi_display, physDev->drawable, physDev->gc,
724 dc->DCOrgX + left, dc->DCOrgY + top,
725 ell_width, bottom - top - 1, 90 * 64, 180 * 64 );
726 XFillArc( gdi_display, physDev->drawable, physDev->gc,
727 dc->DCOrgX + right - ell_width -1, dc->DCOrgY + top,
728 ell_width, bottom - top - 1, 270 * 64, 180 * 64 );
730 XFillArc( gdi_display, physDev->drawable, physDev->gc,
731 dc->DCOrgX + left, dc->DCOrgY + top,
732 ell_width, ell_height, 90 * 64, 90 * 64 );
733 XFillArc( gdi_display, physDev->drawable, physDev->gc,
735 dc->DCOrgY + bottom - ell_height - 1,
736 ell_width, ell_height, 180 * 64, 90 * 64 );
737 XFillArc( gdi_display, physDev->drawable, physDev->gc,
738 dc->DCOrgX + right - ell_width - 1,
739 dc->DCOrgY + bottom - ell_height - 1,
740 ell_width, ell_height, 270 * 64, 90 * 64 );
741 XFillArc( gdi_display, physDev->drawable, physDev->gc,
742 dc->DCOrgX + right - ell_width - 1,
744 ell_width, ell_height, 0, 90 * 64 );
746 if (ell_width < right - left)
748 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
749 dc->DCOrgX + left + (ell_width + 1) / 2,
750 dc->DCOrgY + top + 1,
751 right - left - ell_width - 1,
752 (ell_height + 1) / 2 - 1);
753 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
754 dc->DCOrgX + left + (ell_width + 1) / 2,
755 dc->DCOrgY + bottom - (ell_height) / 2 - 1,
756 right - left - ell_width - 1,
759 if (ell_height < bottom - top)
761 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
762 dc->DCOrgX + left + 1,
763 dc->DCOrgY + top + (ell_height + 1) / 2,
765 bottom - top - ell_height - 1);
769 /* FIXME: this could be done with on X call
770 * more efficient and probably more correct
771 * on any X server: XDrawArcs will draw
772 * straight horizontal and vertical lines
773 * if width or height are zero.
775 * BTW this stuff is optimized for an Xfree86 server
776 * read the comments inside the X11DRV_DrawArc function
778 if (X11DRV_SetupGCForPen(dc)) {
779 if (ell_width > (right-left) )
780 if (ell_height > (bottom-top) )
781 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
782 dc->DCOrgX + left, dc->DCOrgY + top,
783 right - left - 1, bottom -top - 1, 0 , 360 * 64 );
785 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
786 dc->DCOrgX + left, dc->DCOrgY + top,
787 right - left - 1, ell_height - 1, 0 , 180 * 64 );
788 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
790 dc->DCOrgY + bottom - ell_height,
791 right - left - 1, ell_height - 1, 180 * 64 , 180 * 64 );
793 else if (ell_height > (bottom-top) ){
794 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
795 dc->DCOrgX + left, dc->DCOrgY + top,
796 ell_width - 1 , bottom - top - 1, 90 * 64 , 180 * 64 );
797 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
798 dc->DCOrgX + right - ell_width,
800 ell_width - 1 , bottom - top - 1, 270 * 64 , 180 * 64 );
802 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
803 dc->DCOrgX + left, dc->DCOrgY + top,
804 ell_width - 1, ell_height - 1, 90 * 64, 90 * 64 );
805 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
806 dc->DCOrgX + left, dc->DCOrgY + bottom - ell_height,
807 ell_width - 1, ell_height - 1, 180 * 64, 90 * 64 );
808 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
809 dc->DCOrgX + right - ell_width,
810 dc->DCOrgY + bottom - ell_height,
811 ell_width - 1, ell_height - 1, 270 * 64, 90 * 64 );
812 XDrawArc( gdi_display, physDev->drawable, physDev->gc,
813 dc->DCOrgX + right - ell_width, dc->DCOrgY + top,
814 ell_width - 1, ell_height - 1, 0, 90 * 64 );
816 if (ell_width < right - left)
818 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
819 dc->DCOrgX + left + ell_width / 2,
821 dc->DCOrgX + right - (ell_width+1) / 2,
823 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
824 dc->DCOrgX + left + ell_width / 2 ,
825 dc->DCOrgY + bottom - 1,
826 dc->DCOrgX + right - (ell_width+1)/ 2,
827 dc->DCOrgY + bottom - 1);
829 if (ell_height < bottom - top)
831 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
832 dc->DCOrgX + right - 1,
833 dc->DCOrgY + top + ell_height / 2,
834 dc->DCOrgX + right - 1,
835 dc->DCOrgY + bottom - (ell_height+1) / 2);
836 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
838 dc->DCOrgY + top + ell_height / 2,
840 dc->DCOrgY + bottom - (ell_height+1) / 2);
845 /* Update the DIBSection from the pixmap */
846 X11DRV_UnlockDIBSection(dc, update);
848 physDev->pen.width = oldwidth;
849 physDev->pen.endcap = oldendcap;
854 /***********************************************************************
858 X11DRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
861 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
863 x = dc->DCOrgX + INTERNAL_XWPTODP( dc, x, y );
864 y = dc->DCOrgY + INTERNAL_YWPTODP( dc, x, y );
865 pixel = X11DRV_PALETTE_ToPhysical( dc, color );
867 /* Update the pixmap from the DIB section */
868 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
870 /* inefficient but simple... */
872 XSetForeground( gdi_display, physDev->gc, pixel );
873 XSetFunction( gdi_display, physDev->gc, GXcopy );
874 XDrawPoint( gdi_display, physDev->drawable, physDev->gc, x, y );
877 /* Update the DIBSection from the pixmap */
878 X11DRV_UnlockDIBSection(dc, TRUE);
880 return X11DRV_PALETTE_ToLogical(pixel);
884 /***********************************************************************
888 X11DRV_GetPixel( DC *dc, INT x, INT y )
890 static Pixmap pixmap = 0;
893 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
895 /* Update the pixmap from the DIB section */
896 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
898 x = dc->DCOrgX + INTERNAL_XWPTODP( dc, x, y );
899 y = dc->DCOrgY + INTERNAL_YWPTODP( dc, x, y );
901 if (dc->flags & DC_MEMORY)
903 image = XGetImage( gdi_display, physDev->drawable, x, y, 1, 1,
904 AllPlanes, ZPixmap );
908 /* If we are reading from the screen, use a temporary copy */
909 /* to avoid a BadMatch error */
910 if (!pixmap) pixmap = XCreatePixmap( gdi_display, root_window,
911 1, 1, dc->bitsPerPixel );
912 XCopyArea( gdi_display, physDev->drawable, pixmap, BITMAP_colorGC,
914 image = XGetImage( gdi_display, pixmap, 0, 0, 1, 1, AllPlanes, ZPixmap );
916 pixel = XGetPixel( image, 0, 0 );
917 XDestroyImage( image );
920 /* Update the DIBSection from the pixmap */
921 X11DRV_UnlockDIBSection(dc, FALSE);
923 return X11DRV_PALETTE_ToLogical(pixel);
927 /***********************************************************************
931 X11DRV_PaintRgn( DC *dc, HRGN hrgn )
934 HRGN tmpVisRgn, prevVisRgn;
935 HDC hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
936 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
938 if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
940 /* Transform region into device co-ords */
941 if ( !REGION_LPTODP( hdc, tmpVisRgn, hrgn )
942 || OffsetRgn( tmpVisRgn, dc->DCOrgX, dc->DCOrgY ) == ERROR) {
943 DeleteObject( tmpVisRgn );
947 /* Modify visible region */
948 if (!(prevVisRgn = SaveVisRgn16( hdc ))) {
949 DeleteObject( tmpVisRgn );
952 CombineRgn( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
953 SelectVisRgn16( hdc, tmpVisRgn );
954 DeleteObject( tmpVisRgn );
956 /* Fill the region */
958 GetRgnBox( dc->hGCClipRgn, &box );
959 if (X11DRV_SetupGCForBrush( dc ))
961 /* Update the pixmap from the DIB section */
962 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
964 TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
966 box.right-box.left, box.bottom-box.top );
968 /* Update the DIBSection from the pixmap */
969 X11DRV_UnlockDIBSection(dc, TRUE);
972 /* Restore the visible region */
974 RestoreVisRgn16( hdc );
978 /**********************************************************************
982 X11DRV_Polyline( DC *dc, const POINT* pt, INT count )
987 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
989 if((oldwidth = physDev->pen.width) == 0) physDev->pen.width = 1;
991 if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * count )))
993 WARN("No memory to convert POINTs to XPoints!\n");
996 for (i = 0; i < count; i++)
998 points[i].x = dc->DCOrgX + INTERNAL_XWPTODP( dc, pt[i].x, pt[i].y );
999 points[i].y = dc->DCOrgY + INTERNAL_YWPTODP( dc, pt[i].x, pt[i].y );
1002 if (X11DRV_SetupGCForPen ( dc ))
1004 /* Update the pixmap from the DIB section */
1005 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1007 TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
1008 points, count, CoordModeOrigin );
1010 /* Update the DIBSection from the pixmap */
1011 X11DRV_UnlockDIBSection(dc, TRUE);
1014 HeapFree( GetProcessHeap(), 0, points );
1015 physDev->pen.width = oldwidth;
1020 /**********************************************************************
1024 X11DRV_Polygon( DC *dc, const POINT* pt, INT count )
1028 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1029 BOOL update = FALSE;
1031 if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) )))
1033 WARN("No memory to convert POINTs to XPoints!\n");
1036 for (i = 0; i < count; i++)
1038 points[i].x = dc->DCOrgX + INTERNAL_XWPTODP( dc, pt[i].x, pt[i].y );
1039 points[i].y = dc->DCOrgY + INTERNAL_YWPTODP( dc, pt[i].x, pt[i].y );
1041 points[count] = points[0];
1043 /* Update the pixmap from the DIB section */
1044 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1046 if (X11DRV_SetupGCForBrush( dc ))
1048 TSXFillPolygon( gdi_display, physDev->drawable, physDev->gc,
1049 points, count+1, Complex, CoordModeOrigin);
1052 if (X11DRV_SetupGCForPen ( dc ))
1054 TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
1055 points, count+1, CoordModeOrigin );
1059 /* Update the DIBSection from the pixmap */
1060 X11DRV_UnlockDIBSection(dc, update);
1062 HeapFree( GetProcessHeap(), 0, points );
1067 /**********************************************************************
1068 * X11DRV_PolyPolygon
1071 X11DRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polygons)
1074 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1076 /* FIXME: The points should be converted to device coords before */
1077 /* creating the region. */
1079 hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->polyFillMode );
1080 X11DRV_PaintRgn( dc, hrgn );
1081 DeleteObject( hrgn );
1083 /* Draw the outline of the polygons */
1085 if (X11DRV_SetupGCForPen ( dc ))
1090 /* Update the pixmap from the DIB section */
1091 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1093 for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
1094 if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (max+1) )))
1096 WARN("No memory to convert POINTs to XPoints!\n");
1099 for (i = 0; i < polygons; i++)
1101 for (j = 0; j < counts[i]; j++)
1103 points[j].x = dc->DCOrgX + INTERNAL_XWPTODP( dc, pt->x, pt->y );
1104 points[j].y = dc->DCOrgY + INTERNAL_YWPTODP( dc, pt->x, pt->y );
1107 points[j] = points[0];
1108 TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
1109 points, j + 1, CoordModeOrigin );
1112 /* Update the DIBSection of the dc's bitmap */
1113 X11DRV_UnlockDIBSection(dc, TRUE);
1115 HeapFree( GetProcessHeap(), 0, points );
1121 /**********************************************************************
1122 * X11DRV_PolyPolyline
1125 X11DRV_PolyPolyline( DC *dc, const POINT* pt, const DWORD* counts, DWORD polylines )
1127 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1129 if (X11DRV_SetupGCForPen ( dc ))
1134 /* Update the pixmap from the DIB section */
1135 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1137 for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
1138 if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * max )))
1140 WARN("No memory to convert POINTs to XPoints!\n");
1143 for (i = 0; i < polylines; i++)
1145 for (j = 0; j < counts[i]; j++)
1147 points[j].x = dc->DCOrgX + INTERNAL_XWPTODP( dc, pt->x, pt->y );
1148 points[j].y = dc->DCOrgY + INTERNAL_YWPTODP( dc, pt->x, pt->y );
1151 TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
1152 points, j, CoordModeOrigin );
1155 /* Update the DIBSection of the dc's bitmap */
1156 X11DRV_UnlockDIBSection(dc, TRUE);
1158 HeapFree( GetProcessHeap(), 0, points );
1164 /**********************************************************************
1165 * X11DRV_InternalFloodFill
1167 * Internal helper function for flood fill.
1168 * (xorg,yorg) is the origin of the X image relative to the drawable.
1169 * (x,y) is relative to the origin of the X image.
1171 static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
1174 Pixel pixel, WORD fillType )
1176 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1179 #define TO_FLOOD(x,y) ((fillType == FLOODFILLBORDER) ? \
1180 (XGetPixel(image,x,y) != pixel) : \
1181 (XGetPixel(image,x,y) == pixel))
1183 if (!TO_FLOOD(x,y)) return;
1185 /* Find left and right boundaries */
1188 while ((left > 0) && TO_FLOOD( left-1, y )) left--;
1189 while ((right < image->width) && TO_FLOOD( right, y )) right++;
1190 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1191 xOrg + left, yOrg + y, right-left, 1 );
1193 /* Set the pixels of this line so we don't fill it again */
1195 for (x = left; x < right; x++)
1197 if (fillType == FLOODFILLBORDER) XPutPixel( image, x, y, pixel );
1198 else XPutPixel( image, x, y, ~pixel );
1201 /* Fill the line above */
1208 while ((x < right) && !TO_FLOOD(x,y)) x++;
1209 if (x >= right) break;
1210 while ((x < right) && TO_FLOOD(x,y)) x++;
1211 X11DRV_InternalFloodFill(image, dc, x-1, y,
1212 xOrg, yOrg, pixel, fillType );
1216 /* Fill the line below */
1218 if ((y += 2) < image->height)
1223 while ((x < right) && !TO_FLOOD(x,y)) x++;
1224 if (x >= right) break;
1225 while ((x < right) && TO_FLOOD(x,y)) x++;
1226 X11DRV_InternalFloodFill(image, dc, x-1, y,
1227 xOrg, yOrg, pixel, fillType );
1234 /**********************************************************************
1235 * X11DRV_ExtFloodFill
1238 X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color,
1243 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1245 TRACE("X11DRV_ExtFloodFill %d,%d %06lx %d\n", x, y, color, fillType );
1247 if (!PtVisible( dc->hSelf, x, y )) return FALSE;
1248 if (GetRgnBox( dc->hGCClipRgn, &rect ) == ERROR) return FALSE;
1250 if (!(image = TSXGetImage( gdi_display, physDev->drawable,
1253 rect.right - rect.left,
1254 rect.bottom - rect.top,
1255 AllPlanes, ZPixmap ))) return FALSE;
1258 if (X11DRV_SetupGCForBrush( dc ))
1260 /* Update the pixmap from the DIB section */
1261 X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
1263 /* ROP mode is always GXcopy for flood-fill */
1264 XSetFunction( gdi_display, physDev->gc, GXcopy );
1265 X11DRV_InternalFloodFill(image, dc,
1266 XLPTODP(dc,x) + dc->DCOrgX - rect.left,
1267 YLPTODP(dc,y) + dc->DCOrgY - rect.top,
1268 rect.left, rect.top,
1269 X11DRV_PALETTE_ToPhysical( dc, color ),
1271 /* Update the DIBSection of the dc's bitmap */
1272 X11DRV_UnlockDIBSection(dc, TRUE);
1275 XDestroyImage( image );
1276 wine_tsx11_unlock();
1280 /**********************************************************************
1284 X11DRV_SetBkColor( DC *dc, COLORREF color )
1286 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1289 oldColor = dc->backgroundColor;
1290 dc->backgroundColor = color;
1292 physDev->backgroundPixel = X11DRV_PALETTE_ToPhysical( dc, color );
1297 /**********************************************************************
1298 * X11DRV_SetTextColor
1301 X11DRV_SetTextColor( DC *dc, COLORREF color )
1303 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
1306 oldColor = dc->textColor;
1307 dc->textColor = color;
1309 physDev->textPixel = X11DRV_PALETTE_ToPhysical( dc, color );
1314 /***********************************************************************
1317 BOOL X11DRV_GetDCOrgEx( DC *dc, LPPOINT lpp )
1319 if (!(dc->flags & DC_MEMORY))
1321 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *) dc->physDev;
1323 int x, y, w, h, border, depth;
1325 /* FIXME: this is not correct for managed windows */
1326 TSXGetGeometry( gdi_display, physDev->drawable, &root,
1327 &x, &y, &w, &h, &border, &depth );
1331 else lpp->x = lpp->y = 0;