A ::hierarchy_changed signal
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gtk org
- Subject: A ::hierarchy_changed signal
- Date: 03 Mar 2001 21:32:42 -0500
There are a number of cases where a widget needs to know
if there is a change in its set of ancestors.
Two examples of this came up in work I was recently doing
on GtkSocket:
- GtkSocket needs to track whether the toplevel it in
has the focus so it can propagate that information
to the GtkPlug.
- GtkSocket needs to track what toplevel it is in, so
it can forward accelerators from the socket to the
toplevel.
Another example involving non-toplevels would be one of
the schemes that was floated earlier this week for
automatic addition of underline accelerators / mnemonics:
- When a widget is added to a notebook page or a window,
it walks up the widget hierarchy, finds the correct
accelerator group and adds itself to it.
What is basically needed is an extension of the ::parent_set
signal that GtkWidget has to arbitrary changes in ancestors.
The attached implementation adds a hierarchy_changed
signal to GtkWidget that is emitted any time the parent
of the widget changes, or the parent of any ancestor
changes.
(I do the recursion here out of the default handler so
that the user can control whether they see pre-recursive
or post-recursive behavior by choosing between connect()
and connect_after(). The recursion could also be done
directly for more a bit more simplicity and robustness.)
Tim had some worries that this could be pretty inefficient,
since worst-case you can get n*(n-1)/2 emissions for n
widgets. (If you have a widget hierarchy without branching
and you build it from the leaf to the root.)
But it's quite hard to construct plausible scenarious where
more than a couple of hundred emissions would be involved
in creating a toplevel, and benchmarking indicates that,
even pre-gsignal-optimization, there isn't much reason
for concern with that.
Conceivably more efficient alternatives include:
- Having to explicitely register for notification.
(There is something a bit like this with the cross-references
in beast/bse/bsecontainer.c, though either I don't
understand them or they would need to become more
complicated to handle the above scenarious.)
This is more efficient if only a few widgets need
notification, but as more widgets need notification,
the book-keeping overhead here could become large.
- Do notification only when the hierarchy terminates
at a GtkWindow. This reduces the worst case for
signal emission from n*(n-1)/2 to n, and should
be as good for almost all purposes.
The only real disadvantage of this is it is a little
more complicated to explain and a could be little
trickier to use in some cases.
Regards,
Owen
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.187
diff -u -r1.187 gtkwidget.c
--- gtk/gtkwidget.c 2001/02/28 19:07:45 1.187
+++ gtk/gtkwidget.c 2001/03/03 18:50:31
@@ -56,8 +56,10 @@
SIZE_ALLOCATE,
STATE_CHANGED,
PARENT_SET,
+ HIERARCHY_CHANGED,
STYLE_SET,
DIRECTION_CHANGED,
ADD_ACCELERATOR,
REMOVE_ACCELERATOR,
GRAB_FOCUS,
@@ -155,6 +157,7 @@
GtkRequisition *requisition);
static void gtk_widget_real_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
+static void gtk_widget_real_hierarchy_changed (GtkWidget *widget);
static gint gtk_widget_real_key_press_event (GtkWidget *widget,
GdkEventKey *event);
static gint gtk_widget_real_key_release_event (GtkWidget *widget,
@@ -295,8 +298,11 @@
klass->size_allocate = gtk_widget_real_size_allocate;
klass->state_changed = NULL;
klass->parent_set = NULL;
+ klass->hierarchy_changed = gtk_widget_real_hierarchy_changed;
klass->style_set = gtk_widget_style_set;
klass->direction_changed = gtk_widget_direction_changed;
klass->add_accelerator = (void*) gtk_accel_group_handle_add;
klass->remove_accelerator = (void*) gtk_accel_group_handle_remove;
klass->grab_focus = gtk_widget_real_grab_focus;
@@ -429,6 +435,13 @@
gtk_marshal_VOID__POINTER,
GTK_TYPE_NONE, 1,
GTK_TYPE_OBJECT);
+ widget_signals[HIERARCHY_CHANGED] =
+ gtk_signal_new ("hierarchy_changed",
+ GTK_RUN_LAST,
+ GTK_CLASS_TYPE (object_class),
+ GTK_SIGNAL_OFFSET (GtkWidgetClass, hierarchy_changed),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
widget_signals[STYLE_SET] =
gtk_signal_new ("style_set",
GTK_RUN_FIRST,
@@ -1232,6 +1253,7 @@
widget->parent = NULL;
gtk_widget_set_parent_window (widget, NULL);
gtk_signal_emit (GTK_OBJECT (widget), widget_signals[PARENT_SET], old_parent);
+ gtk_signal_emit (GTK_OBJECT (widget), widget_signals[HIERARCHY_CHANGED]);
gtk_widget_unref (widget);
}
@@ -2005,6 +2027,22 @@
}
static void
+hierarchy_changed_foreach (GtkWidget *child, gpointer data)
+{
+ gtk_signal_emit (GTK_OBJECT (child), widget_signals[HIERARCHY_CHANGED]);
+}
+
+static void
+gtk_widget_real_hierarchy_changed (GtkWidget *widget)
+{
+ if (GTK_IS_CONTAINER (widget))
+ {
+ gtk_container_foreach (GTK_CONTAINER (widget),
+ hierarchy_changed_foreach, NULL);
+ }
+}
+
+static void
gtk_widget_real_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
@@ -2980,6 +3018,7 @@
gtk_widget_set_style_recurse (widget, NULL);
gtk_signal_emit (GTK_OBJECT (widget), widget_signals[PARENT_SET], NULL);
+ gtk_signal_emit (GTK_OBJECT (widget), widget_signals[HIERARCHY_CHANGED]);
}
/*****************************************
Index: gtk/gtkwidget.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.h,v
retrieving revision 1.91
diff -u -r1.91 gtkwidget.h
--- gtk/gtkwidget.h 2001/02/28 19:07:46 1.91
+++ gtk/gtkwidget.h 2001/03/03 18:50:31
@@ -250,10 +250,13 @@
GtkStateType previous_state);
void (* parent_set) (GtkWidget *widget,
GtkWidget *previous_parent);
+ void (* hierarchy_changed) (GtkWidget *widget);
void (* style_set) (GtkWidget *widget,
GtkStyle *previous_style);
void (* direction_changed) (GtkWidget *widget,
GtkTextDirection previous_direction);
/* accelerators */
gint (* add_accelerator) (GtkWidget *widget,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]