1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
31 #include "gdkdrawable.h"
32 #include "gdkprivate.h"
35 #define G_PI 3.14159265358979323846
39 gdk_draw_point (GdkDrawable *drawable,
44 GdkWindowPrivate *drawable_private;
45 GdkGCPrivate *gc_private;
48 g_return_if_fail (drawable != NULL);
49 g_return_if_fail (gc != NULL);
51 drawable_private = (GdkWindowPrivate*) drawable;
52 if (drawable_private->destroyed)
54 gc_private = (GdkGCPrivate*) gc;
56 hdc = gdk_gc_predraw (drawable_private, gc_private);
58 /* We use LineTo because SetPixel wants the COLORREF directly,
59 * and doesn't use the current pen, which is what we want.
61 if (!MoveToEx (hdc, x, y, NULL))
62 g_warning ("gdk_draw_point: MoveToEx failed");
63 if (!LineTo (hdc, x + 1, y))
64 g_warning ("gdk_draw_point: LineTo failed");
66 gdk_gc_postdraw (drawable_private, gc_private);
70 gdk_draw_line (GdkDrawable *drawable,
77 GdkWindowPrivate *drawable_private;
78 GdkGCPrivate *gc_private;
81 g_return_if_fail (drawable != NULL);
82 g_return_if_fail (gc != NULL);
84 drawable_private = (GdkWindowPrivate*) drawable;
85 if (drawable_private->destroyed)
87 gc_private = (GdkGCPrivate*) gc;
89 hdc = gdk_gc_predraw (drawable_private, gc_private);
91 GDK_NOTE (MISC, g_print ("gdk_draw_line: %#x (%d) +%d+%d..+%d+%d\n",
92 drawable_private->xwindow, gc_private,
95 MoveToEx (hdc, x1, y1, NULL);
96 if (!LineTo (hdc, x2, y2))
97 g_warning ("gdk_draw_line: LineTo #1 failed");
98 /* LineTo doesn't draw the last point, so if we have a pen width of 1,
99 * we draw the end pixel separately... With wider pens we don't care.
100 * //HB: But the NT developers don't read their API documentation ...
102 if (gc_private->pen_width == 1
103 && GetVersion () > 0x80000000)
104 if (!LineTo (hdc, x2 + 1, y2))
105 g_warning ("gdk_draw_line: LineTo #2 failed");
106 gdk_gc_postdraw (drawable_private, gc_private);
110 gdk_draw_rectangle (GdkDrawable *drawable,
118 GdkWindowPrivate *drawable_private;
119 GdkGCPrivate *gc_private;
121 HGDIOBJ oldpen, oldbrush;
123 g_return_if_fail (drawable != NULL);
124 g_return_if_fail (gc != NULL);
126 drawable_private = (GdkWindowPrivate*) drawable;
127 if (drawable_private->destroyed)
129 gc_private = (GdkGCPrivate*) gc;
132 width = drawable_private->width;
134 height = drawable_private->height;
136 hdc = gdk_gc_predraw (drawable_private, gc_private);
138 GDK_NOTE (MISC, g_print ("gdk_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
139 drawable_private->xwindow,
141 (filled ? "fill " : ""),
142 width, height, x, y));
146 HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
147 HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
150 GetObject (hbr, sizeof (lbr), &lbr);
151 GetObject (hpen, sizeof (lpen), &lpen);
153 g_print ("current brush: style = %s, color = 0x%.08x\n",
154 (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
156 g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
157 (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
164 oldpen = SelectObject (hdc, GetStockObject (NULL_PEN));
166 oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
168 if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
169 g_warning ("gdk_draw_rectangle: Rectangle failed");
172 SelectObject (hdc, oldpen);
174 SelectObject (hdc, oldbrush);
176 gdk_gc_postdraw (drawable_private, gc_private);
180 gdk_draw_arc (GdkDrawable *drawable,
190 GdkWindowPrivate *drawable_private;
191 GdkGCPrivate *gc_private;
193 int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
195 g_return_if_fail (drawable != NULL);
196 g_return_if_fail (gc != NULL);
198 drawable_private = (GdkWindowPrivate*) drawable;
199 if (drawable_private->destroyed)
201 gc_private = (GdkGCPrivate*) gc;
204 width = drawable_private->width;
206 height = drawable_private->height;
208 GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x %d,%d,%d,%d %d %d\n",
209 drawable_private->xwindow,
210 x, y, width, height, angle1, angle2));
212 if (width != 0 && height != 0 && angle2 != 0)
214 hdc = gdk_gc_predraw (drawable_private, gc_private);
216 if (angle2 >= 360*64)
218 nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
222 /* The 100. is just an arbitrary value */
223 nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
224 nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
225 nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
226 nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
230 nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
231 nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
232 nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
233 nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
238 GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
239 x, y, x+width, y+height,
240 nXStartArc, nYStartArc,
241 nXEndArc, nYEndArc));
242 Pie (hdc, x, y, x+width, y+height,
243 nXStartArc, nYStartArc, nXEndArc, nYEndArc);
247 GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
248 x, y, x+width, y+height,
249 nXStartArc, nYStartArc,
250 nXEndArc, nYEndArc));
251 Arc (hdc, x, y, x+width, y+height,
252 nXStartArc, nYStartArc, nXEndArc, nYEndArc);
254 gdk_gc_postdraw (drawable_private, gc_private);
259 gdk_draw_polygon (GdkDrawable *drawable,
265 GdkWindowPrivate *drawable_private;
266 GdkGCPrivate *gc_private;
271 g_return_if_fail (drawable != NULL);
272 g_return_if_fail (gc != NULL);
274 drawable_private = (GdkWindowPrivate*) drawable;
275 if (drawable_private->destroyed)
277 gc_private = (GdkGCPrivate*) gc;
279 GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n",
280 drawable_private->xwindow, gc_private,
286 hdc = gdk_gc_predraw (drawable_private, gc_private);
287 pts = g_malloc ((npoints+1) * sizeof (POINT));
289 for (i = 0; i < npoints; i++)
291 pts[i].x = points[i].x;
292 pts[i].y = points[i].y;
295 if ((points[0].x != points[npoints-1].x) ||
296 (points[0].y != points[npoints-1].y))
298 pts[npoints].x = points[0].x;
299 pts[npoints].y = points[0].y;
304 if (!Polygon (hdc, pts, npoints))
305 g_warning ("gdk_draw_polygon: Polygon failed");
309 if (!Polyline (hdc, pts, npoints))
310 g_warning ("gdk_draw_polygon: Polyline failed");
313 gdk_gc_postdraw (drawable_private, gc_private);
319 gdk_draw_string (GdkDrawable *drawable,
326 gdk_draw_text (drawable, font, gc, x, y, string, strlen (string));
331 * Modified by Li-Da Lho to draw 16 bits and Multibyte strings
333 * Interface changed: add "GdkFont *font" to specify font or fontset explicitely
336 gdk_draw_text (GdkDrawable *drawable,
344 GdkWindowPrivate *drawable_private;
345 GdkFontPrivate *font_private;
346 GdkGCPrivate *gc_private;
351 g_return_if_fail (drawable != NULL);
352 g_return_if_fail (font != NULL);
353 g_return_if_fail (gc != NULL);
354 g_return_if_fail (text != NULL);
356 drawable_private = (GdkWindowPrivate*) drawable;
357 if (drawable_private->destroyed)
359 gc_private = (GdkGCPrivate*) gc;
360 font_private = (GdkFontPrivate*) font;
362 if (font->type == GDK_FONT_FONT)
364 hdc = gdk_gc_predraw (drawable_private, gc_private);
365 xfont = (HFONT) font_private->xfont;
367 GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d) %#x "
368 "+%d+%d font: %#x \"%.*s\" length: %d\n",
369 drawable_private->xwindow,
370 gc_private, gc_private->xgc,
372 (text_length > 10 ? 10 : text_length),
375 if ((oldfont = SelectObject (hdc, xfont)) == NULL)
376 g_warning ("gdk_draw_text: SelectObject failed");
377 if (!TextOutA (hdc, x, y, text, text_length))
378 g_warning ("gdk_draw_text: TextOutA failed");
379 SelectObject (hdc, oldfont);
380 gdk_gc_postdraw (drawable_private, gc_private);
383 g_error ("undefined font type");
387 gdk_draw_text_wc (GdkDrawable *drawable,
392 const GdkWChar *text,
395 GdkWindowPrivate *drawable_private;
396 GdkFontPrivate *font_private;
397 GdkGCPrivate *gc_private;
401 g_return_if_fail (drawable != NULL);
402 g_return_if_fail (font != NULL);
403 g_return_if_fail (gc != NULL);
404 g_return_if_fail (text != NULL);
406 drawable_private = (GdkWindowPrivate*) drawable;
407 if (drawable_private->destroyed)
409 gc_private = (GdkGCPrivate*) gc;
410 font_private = (GdkFontPrivate*) font;
412 if (font->type == GDK_FONT_FONT)
418 hdc = gdk_gc_predraw (drawable_private, gc_private);
419 xfont = (HFONT) font_private->xfont;
421 GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d) %#x "
422 "+%d+%d font: %#x length: %d\n",
423 drawable_private->xwindow,
424 gc_private, gc_private->xgc,
428 if ((oldfont = SelectObject (hdc, xfont)) == NULL)
429 g_warning ("gdk_draw_text: SelectObject failed");
430 wcstr = g_new (wchar_t, text_length);
431 for (i = 0; i < text_length; i++)
433 if (!TextOutW (hdc, x, y, wcstr, text_length))
434 g_warning ("gdk_draw_text: TextOutW failed");
436 SelectObject (hdc, oldfont);
437 gdk_gc_postdraw (drawable_private, gc_private);
440 g_error ("undefined font type");
444 gdk_draw_pixmap (GdkDrawable *drawable,
454 GdkWindowPrivate *drawable_private;
455 GdkWindowPrivate *src_private;
456 GdkGCPrivate *gc_private;
460 HRGN src_rgn, draw_rgn, outside_rgn;
463 g_return_if_fail (drawable != NULL);
464 g_return_if_fail (src != NULL);
465 g_return_if_fail (gc != NULL);
467 drawable_private = (GdkWindowPrivate*) drawable;
468 src_private = (GdkWindowPrivate*) src;
469 if (drawable_private->destroyed || src_private->destroyed)
471 gc_private = (GdkGCPrivate*) gc;
474 width = src_private->width; /* Or should we subtract xsrc? */
476 height = src_private->height; /* Ditto? */
478 GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x "
479 "src: %#x %dx%d@+%d+%d"
480 " dest: %#x @+%d+%d\n",
481 drawable_private->xwindow,
482 src_private->xwindow,
483 width, height, xsrc, ysrc,
484 drawable_private->xwindow, xdest, ydest));
486 hdc = gdk_gc_predraw (drawable_private, gc_private);
488 src_rgn = CreateRectRgn (0, 0, src_private->width + 1, src_private->height + 1);
489 draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
491 outside_rgn = CreateRectRgnIndirect (&r);
493 if (drawable_private->window_type != GDK_WINDOW_PIXMAP)
495 /* If we are drawing on a window, calculate the region that is
496 * outside the source pixmap, and invalidate that, causing it to
499 if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
501 OffsetRgn (outside_rgn, xdest, ydest);
502 GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
503 g_print ("...calling InvalidateRgn, "
504 "bbox: %dx%d@+%d+%d\n",
505 r.right - r.left - 1, r.bottom - r.top - 1,
507 InvalidateRgn (drawable_private->xwindow, outside_rgn, TRUE);
511 #if 1 /* Don't know if this is necessary */
512 if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
513 g_warning ("gdk_draw_pixmap: CombineRgn returned a COMPLEXREGION");
515 GetRgnBox (draw_rgn, &r);
518 || r.right != xsrc + width + 1
519 || r.bottom != ysrc + height + 1)
521 xdest += r.left - xsrc;
523 ydest += r.top - ysrc;
525 width = r.right - xsrc - 1;
526 height = r.bottom - ysrc - 1;
528 GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
530 width, height, xsrc, ysrc,
535 DeleteObject (src_rgn);
536 DeleteObject (draw_rgn);
537 DeleteObject (outside_rgn);
539 /* Strangely enough, this function is called also to bitblt
542 if (src_private->window_type == GDK_WINDOW_PIXMAP)
544 if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
545 g_warning ("gdk_draw_pixmap: CreateCompatibleDC failed");
547 if ((hgdiobj = SelectObject (srcdc, src_private->xwindow)) == NULL)
548 g_warning ("gdk_draw_pixmap: SelectObject #1 failed");
550 if (!BitBlt (hdc, xdest, ydest, width, height,
551 srcdc, xsrc, ysrc, SRCCOPY))
552 g_warning ("gdk_draw_pixmap: BitBlt failed");
554 if ((SelectObject (srcdc, hgdiobj) == NULL))
555 g_warning ("gdk_draw_pixmap: SelectObject #2 failed");
557 if (!DeleteDC (srcdc))
558 g_warning ("gdk_draw_pixmap: DeleteDC failed");
562 if (drawable_private->xwindow == src_private->xwindow)
564 /* Blitting inside a window, use ScrollDC */
565 RECT scrollRect, clipRect, emptyRect;
568 scrollRect.left = MIN (xsrc, xdest);
569 scrollRect.top = MIN (ysrc, ydest);
570 scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
571 scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
573 clipRect.left = xdest;
574 clipRect.top = ydest;
575 clipRect.right = xdest + width + 1;
576 clipRect.bottom = ydest + height + 1;
578 SetRectEmpty (&emptyRect);
579 updateRgn = CreateRectRgnIndirect (&emptyRect);
580 if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
581 &scrollRect, &clipRect,
583 g_warning ("gdk_draw_pixmap: ScrollDC failed");
584 if (!InvalidateRgn (drawable_private->xwindow, updateRgn, FALSE))
585 g_warning ("gdk_draw_pixmap: InvalidateRgn failed");
586 if (!UpdateWindow (drawable_private->xwindow))
587 g_warning ("gdk_draw_pixmap: UpdateWindow failed");
591 if ((srcdc = GetDC (src_private->xwindow)) == NULL)
592 g_warning ("gdk_draw_pixmap: GetDC failed");
594 if (!BitBlt (hdc, xdest, ydest, width, height,
595 srcdc, xsrc, ysrc, SRCCOPY))
596 g_warning ("gdk_draw_pixmap: BitBlt failed");
597 ReleaseDC (src_private->xwindow, srcdc);
600 gdk_gc_postdraw (drawable_private, gc_private);
604 gdk_draw_image (GdkDrawable *drawable,
614 GdkImagePrivate *image_private;
616 g_return_if_fail (drawable != NULL);
617 g_return_if_fail (image != NULL);
618 g_return_if_fail (gc != NULL);
620 image_private = (GdkImagePrivate*) image;
622 g_return_if_fail (image_private->image_put != NULL);
625 width = image->width;
627 height = image->height;
629 (* image_private->image_put) (drawable, gc, image, xsrc, ysrc,
630 xdest, ydest, width, height);
634 gdk_draw_points (GdkDrawable *drawable,
639 GdkWindowPrivate *drawable_private;
640 GdkGCPrivate *gc_private;
644 g_return_if_fail (drawable != NULL);
645 g_return_if_fail ((points != NULL) && (npoints > 0));
646 g_return_if_fail (gc != NULL);
648 drawable_private = (GdkWindowPrivate*) drawable;
649 if (drawable_private->destroyed)
651 gc_private = (GdkGCPrivate*) gc;
653 hdc = gdk_gc_predraw (drawable_private, gc_private);
655 GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x destdc: (%d) %#x "
657 drawable_private->xwindow, gc_private, hdc,
660 for (i = 0; i < npoints; i++)
662 if (!MoveToEx (hdc, points[i].x, points[i].y, NULL))
663 g_warning ("gdk_draw_points: MoveToEx failed");
664 if (!LineTo (hdc, points[i].x + 1, points[i].y))
665 g_warning ("gdk_draw_points: LineTo failed");
667 gdk_gc_postdraw (drawable_private, gc_private);
671 gdk_draw_segments (GdkDrawable *drawable,
676 GdkWindowPrivate *drawable_private;
677 GdkGCPrivate *gc_private;
684 g_return_if_fail (drawable != NULL);
685 g_return_if_fail (segs != NULL);
686 g_return_if_fail (gc != NULL);
688 drawable_private = (GdkWindowPrivate*) drawable;
689 if (drawable_private->destroyed)
691 gc_private = (GdkGCPrivate*) gc;
693 hdc = gdk_gc_predraw (drawable_private, gc_private);
695 for (i = 0; i < nsegs; i++)
697 if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
698 g_warning ("gdk_draw_segments: MoveToEx failed");
699 if (!LineTo (hdc, segs[i].x2, segs[i].y2))
700 g_warning ("gdk_draw_segments: LineTo #1 failed");
703 if (gc_private->pen_width == 1)
704 if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
705 g_warning ("gdk_draw_segments: LineTo #2 failed");
707 gdk_gc_postdraw (drawable_private, gc_private);
711 gdk_draw_lines (GdkDrawable *drawable,
716 GdkWindowPrivate *drawable_private;
717 GdkGCPrivate *gc_private;
725 g_return_if_fail (drawable != NULL);
726 g_return_if_fail (points != NULL);
727 g_return_if_fail (gc != NULL);
729 drawable_private = (GdkWindowPrivate*) drawable;
730 gc_private = (GdkGCPrivate*) gc;
732 hdc = gdk_gc_predraw (drawable_private, gc_private);
734 pts = g_malloc (npoints * sizeof (POINT));
736 for (i = 0; i < npoints; i++)
738 pts[i].x = points[i].x;
739 pts[i].y = points[i].y;
742 if (!Polyline (hdc, pts, npoints))
743 g_warning ("gdk_draw_lines: Polyline(,,%d) failed", npoints);
748 if (gc_private->pen_width == 1)
750 MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
751 if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
752 g_warning ("gdk_draw_lines: LineTo failed");
755 MoveToEx (hdc, points[0].x, points[0].y, NULL);
756 for (i = 1; i < npoints; i++)
757 if (!LineTo (hdc, points[i].x, points[i].y))
758 g_warning ("gdk_draw_lines: LineTo #1 failed");
761 if (gc_private->pen_width == 1)
762 if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
763 g_warning ("gdk_draw_lines: LineTo #2 failed");
765 gdk_gc_postdraw (drawable_private, gc_private);