1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-2004 Tor Lillqvist
4 * Copyright (C) 2001-2005 Hans Breuer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
24 * file for a list of people on the GTK+ Team. See the ChangeLog
25 * files for a list of changes. These files are distributed with
26 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
34 #include <pango/pangowin32.h>
35 #include <cairo-win32.h>
37 #include "gdkscreen.h" /* gdk_screen_get_default() */
38 #include "gdkregion-generic.h"
39 #include "gdkprivate-win32.h"
41 #define ROP3_D 0x00AA0029
42 #define ROP3_DSna 0x00220326
43 #define ROP3_DSPDxax 0x00E20746
45 #define LINE_ATTRIBUTES (GDK_GC_LINE_WIDTH|GDK_GC_LINE_STYLE| \
46 GDK_GC_CAP_STYLE|GDK_GC_JOIN_STYLE)
48 #define MUST_RENDER_DASHES_MANUALLY(gcwin32) \
49 (gcwin32->line_style == GDK_LINE_DOUBLE_DASH || \
50 (gcwin32->line_style == GDK_LINE_ON_OFF_DASH && gcwin32->pen_dash_offset))
52 static void gdk_win32_draw_rectangle (GdkDrawable *drawable,
59 static void gdk_win32_draw_arc (GdkDrawable *drawable,
68 static void gdk_win32_draw_polygon (GdkDrawable *drawable,
73 static void gdk_win32_draw_text (GdkDrawable *drawable,
80 static void gdk_win32_draw_text_wc (GdkDrawable *drawable,
87 static void gdk_win32_draw_drawable (GdkDrawable *drawable,
96 static void gdk_win32_draw_points (GdkDrawable *drawable,
100 static void gdk_win32_draw_segments (GdkDrawable *drawable,
104 static void gdk_win32_draw_lines (GdkDrawable *drawable,
108 static void gdk_win32_draw_image (GdkDrawable *drawable,
118 static cairo_surface_t *gdk_win32_ref_cairo_surface (GdkDrawable *drawable);
120 static void gdk_win32_set_colormap (GdkDrawable *drawable,
121 GdkColormap *colormap);
123 static GdkColormap* gdk_win32_get_colormap (GdkDrawable *drawable);
125 static gint gdk_win32_get_depth (GdkDrawable *drawable);
127 static GdkScreen * gdk_win32_get_screen (GdkDrawable *drawable);
129 static GdkVisual* gdk_win32_get_visual (GdkDrawable *drawable);
131 static void gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass);
133 static void gdk_drawable_impl_win32_finalize (GObject *object);
135 static gpointer parent_class = NULL;
136 static const cairo_user_data_key_t gdk_win32_cairo_key;
139 gdk_drawable_impl_win32_get_type (void)
141 static GType object_type = 0;
145 static const GTypeInfo object_info =
147 sizeof (GdkDrawableImplWin32Class),
148 (GBaseInitFunc) NULL,
149 (GBaseFinalizeFunc) NULL,
150 (GClassInitFunc) gdk_drawable_impl_win32_class_init,
151 NULL, /* class_finalize */
152 NULL, /* class_data */
153 sizeof (GdkDrawableImplWin32),
155 (GInstanceInitFunc) NULL,
158 object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
159 "GdkDrawableImplWin32",
167 gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass)
169 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
170 GObjectClass *object_class = G_OBJECT_CLASS (klass);
172 parent_class = g_type_class_peek_parent (klass);
174 object_class->finalize = gdk_drawable_impl_win32_finalize;
176 drawable_class->create_gc = _gdk_win32_gc_new;
177 drawable_class->draw_rectangle = gdk_win32_draw_rectangle;
178 drawable_class->draw_arc = gdk_win32_draw_arc;
179 drawable_class->draw_polygon = gdk_win32_draw_polygon;
180 drawable_class->draw_text = gdk_win32_draw_text;
181 drawable_class->draw_text_wc = gdk_win32_draw_text_wc;
182 drawable_class->draw_drawable = gdk_win32_draw_drawable;
183 drawable_class->draw_points = gdk_win32_draw_points;
184 drawable_class->draw_segments = gdk_win32_draw_segments;
185 drawable_class->draw_lines = gdk_win32_draw_lines;
186 drawable_class->draw_image = gdk_win32_draw_image;
188 drawable_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
190 drawable_class->set_colormap = gdk_win32_set_colormap;
191 drawable_class->get_colormap = gdk_win32_get_colormap;
193 drawable_class->get_depth = gdk_win32_get_depth;
194 drawable_class->get_screen = gdk_win32_get_screen;
195 drawable_class->get_visual = gdk_win32_get_visual;
197 drawable_class->_copy_to_image = _gdk_win32_copy_to_image;
201 gdk_drawable_impl_win32_finalize (GObject *object)
203 gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
205 G_OBJECT_CLASS (parent_class)->finalize (object);
208 /*****************************************************
209 * Win32 specific implementations of generic functions *
210 *****************************************************/
213 gdk_win32_get_colormap (GdkDrawable *drawable)
215 return GDK_DRAWABLE_IMPL_WIN32 (drawable)->colormap;
219 gdk_win32_set_colormap (GdkDrawable *drawable,
220 GdkColormap *colormap)
222 GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
224 if (impl->colormap == colormap)
228 gdk_colormap_unref (impl->colormap);
229 impl->colormap = colormap;
231 gdk_colormap_ref (impl->colormap);
238 rop2_to_rop3 (int rop2)
242 /* Oh, Microsoft's silly names for binary and ternary rops. */
243 #define CASE(rop2,rop3) case R2_##rop2: return rop3
244 CASE (BLACK, BLACKNESS);
245 CASE (NOTMERGEPEN, NOTSRCERASE);
246 CASE (MASKNOTPEN, 0x00220326);
247 CASE (NOTCOPYPEN, NOTSRCCOPY);
248 CASE (MASKPENNOT, SRCERASE);
249 CASE (NOT, DSTINVERT);
250 CASE (XORPEN, SRCINVERT);
251 CASE (NOTMASKPEN, 0x007700E6);
252 CASE (MASKPEN, SRCAND);
253 CASE (NOTXORPEN, 0x00990066);
254 CASE (NOP, 0x00AA0029);
255 CASE (MERGENOTPEN, MERGEPAINT);
256 CASE (COPYPEN, SRCCOPY);
257 CASE (MERGEPENNOT, 0x00DD0228);
258 CASE (MERGEPEN, SRCPAINT);
259 CASE (WHITE, WHITENESS);
261 default: return SRCCOPY;
266 rop2_to_patblt_rop (int rop2)
270 #define CASE(rop2,patblt_rop) case R2_##rop2: return patblt_rop
271 CASE (COPYPEN, PATCOPY);
272 CASE (XORPEN, PATINVERT);
273 CASE (NOT, DSTINVERT);
274 CASE (BLACK, BLACKNESS);
275 CASE (WHITE, WHITENESS);
278 g_warning ("Unhandled rop2 in GC to be used in PatBlt: %#x", rop2);
284 align_with_dash_offset (int a, DWORD *dashes, int num_dashes, GdkGCWin32 *gcwin32)
289 * We can't simply add the dashoffset, it can be an arbitrary larger
290 * or smaller value not even between x1 and x2. It just says use the
291 * dash pattern aligned to the offset. So ensure x1 is smaller _x1
292 * and we start with the appropriate dash.
294 for (n = 0; n < num_dashes; n++)
295 len_sum += dashes[n];
296 if ( len_sum > 0 /* pathological api usage? */
297 && gcwin32->pen_dash_offset > a)
298 a -= (((gcwin32->pen_dash_offset/len_sum - a/len_sum) + 1) * len_sum);
300 a = gcwin32->pen_dash_offset;
305 /* Render a dashed line 'by hand'. Used for all dashes on Win9x (where
306 * GDI is way too limited), and for double dashes on all Windowses.
308 static inline gboolean
309 render_line_horizontal (GdkGCWin32 *gcwin32,
315 const int pen_width = MAX (gcwin32->pen_width, 1);
318 g_assert (gcwin32->pen_dashes);
320 x1 = align_with_dash_offset (x1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
322 for (n = 0; x1 < x2; n++)
324 int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
328 if (n % 2 == 0 && x1 + len > _x1)
329 if (!GDI_CALL (PatBlt, (gcwin32->hdc,
333 rop2_to_patblt_rop (gcwin32->rop2))))
336 x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
339 if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
343 if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
346 x1 += gcwin32->pen_dash_offset;
347 for (n = 0; x1 < x2; n++)
349 int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
354 if (!GDI_CALL (PatBlt, (gcwin32->hdc, x1, y - pen_width / 2,
356 rop2_to_patblt_rop (gcwin32->rop2))))
359 x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
361 if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
368 static inline gboolean
369 render_line_vertical (GdkGCWin32 *gcwin32,
375 const int pen_width = MAX (gcwin32->pen_width, 1);
378 g_assert (gcwin32->pen_dashes);
380 y1 = align_with_dash_offset (y1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
381 for (n = 0; y1 < y2; n++)
383 int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
386 if (n % 2 == 0 && y1 + len > _y1)
387 if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2,
390 rop2_to_patblt_rop (gcwin32->rop2))))
393 y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
396 if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
400 if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
403 y1 += gcwin32->pen_dash_offset;
404 for (n = 0; y1 < y2; n++)
406 int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
410 if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2, y1,
412 rop2_to_patblt_rop (gcwin32->rop2))))
415 y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
417 if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
425 draw_tiles_lowlevel (HDC dest,
439 GDK_NOTE (DRAW, g_print ("draw_tiles_lowlevel: %p %+d%+d tile=%p:%dx%d@%+d%+d %dx%d\n",
442 tile, tile_width, tile_height,
443 tile_x_origin, tile_y_origin,
446 y = tile_y_origin % tile_height;
449 while (y < dest_y + height)
451 if (y + tile_height >= dest_y)
453 x = tile_x_origin % tile_width;
456 while (x < dest_x + width)
458 if (x + tile_width >= dest_x)
460 gint src_x = MAX (0, dest_x - x);
461 gint src_y = MAX (0, dest_y - y);
463 if (!GDI_CALL (BitBlt, (dest, x + src_x, y + src_y,
464 MIN (tile_width, dest_x + width - (x + src_x)),
465 MIN (tile_height, dest_y + height - (y + src_y)),
479 draw_tiles (GdkDrawable *drawable,
490 const GdkGCValuesMask mask = GDK_GC_FOREGROUND;
491 gint tile_width, tile_height;
493 HDC dest_hdc, tile_hdc;
495 gc_copy = gdk_gc_new (tile);
496 gdk_gc_copy (gc_copy, gc);
497 dest_hdc = gdk_win32_hdc_get (drawable, gc, mask);
498 tile_hdc = gdk_win32_hdc_get (tile, gc_copy, mask);
500 gdk_drawable_get_size (tile, &tile_width, &tile_height);
502 draw_tiles_lowlevel (dest_hdc, tile_hdc, rop3,
503 dest_x, dest_y, tile_x_origin, tile_y_origin,
504 width, height, tile_width, tile_height);
506 gdk_win32_hdc_release (drawable, gc, mask);
507 gdk_win32_hdc_release (tile, gc_copy, mask);
508 gdk_gc_unref (gc_copy);
512 generic_draw (GdkDrawable *drawable,
514 GdkGCValuesMask mask,
515 void (*function) (GdkGCWin32 *, HDC, gint, gint, va_list),
516 const GdkRegion *region,
519 GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
520 GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
523 GdkFill fill_style = _gdk_gc_get_fill (gc);
525 va_start (args, region);
527 /* If tiled or stippled, draw to a temp pixmap and do blitting magic.
530 if (gcwin32->values_mask & GDK_GC_FILL &&
531 ((fill_style == GDK_TILED &&
532 gcwin32->values_mask & GDK_GC_TILE &&
533 _gdk_gc_get_tile (gc) != NULL)
535 ((fill_style == GDK_OPAQUE_STIPPLED ||
536 fill_style == GDK_STIPPLED) &&
537 gcwin32->values_mask & GDK_GC_STIPPLE &&
538 _gdk_gc_get_stipple (gc) != NULL)))
540 const GdkGCValuesMask blitting_mask = 0;
541 GdkGCValuesMask drawing_mask = GDK_GC_FOREGROUND;
542 gint ts_x_origin = 0, ts_y_origin = 0;
544 gint width = region->extents.x2 - region->extents.x1;
545 gint height = region->extents.y2 - region->extents.y1;
547 GdkPixmap *mask_pixmap =
548 gdk_pixmap_new (drawable, width, height, 1);
549 GdkPixmap *tile_pixmap =
550 gdk_pixmap_new (drawable, width, height, -1);
551 GdkPixmap *stipple_bitmap = NULL;
554 GdkGC *mask_gc = gdk_gc_new (mask_pixmap);
555 GdkGC *tile_gc = gdk_gc_new (tile_pixmap);
560 HGDIOBJ old_mask_hbm;
561 HGDIOBJ old_tile_hbm;
563 GdkGCValues gcvalues;
565 hdc = gdk_win32_hdc_get (drawable, gc, blitting_mask);
566 tile_hdc = CreateCompatibleDC (hdc);
568 if (gcwin32->values_mask & GDK_GC_TS_X_ORIGIN)
569 ts_x_origin = gc->ts_x_origin;
570 if (gcwin32->values_mask & GDK_GC_TS_Y_ORIGIN)
571 ts_y_origin = gc->ts_y_origin;
573 ts_x_origin -= region->extents.x1;
574 ts_y_origin -= region->extents.y1;
576 /* Fill mask bitmap with zeros */
577 gdk_gc_set_function (mask_gc, GDK_CLEAR);
578 gdk_draw_rectangle (mask_pixmap, mask_gc, TRUE,
579 0, 0, width, height);
581 /* Paint into mask bitmap, drawing ones */
582 gdk_gc_set_function (mask_gc, GDK_COPY);
584 gdk_gc_set_foreground (mask_gc, &fg);
586 /* If the drawing function uses line attributes, set them as in
589 if (mask & LINE_ATTRIBUTES)
591 gdk_gc_get_values (gc, &gcvalues);
592 if (gcvalues.line_width != 0 ||
593 gcvalues.line_style != GDK_LINE_SOLID ||
594 gcvalues.cap_style != GDK_CAP_BUTT ||
595 gcvalues.join_style != GDK_JOIN_MITER)
596 gdk_gc_set_line_attributes (mask_gc,
600 gcvalues.join_style);
601 drawing_mask |= LINE_ATTRIBUTES;
604 /* Ditto, if the drawing function draws text, set up for that. */
605 if (mask & GDK_GC_FONT)
606 drawing_mask |= GDK_GC_FONT;
608 mask_hdc = gdk_win32_hdc_get (mask_pixmap, mask_gc, drawing_mask);
609 (*function) (GDK_GC_WIN32 (mask_gc), mask_hdc,
610 region->extents.x1, region->extents.y1, args);
611 gdk_win32_hdc_release (mask_pixmap, mask_gc, drawing_mask);
613 if (fill_style == GDK_TILED)
615 /* Tile pixmap with tile */
616 draw_tiles (tile_pixmap, tile_gc, SRCCOPY,
617 _gdk_gc_get_tile (gc),
618 0, 0, ts_x_origin, ts_y_origin,
623 /* Tile with stipple */
626 stipple_bitmap = gdk_pixmap_new (NULL, width, height, 1);
627 stipple_gc = gdk_gc_new (stipple_bitmap);
629 /* Tile stipple bitmap */
630 draw_tiles (stipple_bitmap, stipple_gc, SRCCOPY,
631 _gdk_gc_get_stipple (gc),
632 0, 0, ts_x_origin, ts_y_origin,
635 if (fill_style == GDK_OPAQUE_STIPPLED)
637 /* Fill tile pixmap with background */
638 fg.pixel = _gdk_gc_get_bg_pixel (gc);
639 gdk_gc_set_foreground (tile_gc, &fg);
640 gdk_draw_rectangle (tile_pixmap, tile_gc, TRUE,
641 0, 0, width, height);
643 gdk_gc_unref (stipple_gc);
646 gdk_gc_unref (mask_gc);
647 gdk_gc_unref (tile_gc);
649 mask_hdc = CreateCompatibleDC (hdc);
651 if ((old_mask_hbm = SelectObject (mask_hdc, GDK_PIXMAP_HBITMAP (mask_pixmap))) == NULL)
652 WIN32_GDI_FAILED ("SelectObject");
654 if ((old_tile_hbm = SelectObject (tile_hdc, GDK_PIXMAP_HBITMAP (tile_pixmap))) == NULL)
655 WIN32_GDI_FAILED ("SelectObject");
657 if (fill_style == GDK_STIPPLED ||
658 fill_style == GDK_OPAQUE_STIPPLED)
661 HGDIOBJ old_stipple_hbm;
663 HGDIOBJ old_tile_brush;
665 if ((stipple_hdc = CreateCompatibleDC (hdc)) == NULL)
666 WIN32_GDI_FAILED ("CreateCompatibleDC");
668 if ((old_stipple_hbm =
669 SelectObject (stipple_hdc,
670 GDK_PIXMAP_HBITMAP (stipple_bitmap))) == NULL)
671 WIN32_GDI_FAILED ("SelectObject");
673 if ((fg_brush = CreateSolidBrush
674 (_gdk_win32_colormap_color (impl->colormap,
675 _gdk_gc_get_fg_pixel (gc)))) == NULL)
676 WIN32_GDI_FAILED ("CreateSolidBrush");
678 if ((old_tile_brush = SelectObject (tile_hdc, fg_brush)) == NULL)
679 WIN32_GDI_FAILED ("SelectObject");
681 /* Paint tile with foreround where stipple is one
683 * Desired ternary ROP: (P=foreground, S=stipple, D=destination)
694 * Reading bottom-up: 11100010 = 0xE2. PSDK docs say this is
695 * known as DSPDxax, with hex value 0x00E20746.
697 GDI_CALL (BitBlt, (tile_hdc, 0, 0, width, height,
698 stipple_hdc, 0, 0, ROP3_DSPDxax));
700 if (fill_style == GDK_STIPPLED)
702 /* Punch holes in mask where stipple is zero */
703 GDI_CALL (BitBlt, (mask_hdc, 0, 0, width, height,
704 stipple_hdc, 0, 0, SRCAND));
707 GDI_CALL (SelectObject, (tile_hdc, old_tile_brush));
708 GDI_CALL (DeleteObject, (fg_brush));
709 GDI_CALL (SelectObject, (stipple_hdc, old_stipple_hbm));
710 GDI_CALL (DeleteDC, (stipple_hdc));
711 g_object_unref (stipple_bitmap);
714 /* Tile pixmap now contains the pattern that we should paint in
715 * the areas where mask is one. (It is filled with said pattern.)
718 GDI_CALL (MaskBlt, (hdc, region->extents.x1, region->extents.y1,
721 GDK_PIXMAP_HBITMAP (mask_pixmap), 0, 0,
722 MAKEROP4 (rop2_to_rop3 (gcwin32->rop2), ROP3_D)));
725 GDI_CALL (SelectObject, (mask_hdc, old_mask_hbm));
726 GDI_CALL (SelectObject, (tile_hdc, old_tile_hbm));
727 GDI_CALL (DeleteDC, (mask_hdc));
728 GDI_CALL (DeleteDC, (tile_hdc));
729 g_object_unref (mask_pixmap);
730 g_object_unref (tile_pixmap);
732 gdk_win32_hdc_release (drawable, gc, blitting_mask);
736 hdc = gdk_win32_hdc_get (drawable, gc, mask);
737 (*function) (gcwin32, hdc, 0, 0, args);
738 gdk_win32_hdc_release (drawable, gc, mask);
744 widen_bounds (GdkRectangle *bounds,
750 bounds->x -= pen_width;
751 bounds->y -= pen_width;
752 bounds->width += 2 * pen_width;
753 bounds->height += 2 * pen_width;
755 return gdk_region_rectangle (bounds);
759 draw_rectangle (GdkGCWin32 *gcwin32,
765 HGDIOBJ old_pen_or_brush;
772 filled = va_arg (args, gboolean);
773 x = va_arg (args, gint);
774 y = va_arg (args, gint);
775 width = va_arg (args, gint);
776 height = va_arg (args, gint);
781 if (!filled && MUST_RENDER_DASHES_MANUALLY (gcwin32))
783 render_line_vertical (gcwin32, x, y, y+height+1) &&
784 render_line_horizontal (gcwin32, x, x+width+1, y) &&
785 render_line_vertical (gcwin32, x+width+1, y, y+height+1) &&
786 render_line_horizontal (gcwin32, x, x+width+1, y+height+1);
791 old_pen_or_brush = SelectObject (hdc, GetStockObject (NULL_PEN));
793 old_pen_or_brush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
794 if (old_pen_or_brush == NULL)
795 WIN32_GDI_FAILED ("SelectObject");
797 GDI_CALL (Rectangle, (hdc, x, y, x+width+1, y+height+1));
799 if (old_pen_or_brush != NULL)
800 GDI_CALL (SelectObject, (hdc, old_pen_or_brush));
805 gdk_win32_draw_rectangle (GdkDrawable *drawable,
816 GDK_NOTE (DRAW, g_print ("gdk_win32_draw_rectangle: %s (%p) %s%dx%d@%+d%+d\n",
817 _gdk_win32_drawable_description (drawable),
819 (filled ? "fill " : ""),
820 width, height, x, y));
824 bounds.width = width;
825 bounds.height = height;
826 region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
828 generic_draw (drawable, gc,
829 GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
830 (filled ? 0 : LINE_ATTRIBUTES),
831 draw_rectangle, region, filled, x, y, width, height);
833 gdk_region_destroy (region);
837 draw_arc (GdkGCWin32 *gcwin32,
848 int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
850 filled = va_arg (args, gboolean);
851 x = va_arg (args, gint);
852 y = va_arg (args, gint);
853 width = va_arg (args, gint);
854 height = va_arg (args, gint);
855 angle1 = va_arg (args, gint);
856 angle2 = va_arg (args, gint);
861 if (angle2 >= 360*64)
863 nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
867 nXStartArc = x + width/2 + width * cos(angle1/64.*2.*G_PI/360.);
868 nYStartArc = y + height/2 + -height * sin(angle1/64.*2.*G_PI/360.);
869 nXEndArc = x + width/2 + width * cos((angle1+angle2)/64.*2.*G_PI/360.);
870 nYEndArc = y + height/2 + -height * sin((angle1+angle2)/64.*2.*G_PI/360.);
874 nXEndArc = x + width/2 + width * cos(angle1/64.*2.*G_PI/360.);
875 nYEndArc = y + height/2 + -height * sin(angle1/64.*2.*G_PI/360.);
876 nXStartArc = x + width/2 + width * cos((angle1+angle2)/64.*2.*G_PI/360.);
877 nYStartArc = y + height/2 + -height * sin((angle1+angle2)/64.*2.*G_PI/360.);
882 old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
883 GDK_NOTE (DRAW, g_print ("... Pie(%p,%d,%d,%d,%d,%d,%d,%d,%d)\n",
884 hdc, x, y, x+width, y+height,
885 nXStartArc, nYStartArc, nXEndArc, nYEndArc));
886 GDI_CALL (Pie, (hdc, x, y, x+width, y+height,
887 nXStartArc, nYStartArc, nXEndArc, nYEndArc));
888 GDI_CALL (SelectObject, (hdc, old_pen));
892 GDK_NOTE (DRAW, g_print ("... Arc(%p,%d,%d,%d,%d,%d,%d,%d,%d)\n",
893 hdc, x, y, x+width, y+height,
894 nXStartArc, nYStartArc, nXEndArc, nYEndArc));
895 GDI_CALL (Arc, (hdc, x, y, x+width, y+height,
896 nXStartArc, nYStartArc, nXEndArc, nYEndArc));
901 gdk_win32_draw_arc (GdkDrawable *drawable,
914 GDK_NOTE (DRAW, g_print ("gdk_win32_draw_arc: %s %d,%d,%d,%d %d %d\n",
915 _gdk_win32_drawable_description (drawable),
916 x, y, width, height, angle1, angle2));
918 if (width <= 2 || height <= 2 || angle2 == 0)
923 bounds.width = width;
924 bounds.height = height;
925 region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
927 generic_draw (drawable, gc,
928 GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
929 draw_arc, region, filled, x, y, width, height, angle1, angle2);
931 gdk_region_destroy (region);
935 draw_polygon (GdkGCWin32 *gcwin32,
943 HGDIOBJ old_pen_or_brush;
947 filled = va_arg (args, gboolean);
948 pts = va_arg (args, POINT *);
949 npoints = va_arg (args, gint);
951 if (x_offset != 0 || y_offset != 0)
952 for (i = 0; i < npoints; i++)
954 pts[i].x -= x_offset;
955 pts[i].y -= y_offset;
959 old_pen_or_brush = SelectObject (hdc, GetStockObject (NULL_PEN));
961 old_pen_or_brush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
962 if (old_pen_or_brush == NULL)
963 WIN32_GDI_FAILED ("SelectObject");
964 GDI_CALL (Polygon, (hdc, pts, npoints));
965 if (old_pen_or_brush != NULL)
966 GDI_CALL (SelectObject, (hdc, old_pen_or_brush));
970 gdk_win32_draw_polygon (GdkDrawable *drawable,
981 GDK_NOTE (DRAW, g_print ("gdk_win32_draw_polygon: %s %d points\n",
982 _gdk_win32_drawable_description (drawable),
993 pts = g_new (POINT, npoints);
995 for (i = 0; i < npoints; i++)
997 bounds.x = MIN (bounds.x, points[i].x);
998 bounds.y = MIN (bounds.y, points[i].y);
999 pts[i].x = points[i].x;
1000 pts[i].y = points[i].y;
1003 for (i = 0; i < npoints; i++)
1005 bounds.width = MAX (bounds.width, points[i].x - bounds.x);
1006 bounds.height = MAX (bounds.height, points[i].y - bounds.y);
1009 region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1011 generic_draw (drawable, gc,
1012 GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
1013 draw_polygon, region, filled, pts, npoints);
1015 gdk_region_destroy (region);
1023 } gdk_draw_text_arg;
1026 gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
1027 const wchar_t *wcstr,
1033 gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg;
1038 if ((oldfont = SelectObject (argp->hdc, singlefont->hfont)) == NULL)
1040 WIN32_GDI_FAILED ("SelectObject");
1044 if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
1045 WIN32_GDI_FAILED ("TextOutW");
1046 GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size);
1049 SelectObject (argp->hdc, oldfont);
1053 gdk_win32_draw_text (GdkDrawable *drawable,
1061 const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
1064 gdk_draw_text_arg arg;
1066 if (text_length == 0)
1069 g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1073 arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
1075 GDK_NOTE (DRAW, g_print ("gdk_win32_draw_text: %s (%d,%d) \"%.*s\" (len %d)\n",
1076 _gdk_win32_drawable_description (drawable),
1078 (text_length > 10 ? 10 : text_length),
1079 text, text_length));
1081 if (text_length == 1)
1083 /* For single characters, don't try to interpret as UTF-8. */
1084 wc = (guchar) text[0];
1085 _gdk_wchar_text_handle (font, &wc, 1, gdk_draw_text_handler, &arg);
1089 wcstr = g_utf8_to_utf16 (text, text_length, NULL, &wlen, NULL);
1090 _gdk_wchar_text_handle (font, wcstr, wlen, gdk_draw_text_handler, &arg);
1094 gdk_win32_hdc_release (drawable, gc, mask);
1098 gdk_win32_draw_text_wc (GdkDrawable *drawable,
1103 const GdkWChar *text,
1106 const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
1109 gdk_draw_text_arg arg;
1111 if (text_length == 0)
1114 g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1118 arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
1120 GDK_NOTE (DRAW, g_print ("gdk_win32_draw_text_wc: %s (%d,%d) len: %d\n",
1121 _gdk_win32_drawable_description (drawable),
1122 x, y, text_length));
1124 if (sizeof (wchar_t) != sizeof (GdkWChar))
1126 wcstr = g_new (wchar_t, text_length);
1127 for (i = 0; i < text_length; i++)
1131 wcstr = (wchar_t *) text;
1133 _gdk_wchar_text_handle (font, wcstr, text_length,
1134 gdk_draw_text_handler, &arg);
1136 if (sizeof (wchar_t) != sizeof (GdkWChar))
1139 gdk_win32_hdc_release (drawable, gc, mask);
1143 gdk_win32_draw_drawable (GdkDrawable *drawable,
1153 g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
1155 _gdk_win32_blit (FALSE, (GdkDrawableImplWin32 *) drawable,
1156 gc, src, xsrc, ysrc,
1157 xdest, ydest, width, height);
1161 gdk_win32_draw_points (GdkDrawable *drawable,
1170 hdc = gdk_win32_hdc_get (drawable, gc, GDK_GC_FOREGROUND);
1172 GDK_NOTE (DRAW, g_print ("gdk_win32_draw_points: %s %d points\n",
1173 _gdk_win32_drawable_description (drawable),
1176 /* The X11 version uses XDrawPoint(), which doesn't use the fill
1177 * mode, so don't use generic_draw. But we should use the current
1178 * function, so we can't use SetPixel(). Draw single-pixel
1179 * rectangles (sigh).
1182 old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
1183 for (i = 0; i < npoints; i++)
1184 Rectangle (hdc, points[i].x, points[i].y,
1185 points[i].x + 2, points[i].y + 2);
1187 SelectObject (hdc, old_pen);
1188 gdk_win32_hdc_release (drawable, gc, GDK_GC_FOREGROUND);
1192 draw_segments (GdkGCWin32 *gcwin32,
1202 segs = va_arg (args, GdkSegment *);
1203 nsegs = va_arg (args, gint);
1205 if (x_offset != 0 || y_offset != 0)
1207 /* must not modify in place, but could splice in the offset all below */
1208 segs = g_memdup (segs, nsegs * sizeof (GdkSegment));
1209 for (i = 0; i < nsegs; i++)
1211 segs[i].x1 -= x_offset;
1212 segs[i].y1 -= y_offset;
1213 segs[i].x2 -= x_offset;
1214 segs[i].y2 -= y_offset;
1218 if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
1220 for (i = 0; i < nsegs; i++)
1222 if (segs[i].x1 == segs[i].x2)
1226 if (segs[i].y1 <= segs[i].y2)
1227 y1 = segs[i].y1, y2 = segs[i].y2;
1229 y1 = segs[i].y2, y2 = segs[i].y1;
1231 render_line_vertical (gcwin32, segs[i].x1, y1, y2);
1233 else if (segs[i].y1 == segs[i].y2)
1237 if (segs[i].x1 <= segs[i].x2)
1238 x1 = segs[i].x1, x2 = segs[i].x2;
1240 x1 = segs[i].x2, x2 = segs[i].x1;
1242 render_line_horizontal (gcwin32, x1, x2, segs[i].y1);
1245 GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
1246 GDI_CALL (LineTo, (hdc, segs[i].x2, segs[i].y2));
1251 for (i = 0; i < nsegs; i++)
1253 const GdkSegment *ps = &segs[i];
1254 const int x1 = ps->x1, y1 = ps->y1;
1255 int x2 = ps->x2, y2 = ps->y2;
1257 GDK_NOTE (DRAW, g_print (" +%d+%d..+%d+%d", x1, y1, x2, y2));
1258 GDI_CALL (MoveToEx, (hdc, x1, y1, NULL)) &&
1259 GDI_CALL (LineTo, (hdc, x2, y2));
1262 GDK_NOTE (DRAW, g_print ("\n"));
1264 if (x_offset != 0 || y_offset != 0)
1269 gdk_win32_draw_segments (GdkDrawable *drawable,
1274 GdkRectangle bounds;
1278 GDK_NOTE (DRAW, g_print ("gdk_win32_draw_segments: %s %d segs\n",
1279 _gdk_win32_drawable_description (drawable),
1282 bounds.x = G_MAXINT;
1283 bounds.y = G_MAXINT;
1287 for (i = 0; i < nsegs; i++)
1289 bounds.x = MIN (bounds.x, segs[i].x1);
1290 bounds.x = MIN (bounds.x, segs[i].x2);
1291 bounds.y = MIN (bounds.y, segs[i].y1);
1292 bounds.y = MIN (bounds.y, segs[i].y2);
1295 for (i = 0; i < nsegs; i++)
1297 bounds.width = MAX (bounds.width, segs[i].x1 - bounds.x);
1298 bounds.width = MAX (bounds.width, segs[i].x2 - bounds.x);
1299 bounds.height = MAX (bounds.height, segs[i].y1 - bounds.y);
1300 bounds.height = MAX (bounds.height, segs[i].y2 - bounds.y);
1303 region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1305 generic_draw (drawable, gc, GDK_GC_FOREGROUND | LINE_ATTRIBUTES,
1306 draw_segments, region, segs, nsegs);
1308 gdk_region_destroy (region);
1312 draw_lines (GdkGCWin32 *gcwin32,
1322 pts = va_arg (args, POINT *);
1323 npoints = va_arg (args, gint);
1325 if (x_offset != 0 || y_offset != 0)
1326 for (i = 0; i < npoints; i++)
1328 pts[i].x -= x_offset;
1329 pts[i].y -= y_offset;
1332 if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
1334 for (i = 0; i < npoints - 1; i++)
1336 if (pts[i].x == pts[i+1].x)
1339 if (pts[i].y > pts[i+1].y)
1340 y1 = pts[i+1].y, y2 = pts[i].y;
1342 y1 = pts[i].y, y2 = pts[i+1].y;
1344 render_line_vertical (gcwin32, pts[i].x, y1, y2);
1346 else if (pts[i].y == pts[i+1].y)
1349 if (pts[i].x > pts[i+1].x)
1350 x1 = pts[i+1].x, x2 = pts[i].x;
1352 x1 = pts[i].x, x2 = pts[i+1].x;
1354 render_line_horizontal (gcwin32, x1, x2, pts[i].y);
1357 GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
1358 GDI_CALL (LineTo, (hdc, pts[i+1].x, pts[i+1].y));
1362 GDI_CALL (Polyline, (hdc, pts, npoints));
1366 gdk_win32_draw_lines (GdkDrawable *drawable,
1371 GdkRectangle bounds;
1376 GDK_NOTE (DRAW, g_print ("gdk_win32_draw_lines: %s %d points\n",
1377 _gdk_win32_drawable_description (drawable),
1383 bounds.x = G_MAXINT;
1384 bounds.y = G_MAXINT;
1388 pts = g_new (POINT, npoints);
1390 for (i = 0; i < npoints; i++)
1392 bounds.x = MIN (bounds.x, points[i].x);
1393 bounds.y = MIN (bounds.y, points[i].y);
1394 pts[i].x = points[i].x;
1395 pts[i].y = points[i].y;
1398 for (i = 0; i < npoints; i++)
1400 bounds.width = MAX (bounds.width, points[i].x - bounds.x);
1401 bounds.height = MAX (bounds.height, points[i].y - bounds.y);
1404 region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
1406 generic_draw (drawable, gc, GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
1408 draw_lines, region, pts, npoints);
1410 gdk_region_destroy (region);
1415 blit_from_pixmap (gboolean use_fg_bg,
1416 GdkDrawableImplWin32 *dest,
1418 GdkPixmapImplWin32 *src,
1427 GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
1430 RGBQUAD oldtable[256], newtable[256];
1433 gint newtable_size = 0, oldtable_size = 0;
1436 GDK_NOTE (DRAW, g_print ("blit_from_pixmap\n"));
1438 srcdc = _gdk_win32_drawable_acquire_dc (GDK_DRAWABLE (src));
1442 if (!(holdbitmap = SelectObject (srcdc, ((GdkDrawableImplWin32 *) src)->handle)))
1443 WIN32_GDI_FAILED ("SelectObject");
1446 if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth <= 8)
1448 /* Blitting from a 1, 4 or 8-bit pixmap */
1450 if ((oldtable_size = GetDIBColorTable (srcdc, 0, 256, oldtable)) == 0)
1451 WIN32_GDI_FAILED ("GetDIBColorTable");
1452 else if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth == 1)
1454 /* Blitting from an 1-bit pixmap */
1460 bgix = _gdk_gc_get_bg_pixel (gc);
1461 fgix = _gdk_gc_get_fg_pixel (gc);
1469 if (GDK_IS_PIXMAP_IMPL_WIN32 (dest) &&
1470 GDK_PIXMAP_OBJECT (dest->wrapper)->depth <= 8)
1472 /* Destination is also pixmap, get fg and bg from
1473 * its palette. Either use the foreground and
1474 * background pixel values in the GC (only in the
1475 * case of gdk_image_put(), cf. XPutImage()), or 0
1476 * and 1 to index the palette.
1478 if (!GDI_CALL (GetDIBColorTable, (hdc, bgix, 1, newtable)) ||
1479 !GDI_CALL (GetDIBColorTable, (hdc, fgix, 1, newtable+1)))
1484 /* Destination is a window, get fg and bg from its
1488 bg = _gdk_win32_colormap_color (dest->colormap, bgix);
1489 fg = _gdk_win32_colormap_color (dest->colormap, fgix);
1490 newtable[0].rgbBlue = GetBValue (bg);
1491 newtable[0].rgbGreen = GetGValue (bg);
1492 newtable[0].rgbRed = GetRValue (bg);
1493 newtable[0].rgbReserved = 0;
1494 newtable[1].rgbBlue = GetBValue (fg);
1495 newtable[1].rgbGreen = GetGValue (fg);
1496 newtable[1].rgbRed = GetRValue (fg);
1497 newtable[1].rgbReserved = 0;
1500 GDK_NOTE (DRAW, g_print ("bg: %02x %02x %02x "
1501 "fg: %02x %02x %02x\n",
1503 newtable[0].rgbGreen,
1504 newtable[0].rgbBlue,
1506 newtable[1].rgbGreen,
1507 newtable[1].rgbBlue));
1510 else if (GDK_IS_PIXMAP_IMPL_WIN32 (dest))
1512 /* Destination is pixmap, get its color table */
1514 if ((newtable_size = GetDIBColorTable (hdc, 0, 256, newtable)) == 0)
1515 WIN32_GDI_FAILED ("GetDIBColorTable"), ok = FALSE;
1518 /* If blitting between pixmaps, set source's color table */
1519 if (ok && newtable_size > 0)
1521 GDK_NOTE (MISC_OR_COLORMAP,
1522 g_print ("blit_from_pixmap: set color table"
1523 " hdc=%p count=%d\n",
1524 srcdc, newtable_size));
1525 if (!GDI_CALL (SetDIBColorTable, (srcdc, 0, newtable_size, newtable)))
1531 if (!BitBlt (hdc, xdest, ydest, width, height,
1532 srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)) &&
1533 GetLastError () != ERROR_INVALID_HANDLE)
1534 WIN32_GDI_FAILED ("BitBlt");
1536 /* Restore source's color table if necessary */
1537 if (ok && newtable_size > 0 && oldtable_size > 0)
1539 GDK_NOTE (MISC_OR_COLORMAP,
1540 g_print ("blit_from_pixmap: reset color table"
1541 " hdc=%p count=%d\n",
1542 srcdc, oldtable_size));
1543 GDI_CALL (SetDIBColorTable, (srcdc, 0, oldtable_size, oldtable));
1546 GDI_CALL (SelectObject, (srcdc, holdbitmap));
1549 _gdk_win32_drawable_release_dc (GDK_DRAWABLE (src));
1553 blit_inside_drawable (HDC hdc,
1554 GdkGCWin32 *gcwin32,
1563 GDK_NOTE (DRAW, g_print ("blit_inside_drawable\n"));
1565 GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1566 hdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1570 blit_from_window (HDC hdc,
1571 GdkGCWin32 *gcwin32,
1572 GdkDrawableImplWin32 *src,
1581 HPALETTE holdpal = NULL;
1582 GdkColormap *cmap = gdk_colormap_get_system ();
1584 GDK_NOTE (DRAW, g_print ("blit_from_window\n"));
1586 if ((srcdc = GetDC (src->handle)) == NULL)
1588 WIN32_GDI_FAILED ("GetDC");
1592 if (cmap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
1593 cmap->visual->type == GDK_VISUAL_STATIC_COLOR)
1597 if (!(holdpal = SelectPalette (srcdc, GDK_WIN32_COLORMAP_DATA (cmap)->hpal, FALSE)))
1598 WIN32_GDI_FAILED ("SelectPalette");
1599 else if ((k = RealizePalette (srcdc)) == GDI_ERROR)
1600 WIN32_GDI_FAILED ("RealizePalette");
1602 GDK_NOTE (MISC_OR_COLORMAP,
1603 g_print ("blit_from_window: realized %d\n", k));
1606 GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
1607 srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
1609 if (holdpal != NULL)
1610 GDI_CALL (SelectPalette, (srcdc, holdpal, FALSE));
1612 GDI_CALL (ReleaseDC, (src->handle, srcdc));
1616 _gdk_win32_blit (gboolean use_fg_bg,
1617 GdkDrawableImplWin32 *draw_impl,
1628 HRGN src_rgn, draw_rgn, outside_rgn;
1630 GdkDrawableImplWin32 *src_impl = NULL;
1631 gint src_width, src_height;
1633 GDK_NOTE (DRAW, g_print ("_gdk_win32_blit: src:%s %dx%d@%+d%+d\n"
1634 " dst:%s @%+d%+d use_fg_bg=%d\n",
1635 _gdk_win32_drawable_description (src),
1636 width, height, xsrc, ysrc,
1637 _gdk_win32_drawable_description (&draw_impl->parent_instance),
1641 /* If blitting from the root window, take the multi-monitor offset
1644 if (src == ((GdkWindowObject *)_gdk_root)->impl)
1646 GDK_NOTE (DRAW, g_print ("... offsetting src coords\n"));
1647 xsrc -= _gdk_offset_x;
1648 ysrc -= _gdk_offset_y;
1651 if (GDK_IS_DRAWABLE_IMPL_WIN32 (src))
1652 src_impl = (GdkDrawableImplWin32 *) src;
1653 else if (GDK_IS_WINDOW (src))
1654 src_impl = (GdkDrawableImplWin32 *) GDK_WINDOW_OBJECT (src)->impl;
1655 else if (GDK_IS_PIXMAP (src))
1656 src_impl = (GdkDrawableImplWin32 *) GDK_PIXMAP_OBJECT (src)->impl;
1658 g_assert_not_reached ();
1660 hdc = gdk_win32_hdc_get (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
1662 gdk_drawable_get_size (src, &src_width, &src_height);
1664 if ((src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1)) == NULL)
1665 WIN32_GDI_FAILED ("CreateRectRgn");
1666 else if ((draw_rgn = CreateRectRgn (xsrc, ysrc,
1668 ysrc + height + 1)) == NULL)
1669 WIN32_GDI_FAILED ("CreateRectRgn");
1672 if (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl))
1676 /* If we are drawing on a window, calculate the region that is
1677 * outside the source pixmap, and invalidate that, causing it to
1678 * be cleared. Not completely sure whether this is always needed. XXX
1681 outside_rgn = CreateRectRgnIndirect (&r);
1683 if ((comb = CombineRgn (outside_rgn,
1685 RGN_DIFF)) == ERROR)
1686 WIN32_GDI_FAILED ("CombineRgn");
1687 else if (comb != NULLREGION)
1689 OffsetRgn (outside_rgn, xdest, ydest);
1690 GDK_NOTE (DRAW, (GetRgnBox (outside_rgn, &r),
1691 g_print ("... InvalidateRgn "
1692 "bbox: %ldx%ld@%+ld%+ld\n",
1693 r.right - r.left - 1, r.bottom - r.top - 1,
1695 InvalidateRgn (draw_impl->handle, outside_rgn, TRUE);
1697 GDI_CALL (DeleteObject, (outside_rgn));
1700 #if 1 /* Don't know if this is necessary XXX */
1701 if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
1702 g_warning ("gdk_win32_blit: CombineRgn returned a COMPLEXREGION");
1704 GetRgnBox (draw_rgn, &r);
1705 if (r.left != xsrc || r.top != ysrc ||
1706 r.right != xsrc + width + 1 || r.bottom != ysrc + height + 1)
1708 xdest += r.left - xsrc;
1710 ydest += r.top - ysrc;
1712 width = r.right - xsrc - 1;
1713 height = r.bottom - ysrc - 1;
1715 GDK_NOTE (DRAW, g_print ("... restricted to src: %dx%d@%+d%+d, "
1717 width, height, xsrc, ysrc,
1722 GDI_CALL (DeleteObject, (src_rgn));
1723 GDI_CALL (DeleteObject, (draw_rgn));
1726 if (draw_impl->handle == src_impl->handle)
1727 blit_inside_drawable (hdc, GDK_GC_WIN32 (gc), xsrc, ysrc, xdest, ydest, width, height);
1728 else if (GDK_IS_PIXMAP_IMPL_WIN32 (src_impl))
1729 blit_from_pixmap (use_fg_bg, draw_impl, hdc,
1730 (GdkPixmapImplWin32 *) src_impl, gc,
1731 xsrc, ysrc, xdest, ydest, width, height);
1733 blit_from_window (hdc, GDK_GC_WIN32 (gc), src_impl, xsrc, ysrc, xdest, ydest, width, height);
1734 gdk_win32_hdc_release (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
1738 gdk_win32_draw_image (GdkDrawable *drawable,
1748 g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
1750 _gdk_win32_blit (TRUE, (GdkDrawableImplWin32 *) drawable,
1751 gc, (GdkPixmap *) image->windowing_data,
1752 xsrc, ysrc, xdest, ydest, width, height);
1756 * _gdk_win32_drawable_acquire_dc
1757 * @drawable: a Win32 #GdkDrawable implementation
1759 * Gets a DC with the given drawable selected into
1762 * Return value: The DC, on success. Otherwise
1763 * %NULL. If this function succeeded
1764 * _gdk_win32_drawable_release_dc() must be called
1765 * release the DC when you are done using it.
1768 _gdk_win32_drawable_acquire_dc (GdkDrawable *drawable)
1770 GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
1772 if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
1773 GDK_WINDOW_DESTROYED (impl->wrapper))
1778 if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
1780 impl->hdc = CreateCompatibleDC (NULL);
1782 WIN32_GDI_FAILED ("CreateCompatibleDC");
1786 impl->saved_dc_bitmap = SelectObject (impl->hdc,
1788 if (!impl->saved_dc_bitmap)
1790 WIN32_GDI_FAILED ("CreateCompatibleDC");
1791 DeleteDC (impl->hdc);
1798 impl->hdc = GetDC (impl->handle);
1800 WIN32_GDI_FAILED ("GetDC");
1814 * _gdk_win32_drawable_release_dc
1815 * @drawable: a Win32 #GdkDrawable implementation
1817 * Releases the reference count for the DC
1818 * from _gdk_win32_drawable_acquire_dc()
1821 _gdk_win32_drawable_release_dc (GdkDrawable *drawable)
1823 GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
1825 g_return_if_fail (impl->hdc_count > 0);
1828 if (impl->hdc_count == 0)
1830 if (impl->saved_dc_bitmap)
1832 GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
1833 impl->saved_dc_bitmap = NULL;
1838 if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
1839 GDI_CALL (DeleteDC, (impl->hdc));
1841 GDI_CALL (ReleaseDC, (impl->handle, impl->hdc));
1848 gdk_win32_cairo_surface_destroy (void *data)
1850 GdkDrawableImplWin32 *impl = data;
1852 _gdk_win32_drawable_release_dc (GDK_DRAWABLE (impl));
1853 impl->cairo_surface = NULL;
1856 static cairo_surface_t *
1857 gdk_win32_ref_cairo_surface (GdkDrawable *drawable)
1859 GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
1861 if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
1862 GDK_WINDOW_DESTROYED (impl->wrapper))
1865 if (!impl->cairo_surface)
1867 HDC hdc = _gdk_win32_drawable_acquire_dc (drawable);
1871 impl->cairo_surface = cairo_win32_surface_create (hdc);
1873 cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
1874 drawable, gdk_win32_cairo_surface_destroy);
1877 cairo_surface_reference (impl->cairo_surface);
1879 return impl->cairo_surface;
1883 gdk_win32_get_depth (GdkDrawable *drawable)
1885 /* This is a bit bogus but I'm not sure the other way is better */
1887 return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1891 gdk_win32_get_screen (GdkDrawable *drawable)
1893 return gdk_screen_get_default ();
1897 gdk_win32_get_visual (GdkDrawable *drawable)
1899 return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
1903 gdk_win32_drawable_get_handle (GdkDrawable *drawable)
1905 return GDK_DRAWABLE_HANDLE (drawable);
1909 * _gdk_win32_drawable_finish
1910 * @drawable: a Win32 #GdkDrawable implementation
1912 * Releases any resources allocated internally for the drawable.
1913 * This is called when the drawable becomes unusable
1914 * (gdk_window_destroy() for a window, or the refcount going to
1915 * zero for a pixmap.)
1918 _gdk_win32_drawable_finish (GdkDrawable *drawable)
1920 GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
1922 if (impl->cairo_surface)
1924 cairo_surface_finish (impl->cairo_surface);
1925 cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
1929 g_assert (impl->hdc_count == 0);