added GdkRectangle *clip_rect to gtk_widget_get_snapshot().

2008-05-21 21:10:15  Tim Janik  <timj@imendio.com>

        * gtk/gtkwidget.h: added GdkRectangle *clip_rect to gtk_widget_get_snapshot().

        * gtk/gtkwidget.c: clip the returned snapshot pixmap to clip_rect.
        return snapshot pixmap coordinates widget relative in *clip_rect.

        * tests/testgtk.c: fixed bogus NULL pointer unref.


svn path=/trunk/; revision=20124
This commit is contained in:
21:10:15 Tim Janik 2008-05-21 19:15:12 +00:00 committed by Tim Janik
parent aa4ab3f037
commit b3d160ced5
4 changed files with 98 additions and 17 deletions

View File

@ -1,3 +1,12 @@
2008-05-21 21:10:15 Tim Janik <timj@imendio.com>
* gtk/gtkwidget.h: added GdkRectangle *clip_rect to gtk_widget_get_snapshot().
* gtk/gtkwidget.c: clip the returned snapshot pixmap to clip_rect.
return snapshot pixmap coordinates widget relative in *clip_rect.
* tests/testgtk.c: fixed bogus NULL pointer unref.
2008-05-21 21:04:28 Tim Janik <timj@imendio.com> 2008-05-21 21:04:28 Tim Janik <timj@imendio.com>
* gtk/gtkwidget.c gtk_widget_get_snapshot(): grow snapshot area from * gtk/gtkwidget.c gtk_widget_get_snapshot(): grow snapshot area from

View File

@ -8314,30 +8314,49 @@ gtk_widget_unref (GtkWidget *widget)
/** /**
* gtk_widget_get_snapshot: * gtk_widget_get_snapshot:
* @widget: a #GtkWidget * @widget: a #GtkWidget
* @clip_rect: a #GdkRectangle or %NULL
* *
* Creates a #GdkPixmap of the contents of the widget and its * Create a #GdkPixmap of the contents of the widget and its children.
* children. Works even if the widget is obscured. * Works even if the widget is obscured. The depth and visual of the
* Note that the depth and visual of the resulting pixmap is dependent * resulting pixmap is dependent on the widget being snapshot and likely
* on the widget being snapshot and likely differs from those of a target * differs from those of a target widget displaying the pixmap.
* widget displaying the pixmap. Use gdk_pixbuf_get_from_drawable() * The function gdk_pixbuf_get_from_drawable() can be used to convert
* to convert the pixmap to a visual independant representation. * the pixmap to a visual independant representation.
* The snapshot area used by this function is the @widget's allocation plus
* any extra space occupied by additional windows belonging to this widget
* (such as the arrows of a spin button).
* Thus, the resulting snapshot pixmap is possibly larger than the allocation.
* If @clip_rect is non NULL, the resulting pixmap is shrunken to
* match the specified clip_rect. The (x,y) coordinates of @clip_rect are
* interpreted widget relative. If width or height of @clip_rect are 0 or
* negative, the width or height of the resulting pixmap will be shrunken
* by the respective amount.
* For instance a @clip_rect <literal>{ +5, +5, -10, -10 }</literal> will
* chop off 5 pixel at each side of the snapshot pixmap.
* If non-%NULL, clip_rect will contain the exact widget relative snapshot
* coordinates upon return. A @clip_rect of <literal>{ -1, -1, 0, 0 }</literal>
* can be used to preserve the auto-grown snapshot area and use @clip_rect
* as a pure output parameter.
* The returned pixmap can be %NULL, if the resulting clip_area was empty.
* *
* Return value: #GdkPixmap of the widget * Return value: #GdkPixmap snapshot of the widget
* Since: 2.16 * Since: 2.16
**/ **/
GdkPixmap* GdkPixmap*
gtk_widget_get_snapshot (GtkWidget *widget) gtk_widget_get_snapshot (GtkWidget *widget,
GdkRectangle *clip_rect)
{ {
int x, y, width, height; int x, y, width, height;
GdkWindow *parent_window = NULL; GdkWindow *parent_window = NULL;
GdkPixmap *pixmap; GdkPixmap *pixmap;
/* the widget (and parent_window) must be realized to be drawable */
if (widget->parent && !GTK_WIDGET_REALIZED (widget->parent)) if (widget->parent && !GTK_WIDGET_REALIZED (widget->parent))
gtk_widget_realize (widget->parent); gtk_widget_realize (widget->parent);
if (!GTK_WIDGET_REALIZED (widget)) if (!GTK_WIDGET_REALIZED (widget))
gtk_widget_realize (widget); gtk_widget_realize (widget);
/* figure snapshot rectangle */ /* determine snapshot rectangle */
x = widget->allocation.x; x = widget->allocation.x;
y = widget->allocation.y; y = widget->allocation.y;
width = widget->allocation.width; width = widget->allocation.width;
@ -8345,6 +8364,7 @@ gtk_widget_get_snapshot (GtkWidget *widget)
GList *windows = NULL, *list; GList *windows = NULL, *list;
if (widget->parent && !GTK_WIDGET_NO_WINDOW (widget)) if (widget->parent && !GTK_WIDGET_NO_WINDOW (widget))
{ {
/* grow snapshot rectangle to cover all widget windows */
parent_window = gtk_widget_get_parent_window (widget); parent_window = gtk_widget_get_parent_window (widget);
for (list = gdk_window_peek_children (parent_window); list; list = list->next) for (list = gdk_window_peek_children (parent_window); list; list = list->next)
{ {
@ -8377,18 +8397,50 @@ gtk_widget_get_snapshot (GtkWidget *widget)
else if (!widget->parent) else if (!widget->parent)
x = y = 0; /* toplevel */ x = y = 0; /* toplevel */
/* at this point, (x,y,width,height) is the parent_window relative
* snapshot area covering all of widget's windows.
*/
/* shrink snapshot size by clip_rectangle */
if (clip_rect)
{
GdkRectangle snap = { x, y, width, height }, clip = *clip_rect;
clip.x = clip.x < 0 ? x : clip.x;
clip.y = clip.y < 0 ? y : clip.y;
clip.width = clip.width <= 0 ? MAX (0, width + clip.width) : clip.width;
clip.height = clip.height <= 0 ? MAX (0, height + clip.height) : clip.height;
if (widget->parent)
{
/* offset clip_rect, so it's parent_window relative */
if (clip_rect->x >= 0)
clip.x += widget->allocation.x;
if (clip_rect->y >= 0)
clip.y += widget->allocation.y;
}
if (!gdk_rectangle_intersect (&snap, &clip, &snap))
{
g_list_free (windows);
clip_rect->width = clip_rect->height = 0;
return NULL; /* empty snapshot area */
}
x = snap.x;
y = snap.y;
width = snap.width;
height = snap.height;
}
/* render snapshot */ /* render snapshot */
pixmap = gdk_pixmap_new (widget->window, width, height, gdk_drawable_get_depth (widget->window)); pixmap = gdk_pixmap_new (widget->window, width, height, gdk_drawable_get_depth (widget->window));
for (list = windows; list; list = list->next) for (list = windows; list; list = list->next) /* !NO_WINDOW widgets */
{ {
GdkWindow *subwin = list->data; GdkWindow *subwin = list->data;
int wx, wy; int wx, wy;
gdk_window_get_position (subwin, &wx, &wy); gdk_window_get_position (subwin, &wx, &wy);
gdk_window_redirect_to_drawable (subwin, pixmap, MAX (0, x - wx), MAX (0, y - wy), gdk_window_redirect_to_drawable (subwin, pixmap, MAX (0, x - wx), MAX (0, y - wy),
wx - x, wy - y, width, height); MAX (0, wx - x), MAX (0, wy - y), width, height);
gdk_window_invalidate_rect (subwin, NULL, TRUE); gdk_window_invalidate_rect (subwin, NULL, TRUE);
} }
if (!windows) /* NO_WINDOW || toplevel */ if (!windows) /* NO_WINDOW || toplevel => parent_window == NULL || parent_window == widget->window */
{ {
gdk_window_redirect_to_drawable (widget->window, pixmap, x, y, 0, 0, width, height); gdk_window_redirect_to_drawable (widget->window, pixmap, x, y, 0, 0, width, height);
gdk_window_invalidate_rect (widget->window, NULL, TRUE); gdk_window_invalidate_rect (widget->window, NULL, TRUE);
@ -8404,6 +8456,25 @@ gtk_widget_get_snapshot (GtkWidget *widget)
if (!windows) /* NO_WINDOW || toplevel */ if (!windows) /* NO_WINDOW || toplevel */
gdk_window_remove_redirection (widget->window); gdk_window_remove_redirection (widget->window);
g_list_free (windows); g_list_free (windows);
/* return pixmap and snapshot rectangle coordinates */
if (clip_rect)
{
clip_rect->x = x;
clip_rect->y = y;
clip_rect->width = width;
clip_rect->height = height;
if (widget->parent)
{
/* offset clip_rect from parent_window so it's widget relative */
clip_rect->x -= widget->allocation.x;
clip_rect->y -= widget->allocation.y;
}
if (0)
g_printerr ("gtk_widget_get_snapshot: %s (%d,%d, %dx%d)\n",
G_OBJECT_TYPE_NAME (widget),
clip_rect->x, clip_rect->y, clip_rect->width, clip_rect->height);
}
return pixmap; return pixmap;
} }

View File

@ -614,7 +614,8 @@ GdkWindow * gtk_widget_get_root_window (GtkWidget *widget);
GtkSettings* gtk_widget_get_settings (GtkWidget *widget); GtkSettings* gtk_widget_get_settings (GtkWidget *widget);
GtkClipboard *gtk_widget_get_clipboard (GtkWidget *widget, GtkClipboard *gtk_widget_get_clipboard (GtkWidget *widget,
GdkAtom selection); GdkAtom selection);
GdkPixmap * gtk_widget_get_snapshot (GtkWidget *widget); GdkPixmap * gtk_widget_get_snapshot (GtkWidget *widget,
GdkRectangle *clip_rect);
#ifndef GTK_DISABLE_DEPRECATED #ifndef GTK_DISABLE_DEPRECATED
#define gtk_widget_set_visual(widget,visual) ((void) 0) #define gtk_widget_set_visual(widget,visual) ((void) 0)

View File

@ -12259,16 +12259,16 @@ snapshot_widget_event (GtkWidget *widget,
if (res_widget) if (res_widget)
{ {
GdkPixmap *pixmap; GdkPixmap *pixmap;
GdkPixbuf *pixbuf = NULL;
GtkWidget *window, *image; GtkWidget *window, *image;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL); window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
pixmap = gtk_widget_get_snapshot (res_widget); pixmap = gtk_widget_get_snapshot (res_widget, NULL);
gtk_widget_realize (window); gtk_widget_realize (window);
if (gdk_drawable_get_depth (window->window) != gdk_drawable_get_depth (pixmap)) if (gdk_drawable_get_depth (window->window) != gdk_drawable_get_depth (pixmap))
{ {
/* this branch is needed to convert ARGB -> RGB */ /* this branch is needed to convert ARGB -> RGB */
int width, height; int width, height;
GdkPixbuf *pixbuf;
gdk_drawable_get_size (pixmap, &width, &height); gdk_drawable_get_size (pixmap, &width, &height);
pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap,
gtk_widget_get_colormap (res_widget), gtk_widget_get_colormap (res_widget),
@ -12276,10 +12276,10 @@ snapshot_widget_event (GtkWidget *widget,
0, 0, 0, 0,
width, height); width, height);
image = gtk_image_new_from_pixbuf (pixbuf); image = gtk_image_new_from_pixbuf (pixbuf);
g_object_unref (pixbuf);
} }
else else
image = gtk_image_new_from_pixmap (pixmap, NULL); image = gtk_image_new_from_pixmap (pixmap, NULL);
g_object_unref (pixbuf);
gtk_container_add (GTK_CONTAINER (window), image); gtk_container_add (GTK_CONTAINER (window), image);
g_object_unref (pixmap); g_object_unref (pixmap);
gtk_widget_show_all (window); gtk_widget_show_all (window);