Re: Problems with expose_event->region patch



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]