From 0f133f4f4b41901d3ef22b25373aa2192e99601f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 21 Jun 2005 04:09:52 +0000 Subject: [PATCH] New function which can be used to implement scrolling in non-window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2005-06-21 Matthias Clasen * gdk/gdk.symbols: * gdk/gdkwindow.h: * gdk/x11/gdkgeometry-x11.c (gdk_window_move_region): New function which can be used to implement scrolling in non-window widgets. (#135165, Søren Sandmann) --- ChangeLog | 8 ++ ChangeLog.pre-2-10 | 8 ++ ChangeLog.pre-2-8 | 8 ++ docs/reference/ChangeLog | 4 + docs/reference/gdk/gdk-sections.txt | 1 + gdk/gdk.symbols | 1 + gdk/gdkwindow.h | 4 + gdk/x11/gdkgeometry-x11.c | 156 ++++++++++++++++++++++++++-- 8 files changed, 179 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index afd1bded1e..9b96eb41a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2005-06-21 Matthias Clasen + + * gdk/gdk.symbols: + * gdk/gdkwindow.h: + * gdk/x11/gdkgeometry-x11.c (gdk_window_move_region): New + function which can be used to implement scrolling in + non-window widgets. (#135165, Søren Sandmann) + 2005-06-20 Matthias Clasen * gtk/gtkiconcache.c: Handle MAP_FAILED. (#308449, Georg diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index afd1bded1e..9b96eb41a3 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,11 @@ +2005-06-21 Matthias Clasen + + * gdk/gdk.symbols: + * gdk/gdkwindow.h: + * gdk/x11/gdkgeometry-x11.c (gdk_window_move_region): New + function which can be used to implement scrolling in + non-window widgets. (#135165, Søren Sandmann) + 2005-06-20 Matthias Clasen * gtk/gtkiconcache.c: Handle MAP_FAILED. (#308449, Georg diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index afd1bded1e..9b96eb41a3 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,11 @@ +2005-06-21 Matthias Clasen + + * gdk/gdk.symbols: + * gdk/gdkwindow.h: + * gdk/x11/gdkgeometry-x11.c (gdk_window_move_region): New + function which can be used to implement scrolling in + non-window widgets. (#135165, Søren Sandmann) + 2005-06-20 Matthias Clasen * gtk/gtkiconcache.c: Handle MAP_FAILED. (#308449, Georg diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 2f89903b5d..5b27becfe5 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,7 @@ +2005-06-21 Matthias Clasen + + * gdk/gdk-sections.txt: Add gdk_window_move_region + 2005-06-20 Matthias Clasen * === Released 2.7.0 === diff --git a/docs/reference/gdk/gdk-sections.txt b/docs/reference/gdk/gdk-sections.txt index 36f64f15fa..6dcde195e9 100644 --- a/docs/reference/gdk/gdk-sections.txt +++ b/docs/reference/gdk/gdk-sections.txt @@ -643,6 +643,7 @@ gdk_window_move gdk_window_resize gdk_window_move_resize gdk_window_scroll +gdk_window_move_region gdk_window_reparent gdk_window_clear gdk_window_clear_area diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index 7839ece7c4..ab1159eae8 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -680,6 +680,7 @@ gdk_window_register_dnd #if IN_HEADER(__GDK_WINDOW_H__) #if IN_FILE(__GDK_GEOMETRY_X11_C__) gdk_window_scroll +gdk_window_move_region #endif #endif diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index 85ac3a537a..6c99cdc61a 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -331,6 +331,10 @@ void gdk_window_remove_filter (GdkWindow *window, void gdk_window_scroll (GdkWindow *window, gint dx, gint dy); +void gdk_window_move_region (GdkWindow *window, + GdkRegion *region, + gint dx, + gint dy); /* * This allows for making shaped (partially transparent) windows diff --git a/gdk/x11/gdkgeometry-x11.c b/gdk/x11/gdkgeometry-x11.c index f0b33c8636..4021dddeba 100644 --- a/gdk/x11/gdkgeometry-x11.c +++ b/gdk/x11/gdkgeometry-x11.c @@ -155,6 +155,7 @@ struct _GdkWindowQueueItem GdkWindowQueueType type; union { struct { + GdkRegion *area; gint dx; gint dy; } translate; @@ -183,6 +184,7 @@ static void gdk_window_premove (GdkWindow *window, static void gdk_window_postmove (GdkWindow *window, GdkWindowParentPos *parent_pos); static void gdk_window_queue_translation (GdkWindow *window, + GdkRegion *area, gint dx, gint dy); static void gdk_window_clip_changed (GdkWindow *window, @@ -231,8 +233,8 @@ gdk_window_copy_area_scroll (GdkWindow *window, gc = _gdk_drawable_get_scratch_gc (window, TRUE); - gdk_window_queue_translation (window, dx, dy); - + gdk_window_queue_translation (window, NULL, dx, dy); + XCopyArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), GDK_WINDOW_XID (window), @@ -327,7 +329,7 @@ gdk_window_guffaw_scroll (GdkWindow *window, _gdk_x11_window_tmp_unset_bg (window, FALSE);; if (dx > 0 || dy > 0) - gdk_window_queue_translation (window, MAX (dx, 0), MAX (dy, 0)); + gdk_window_queue_translation (window, NULL, MAX (dx, 0), MAX (dy, 0)); gdk_window_set_static_gravities (window, TRUE); @@ -353,7 +355,7 @@ gdk_window_guffaw_scroll (GdkWindow *window, new_position.x - d_xoffset, new_position.y - d_yoffset); if (dx < 0 || dy < 0) - gdk_window_queue_translation (window, MIN (dx, 0), MIN (dy, 0)); + gdk_window_queue_translation (window, NULL, MIN (dx, 0), MIN (dy, 0)); XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), @@ -461,6 +463,115 @@ gdk_window_scroll (GdkWindow *window, gdk_window_guffaw_scroll (window, dx, dy); } +/** + * gdk_window_move_region: + * @window: a #GdkWindow + * @region: The #GdkRegion to move + * @dx: Amount to move in the X direction + * @dy: Amount to move in the Y direction + * + * Move the part of @window indicated by @region by @dy pixels in the Y + * direction and @dx pixels in the X direction. The portions of @region + * that not covered by the new position of @region are invalidated. + * + * Child windows are not moved. + * + * Since: 2.8 + **/ +void +gdk_window_move_region (GdkWindow *window, + GdkRegion *region, + gint dx, + gint dy) +{ + GdkWindowImplX11 *impl; + GdkWindowObject *private; + GdkRegion *window_clip; + GdkRegion *src_region; + GdkRegion *brought_in; + GdkRegion *dest_region; + GdkRegion *moving_invalid_region; + GdkRectangle dest_extents; + GdkGC *gc; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (region != NULL); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + private = GDK_WINDOW_OBJECT (window); + impl = GDK_WINDOW_IMPL_X11 (private->impl); + + if (dx == 0 && dy == 0) + return; + + window_clip = gdk_region_rectangle (&impl->position_info.clip_rect); + + /* compute source regions */ + src_region = gdk_region_copy (region); + brought_in = gdk_region_copy (region); + gdk_region_intersect (src_region, window_clip); + + gdk_region_subtract (brought_in, src_region); + gdk_region_offset (brought_in, dx, dy); + + /* compute destination regions */ + dest_region = gdk_region_copy (src_region); + gdk_region_offset (dest_region, dx, dy); + gdk_region_intersect (dest_region, window_clip); + gdk_region_get_clipbox (dest_region, &dest_extents); + + gdk_region_destroy (window_clip); + + /* calculating moving part of current invalid area */ + moving_invalid_region = NULL; + if (private->update_area) + { + moving_invalid_region = gdk_region_copy (private->update_area); + gdk_region_intersect (moving_invalid_region, src_region); + gdk_region_offset (moving_invalid_region, dx, dy); + } + + /* invalidate all of the src region */ + gdk_window_invalidate_region (window, src_region, FALSE); + + /* un-invalidate destination region */ + if (private->update_area) + gdk_region_subtract (private->update_area, dest_region); + + /* invalidate moving parts of existing update area */ + if (moving_invalid_region) + { + gdk_window_invalidate_region (window, moving_invalid_region, FALSE); + gdk_region_destroy (moving_invalid_region); + } + + /* invalidate area brought in from off-screen */ + gdk_window_invalidate_region (window, brought_in, FALSE); + gdk_region_destroy (brought_in); + + /* Actually do the moving */ + gdk_window_queue_translation (window, src_region, dx, dy); + + gc = _gdk_drawable_get_scratch_gc (window, TRUE); + gdk_gc_set_clip_region (gc, dest_region); + + XCopyArea (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + GDK_WINDOW_XID (window), + GDK_GC_XGC (gc), + dest_extents.x - dx, dest_extents.y - dy, + dest_extents.width, dest_extents.height, + dest_extents.x, dest_extents.y); + + /* Unset clip region of cached GC */ + gdk_gc_set_clip_region (gc, NULL); + + gdk_region_destroy (src_region); + gdk_region_destroy (dest_region); +} + void _gdk_window_move_resize_child (GdkWindow *window, gint x, @@ -520,7 +631,7 @@ _gdk_window_move_resize_child (GdkWindow *window, gdk_window_set_static_gravities (window, TRUE); if (d_xoffset < 0 || d_yoffset < 0) - gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0)); + gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0)); compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset, &new_position); @@ -541,7 +652,7 @@ _gdk_window_move_resize_child (GdkWindow *window, new_position.x + dx, new_position.y + dy); if (d_xoffset > 0 || d_yoffset > 0) - gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0)); + gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0)); XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), @@ -797,7 +908,7 @@ gdk_window_premove (GdkWindow *window, GdkRectangle new_position; if (d_xoffset < 0 || d_yoffset < 0) - gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0)); + gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0)); compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset, &new_position); @@ -843,7 +954,7 @@ gdk_window_postmove (GdkWindow *window, if (d_xoffset != 0 || d_yoffset != 0) { if (d_xoffset > 0 || d_yoffset > 0) - gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0)); + gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0)); XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window), @@ -917,6 +1028,11 @@ queue_item_free (GdkWindowQueueItem *item) if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE) gdk_region_destroy (item->u.antiexpose.area); + else + { + if (item->u.translate.area) + gdk_region_destroy (item->u.translate.area); + } g_free (item); } @@ -990,11 +1106,13 @@ gdk_window_queue (GdkWindow *window, static void gdk_window_queue_translation (GdkWindow *window, + GdkRegion *area, gint dx, gint dy) { GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1); item->type = GDK_WINDOW_QUEUE_TRANSLATE; + item->u.translate.area = area ? gdk_region_copy (area) : NULL; item->u.translate.dx = dx; item->u.translate.dy = dy; @@ -1024,7 +1142,7 @@ _gdk_window_process_expose (GdkWindow *window, GdkRegion *clip_region; GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl); - + if (display_x11->translate_queue) { GList *tmp_list = display_x11->translate_queue->head; @@ -1039,9 +1157,25 @@ _gdk_window_process_expose (GdkWindow *window, if (item->window == window) { if (item->type == GDK_WINDOW_QUEUE_TRANSLATE) - gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy); + { + if (item->u.translate.area) + { + GdkRegion *intersection; + + intersection = gdk_region_copy (invalidate_region); + gdk_region_intersect (intersection, item->u.translate.area); + gdk_region_subtract (invalidate_region, intersection); + gdk_region_offset (intersection, item->u.translate.dx, item->u.translate.dy); + gdk_region_union (invalidate_region, intersection); + gdk_region_destroy (intersection); + } + else + gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy); + } else /* anti-expose */ - gdk_region_subtract (invalidate_region, item->u.antiexpose.area); + { + gdk_region_subtract (invalidate_region, item->u.antiexpose.area); + } } } else