Re: Problems with expose_event->region patch
- From: Alexander Larsson <alla lysator liu se>
- To: Owen Taylor <otaylor redhat com>
- Cc: <gtk-devel-list gnome org>
- Subject: Re: Problems with expose_event->region patch
- Date: Thu, 8 Mar 2001 14:07:29 +0100 (CET)
On 7 Mar 2001, Owen Taylor wrote:
> At least with backing store, I don't follow this. Only the region
> is copied from the back buffer to the screen, so painting outside
> the region doesn't matter. There is an implicit clip to the region
> passed to gtk_window_begin_paint().
>
> (Have you changed gtk_main_do_event to call gtk_window_begin_paint_region?
> Now that you have the region in the expose?)
No, i must have missed this. I'm not very good at the backing store stuff,
and i don't think many are. Have you written any docs on that?
When i made this change everything works just perfect.
> For the non-backing-store case we could even add a
> gdk_drawable_set_clip_region() call and emulate it by changing the
> GC's clips, though that could be rather inefficient without a
> lot of complexity.
>
> But I would really consider that unless you have a widget in which
> you are doing all your own painting, you really are supposed
> to leave backing store on.
>
> [ That is, calling gtk_widget_set_double_buffered (gtkwindow, FALSE)
> is bogus ]
nod.
Here is the core of the patch in the final form. Then i changed all the
widgets to chain to the expose handler or propagate exposes correctly.
That part is pretty much like the previously send patch, although i found
some additional gtk_widget_event()s.
Is this ok to check in?
Index: docs/Changes-2.0.txt
===================================================================
RCS file: /cvs/gnome/gtk+/docs/Changes-2.0.txt,v
retrieving revision 1.13
diff -u -p -r1.13 Changes-2.0.txt
--- docs/Changes-2.0.txt 2001/03/07 23:40:59 1.13
+++ docs/Changes-2.0.txt 2001/03/08 12:36:32
@@ -279,6 +279,15 @@ Incompatible Changes from GTK+-1.2 to GT
implementation, since they will already have working expose_event
implementations. The draw method was rarely called in practice
anyway.
+
+- The GdkExposeEvent has a new region field. This can be used instead
+ of the area field if you want a more exact representation of the
+ area to update. If your code sends any synthetic expose events, make
+ sure you initialize the region field, by using something like:
+ event.region = gdk_region_rectangle (event.area);
+ Note that sending synthetic expose events isn't really a good way to
+ expose (parts of) a window anymore, you should use
+ gdk_window_invalidate_rect() or gdk_window_invalidate_region() instead.
* The draw_default and draw_focus methods/signals on GtkWidget are
gone; simply draw things in your expose handler.
Index: gdk/gdkevents.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkevents.c,v
retrieving revision 1.34
diff -u -p -r1.34 gdkevents.c
--- gdk/gdkevents.c 2001/02/27 20:39:46 1.34
+++ gdk/gdkevents.c 2001/03/08 12:36:33
@@ -322,8 +322,12 @@ gdk_event_copy (GdkEvent *event)
gdk_drag_context_ref (event->dnd.context);
break;
- default:
+ case GDK_EXPOSE:
+ if (event->expose.region)
+ new_event->expose.region = gdk_region_copy (event->expose.region);
break;
+ default:
+ break;
}
return new_event;
@@ -384,7 +388,12 @@ gdk_event_free (GdkEvent *event)
if (event->button.axes)
g_free (event->button.axes);
break;
-
+
+ case GDK_EXPOSE:
+ if (event->expose.region)
+ gdk_region_destroy (event->expose.region);
+ break;
+
case GDK_MOTION_NOTIFY:
if (event->motion.axes)
g_free (event->motion.axes);
Index: gdk/gdkevents.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkevents.h,v
retrieving revision 1.12
diff -u -p -r1.12 gdkevents.h
--- gdk/gdkevents.h 2001/02/27 20:39:47 1.12
+++ gdk/gdkevents.h 2001/03/08 12:36:33
@@ -215,6 +215,7 @@ struct _GdkEventExpose
GdkWindow *window;
gint8 send_event;
GdkRectangle area;
+ GdkRegion *region;
gint count; /* If non-zero, how many more events follow. */
};
Index: gdk/gdkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.c,v
retrieving revision 1.109
diff -u -p -r1.109 gdkwindow.c
--- gdk/gdkwindow.c 2001/02/27 20:39:47 1.109
+++ gdk/gdkwindow.c 2001/03/08 12:36:33
@@ -1748,6 +1748,8 @@ gdk_window_process_updates_internal (Gdk
{
GdkEvent event;
GdkRectangle window_rect;
+ GdkRegion *expose_region;
+ GdkRegion *window_region;
gint width, height;
if (debug_updates)
@@ -1769,16 +1771,28 @@ gdk_window_process_updates_internal (Gdk
event.expose.type = GDK_EXPOSE;
event.expose.window = gdk_window_ref (window);
event.expose.count = 0;
-
- gdk_region_get_clipbox (update_area, &event.expose.area);
- if (gdk_rectangle_intersect (&event.expose.area, &window_rect, &event.expose.area))
+
+ if (save_region)
+ expose_region = gdk_region_copy (update_area);
+ else
+ expose_region = update_area;
+ window_region = gdk_region_rectangle (&window_rect);
+ gdk_region_intersect (expose_region,
+ window_region);
+ gdk_region_destroy (window_region);
+
+ event.expose.region = expose_region;
+ gdk_region_get_clipbox (expose_region, &event.expose.area);
+
+ if (!gdk_region_empty (expose_region))
{
(*gdk_event_func) (&event, gdk_event_data);
}
+ if (expose_region != update_area)
+ gdk_region_destroy (expose_region);
gdk_window_unref (window);
}
-
if (!save_region)
gdk_region_destroy (update_area);
}
Index: gdk/x11/gdkevents-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkevents-x11.c,v
retrieving revision 1.41
diff -u -p -r1.41 gdkevents-x11.c
--- gdk/x11/gdkevents-x11.c 2001/03/03 21:34:18 1.41
+++ gdk/x11/gdkevents-x11.c 2001/03/08 12:36:33
@@ -973,6 +973,7 @@ gdk_event_translate (GdkEvent *event,
{
event->expose.type = GDK_EXPOSE;
event->expose.area = expose_rect;
+ event->expose.region = gdk_region_rectangle (&expose_rect);
event->expose.window = window;
event->expose.count = xevent->xexpose.count;
@@ -1007,6 +1008,7 @@ gdk_event_translate (GdkEvent *event,
{
event->expose.type = GDK_EXPOSE;
event->expose.area = expose_rect;
+ event->expose.region = gdk_region_rectangle (&expose_rect);
event->expose.window = window;
event->expose.count = xevent->xgraphicsexpose.count;
Index: gtk/gtkcontainer.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkcontainer.c,v
retrieving revision 1.71
diff -u -p -r1.71 gtkcontainer.c
--- gtk/gtkcontainer.c 2001/03/07 14:49:19 1.71
+++ gtk/gtkcontainer.c 2001/03/08 12:36:35
@@ -96,6 +96,8 @@ static void gtk_container_children_c
gpointer client_data);
static void gtk_container_show_all (GtkWidget *widget);
static void gtk_container_hide_all (GtkWidget *widget);
+static gint gtk_container_expose (GtkWidget *widget,
+ GdkEventExpose *event);
static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
@@ -172,6 +174,7 @@ gtk_container_class_init (GtkContainerCl
widget_class->show_all = gtk_container_show_all;
widget_class->hide_all = gtk_container_hide_all;
+ widget_class->expose_event = gtk_container_expose;
class->add = gtk_container_add_unimplemented;
class->remove = gtk_container_remove_unimplemented;
@@ -1962,4 +1965,86 @@ gtk_container_hide_all (GtkWidget *widge
gtk_container_foreach (GTK_CONTAINER (widget),
(GtkCallback) gtk_widget_hide_all,
NULL);
+}
+
+
+static void
+gtk_container_expose_child (GtkWidget *child,
+ gpointer client_data)
+{
+ struct {
+ GtkWidget *container;
+ GdkEventExpose *event;
+ } *data = client_data;
+
+ gtk_container_propagate_expose (GTK_CONTAINER (data->container),
+ child,
+ data->event);
+}
+
+static gint
+gtk_container_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ struct {
+ GtkWidget *container;
+ GdkEventExpose *event;
+ } data;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+
+ if (GTK_WIDGET_DRAWABLE (widget))
+ {
+ data.container = widget;
+ data.event = event;
+
+ gtk_container_foreach (GTK_CONTAINER (widget),
+ gtk_container_expose_child,
+ &data);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * gtk_container_propagate_expose:
+ * @container: a #GtkContainer
+ * @child: a child of @container
+ * @event: a expose event sent to container
+ *
+ * Some windows (those without GdkWindows) need to get synthetic expose
+ * events, since they don't get expose events otherwise. This function
+ * should be used by all containers to propagate expose events. It handles
+ * correct intersecting and coordinate translation of the event.
+ **/
+void
+gtk_container_propagate_expose (GtkContainer *container,
+ GtkWidget *child,
+ GdkEventExpose *event)
+{
+ GdkEventExpose child_event;
+
+ g_return_if_fail (GTK_IS_CONTAINER (container));
+ g_return_if_fail (GTK_IS_WIDGET (child));
+ g_return_if_fail (event != NULL);
+
+ g_assert (child->parent == GTK_WIDGET (container));
+
+ if (GTK_WIDGET_DRAWABLE (child) &&
+ GTK_WIDGET_NO_WINDOW (child))
+ {
+ child_event = *event;
+
+ child_event.region = gtk_widget_region_intersect (child, event->region);
+ if (!gdk_region_empty (child_event.region))
+ {
+ gdk_region_get_clipbox (child_event.region, &child_event.area);
+ gtk_widget_send_expose (child, (GdkEvent *)&child_event);
+ }
+ gdk_region_destroy (child_event.region);
+ }
}
Index: gtk/gtkcontainer.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkcontainer.h,v
retrieving revision 1.35
diff -u -p -r1.35 gtkcontainer.h
--- gtk/gtkcontainer.h 2000/12/11 17:47:24 1.35
+++ gtk/gtkcontainer.h 2001/03/08 12:36:35
@@ -130,6 +130,9 @@ void gtk_container_foreach_full (Gtk
GList* gtk_container_children (GtkContainer *container);
gboolean gtk_container_focus (GtkContainer *container,
GtkDirectionType direction);
+void gtk_container_propagate_expose (GtkContainer *container,
+ GtkWidget *child,
+ GdkEventExpose *event);
/* Widget-level methods */
Index: gtk/gtkmain.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmain.c,v
retrieving revision 1.152
diff -u -p -r1.152 gtkmain.c
--- gtk/gtkmain.c 2001/03/03 21:34:18 1.152
+++ gtk/gtkmain.c 2001/03/08 12:36:37
@@ -869,9 +869,9 @@ gtk_main_do_event (GdkEvent *event)
case GDK_EXPOSE:
if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
- gdk_window_begin_paint_rect (event->any.window, &event->expose.area);
+ gdk_window_begin_paint_region (event->any.window, event->expose.region);
- gtk_widget_event (event_widget, event);
+ gtk_widget_send_expose (event_widget, event);
if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
gdk_window_end_paint (event->any.window);
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.190
diff -u -p -r1.190 gtkwidget.c
--- gtk/gtkwidget.c 2001/03/08 06:14:42 1.190
+++ gtk/gtkwidget.c 2001/03/08 12:36:41
@@ -182,6 +182,8 @@ static void gtk_widget_set_style_interna
gboolean initial_emission);
static void gtk_widget_set_style_recurse (GtkWidget *widget,
gpointer client_data);
+static gint gtk_widget_event_internal (GtkWidget *widget,
+ GdkEvent *event);
static void gtk_widget_propagate_hierarchy_changed (GtkWidget *widget,
gpointer client_data);
@@ -2244,12 +2246,62 @@ gint
gtk_widget_event (GtkWidget *widget,
GdkEvent *event)
{
- gboolean return_val;
- gint signal_num;
+ g_return_val_if_fail (widget != NULL, TRUE);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
+
+ if (event->type == GDK_EXPOSE)
+ {
+ g_warning ("Events of type GDK_EXPOSE cannot be synthesized. To get "
+ "the same effect, call gdk_window_invalidate_rect/region(), "
+ "followed by gdk_window_process_updates().");
+ return TRUE;
+ }
+
+ return gtk_widget_event_internal (widget, event);
+}
+
+/**
+ * gtk_widget_send_expose:
+ * @widget: a #GtkWidget
+ * @event: a expose #GdkEvent
+ *
+ * Very rarely-used function. This function is used to emit
+ * an expose event signals on a widget. This function is not
+ * normally used directly. The only time it is used is when
+ * propagating an expose event to a child NO_WINDOW widget, and
+ * that is normally done using gtk_container_propagate_expose.
+ *
+ * If you just want to synthesize an expose event, use
+ * gdk_window_invalidate_rect() to invalidate a region of the
+ * window.
+ *
+ * Return value: return from the event signal emission (%TRUE if the event was handled)
+ **/
+gint
+gtk_widget_send_expose (GtkWidget *widget,
+ GdkEvent *event)
+{
g_return_val_if_fail (widget != NULL, TRUE);
g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
+ g_return_val_if_fail (event != NULL, TRUE);
+ g_return_val_if_fail (event->type == GDK_EXPOSE, TRUE);
+ if (event->type != GDK_EXPOSE)
+ return TRUE;
+
+ return gtk_widget_event_internal (widget, event);
+}
+
+/* This internal function is called from gtkmain.c
+ * to allow it to pass expose events. */
+static gint
+gtk_widget_event_internal (GtkWidget *widget,
+ GdkEvent *event)
+{
+ gboolean return_val;
+ gint signal_num;
+
gtk_widget_ref (widget);
return_val = FALSE;
gtk_signal_emit (GTK_OBJECT (widget), widget_signals[EVENT], event,
@@ -2574,6 +2626,38 @@ gtk_widget_intersect (GtkWidget *widg
}
return return_val;
+}
+
+/**
+ * gtk_widget_region_intersect:
+ * @widget: a #GtkWidget
+ * @region: a #GdkRegion
+ * @returns: the intersection of @widget and @region
+ *
+ * Computes the intersection of a @widget's area and @region, returning
+ * the intersection. The result may be empty, use #gdk_region_empty to
+ * check.
+ **/
+GdkRegion *
+gtk_widget_region_intersect (GtkWidget *widget,
+ GdkRegion *region)
+{
+ GdkRegion *dest;
+
+ g_return_val_if_fail (widget != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (region != NULL, NULL);
+
+ dest = gdk_region_rectangle (&widget->allocation);
+
+ gdk_region_intersect (dest, region);
+
+ if (!GTK_WIDGET_NO_WINDOW (widget))
+ gdk_region_offset (dest,
+ -widget->allocation.x,
+ -widget->allocation.y);
+
+ return dest;
}
/**
Index: gtk/gtkwidget.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.h,v
retrieving revision 1.93
diff -u -p -r1.93 gtkwidget.h
--- gtk/gtkwidget.h 2001/03/08 06:14:43 1.93
+++ gtk/gtkwidget.h 2001/03/08 12:36:41
@@ -466,6 +466,8 @@ void gtk_widget_unlock_accelerators (
gboolean gtk_widget_accelerators_locked (GtkWidget *widget);
gint gtk_widget_event (GtkWidget *widget,
GdkEvent *event);
+gint gtk_widget_send_expose (GtkWidget *widget,
+ GdkEvent *event);
gboolean gtk_widget_activate (GtkWidget *widget);
gboolean gtk_widget_set_scroll_adjustments (GtkWidget *widget,
@@ -480,6 +482,8 @@ void gtk_widget_popup (GtkWidget
gboolean gtk_widget_intersect (GtkWidget *widget,
GdkRectangle *area,
GdkRectangle *intersection);
+GdkRegion *gtk_widget_region_intersect (GtkWidget *widget,
+ GdkRegion *region);
gboolean gtk_widget_is_focus (GtkWidget *widget);
void gtk_widget_grab_focus (GtkWidget *widget);
@@ -639,6 +643,7 @@ void gtk_widget_class_path (GtkW
guint *path_length,
gchar **path,
gchar **path_reversed);
+
#if defined (GTK_TRACE_OBJECTS) && defined (__GNUC__)
# define gtk_widget_ref gtk_object_ref
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]