Adding a ::screen-changed property
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gnome org
- Subject: Adding a ::screen-changed property
- Date: Tue, 5 Nov 2002 17:14:05 -0500 (EST)
After resisting it for a long time, I've come to the conclusion that
we really need a ::screen-changed property on GtkWidget.
It does add one more signal when adding a widget to a widget
heirarchy, but a no-op signal is only about 3000 cycles (100,000 a
second on a 300mhz machine) so that isn't a _huge_ concern.
The reason for it is that you need to track the quantity fairly often
when writing multihead-safe code (See GtkToolbar and GtkFontSelection)
and that it is a big pain to do with only the primitives we have
currently (See GtkToolbar and GtkFontSelection).
The other reason I was inspired to add it was that I needed
the screen-tracking machinery to fix
http://bugzilla.gnome.org/show_bug.cgi?id=85709.
The attach patch implements this; note that the quantity that
the signal tracks is not the result of gtk_widget_get_screen()
but rather the result of:
if (gtk_widget_has_screen (widget))
return gtk_widget_get_screen (widget);
else
return NULL;
That is, unanchored widgets are considered to have a screen
of NULL.
[ It definitely sucks that this distinction is necessary, but
I'm hesistant to change gtk_widget_get_screen() now ]
Regards,
Owen
? gtk/gtkcombo.c.owt
Index: gtk/gtkfontsel.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkfontsel.c,v
retrieving revision 1.77
diff -u -p -r1.77 gtkfontsel.c
--- gtk/gtkfontsel.c 9 Oct 2002 22:11:07 -0000 1.77
+++ gtk/gtkfontsel.c 5 Nov 2002 22:02:05 -0000
@@ -118,8 +118,8 @@ static void gtk_font_selection_get_pr
GParamSpec *pspec);
static void gtk_font_selection_init (GtkFontSelection *fontsel);
static void gtk_font_selection_finalize (GObject *object);
-static void gtk_font_selection_hierarchy_changed (GtkWidget *widget,
- GtkWidget *previous_toplevel);
+static void gtk_font_selection_screen_changed (GtkWidget *widget,
+ GdkScreen *previous_screen);
/* These are the callbacks & related functions. */
static void gtk_font_selection_select_font (GtkTreeSelection *selection,
@@ -200,7 +200,7 @@ gtk_font_selection_class_init (GtkFontSe
gobject_class->set_property = gtk_font_selection_set_property;
gobject_class->get_property = gtk_font_selection_get_property;
- widget_class->hierarchy_changed = gtk_font_selection_hierarchy_changed;
+ widget_class->screen_changed = gtk_font_selection_screen_changed;
g_object_class_install_property (gobject_class,
PROP_FONT_NAME,
@@ -522,60 +522,17 @@ gtk_font_selection_finalize (GObject *ob
}
static void
-fontsel_screen_changed (GtkFontSelection *fontsel)
+gtk_font_selection_screen_changed (GtkWidget *widget,
+ GdkScreen *previous_screen)
{
- GdkScreen *old_screen = g_object_get_data (G_OBJECT (fontsel), "gtk-font-selection-screen");
- GdkScreen *screen;
+ GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
- screen = gtk_widget_get_screen (GTK_WIDGET (fontsel));
- else
- screen = NULL;
-
- if (screen == old_screen)
- return;
-
- if (fontsel->font)
- {
- gdk_font_unref (fontsel->font);
- fontsel->font = NULL;
- }
-
- if (old_screen)
- g_object_unref (old_screen);
-
- if (screen)
{
- g_object_ref (screen);
- g_object_set_data (G_OBJECT (fontsel), "gtk-font-selection-screen", screen);
-
gtk_font_selection_show_available_fonts (fontsel);
gtk_font_selection_show_available_sizes (fontsel, TRUE);
gtk_font_selection_show_available_styles (fontsel);
}
- else
- g_object_set_data (G_OBJECT (fontsel), "gtk-font-selection-screen", NULL);
-}
-
-static void
-gtk_font_selection_hierarchy_changed (GtkWidget *widget,
- GtkWidget *previous_toplevel)
-{
- GtkWidget *toplevel;
-
- if (previous_toplevel)
- g_signal_handlers_disconnect_by_func (previous_toplevel,
- fontsel_screen_changed,
- widget);
-
- toplevel = gtk_widget_get_toplevel (widget);
- if (GTK_WIDGET_TOPLEVEL (toplevel))
- g_signal_connect_swapped (toplevel,
- "notify::screen",
- G_CALLBACK (fontsel_screen_changed),
- widget);
-
- fontsel_screen_changed (GTK_FONT_SELECTION (widget));
}
static void
Index: gtk/gtkinvisible.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkinvisible.c,v
retrieving revision 1.19
diff -u -p -r1.19 gtkinvisible.c
--- gtk/gtkinvisible.c 10 Oct 2002 22:00:09 -0000 1.19
+++ gtk/gtkinvisible.c 5 Nov 2002 22:02:05 -0000
@@ -189,6 +189,8 @@ void
gtk_invisible_set_screen (GtkInvisible *invisible,
GdkScreen *screen)
{
+ GtkWidget *widget;
+ GdkScreen *previous_screen;
gboolean was_realized;
g_return_if_fail (GTK_IS_INVISIBLE (invisible));
@@ -197,16 +199,21 @@ gtk_invisible_set_screen (GtkInvisible *
if (screen == invisible->screen)
return;
+ widget = GTK_WIDGET (invisible);
+
+ previous_screen = invisible->screen;
was_realized = GTK_WIDGET_REALIZED (invisible);
if (was_realized)
- gtk_widget_unrealize (GTK_WIDGET (invisible));
+ gtk_widget_unrealize (widget);
invisible->screen = screen;
+ if (screen != previous_screen)
+ _gtk_widget_propagate_screen_changed (widget, previous_screen);
g_object_notify (G_OBJECT (invisible), "screen");
if (was_realized)
- gtk_widget_realize (GTK_WIDGET (invisible));
+ gtk_widget_realize (widget);
}
/**
Index: gtk/gtktoolbar.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktoolbar.c,v
retrieving revision 1.82
diff -u -p -r1.82 gtktoolbar.c
--- gtk/gtktoolbar.c 2 Nov 2002 05:37:03 -0000 1.82
+++ gtk/gtktoolbar.c 5 Nov 2002 22:02:05 -0000
@@ -94,8 +94,8 @@ static void gtk_toolbar_style_set
GtkStyle *prev_style);
static gboolean gtk_toolbar_focus (GtkWidget *widget,
GtkDirectionType dir);
-static void gtk_toolbar_hierarchy_changed (GtkWidget *widget,
- GtkWidget *previous_toplevel);
+static void gtk_toolbar_screen_changed (GtkWidget *widget,
+ GdkScreen *previous_screen);
static void gtk_toolbar_show_all (GtkWidget *widget);
static void gtk_toolbar_add (GtkContainer *container,
GtkWidget *widget);
@@ -195,7 +195,7 @@ gtk_toolbar_class_init (GtkToolbarClass
widget_class->style_set = gtk_toolbar_style_set;
widget_class->show_all = gtk_toolbar_show_all;
widget_class->focus = gtk_toolbar_focus;
- widget_class->hierarchy_changed = gtk_toolbar_hierarchy_changed;
+ widget_class->screen_changed = gtk_toolbar_screen_changed;
container_class->add = gtk_toolbar_add;
container_class->remove = gtk_toolbar_remove;
@@ -329,8 +329,10 @@ toolbar_get_settings (GtkToolbar *toolba
}
static void
-toolbar_screen_changed (GtkToolbar *toolbar)
+gtk_toolbar_screen_changed (GtkWidget *widget,
+ GdkScreen *previous_screen)
{
+ GtkToolbar *toolbar = GTK_TOOLBAR (widget);
GtkSettings *old_settings = toolbar_get_settings (toolbar);
GtkSettings *settings;
@@ -373,27 +375,6 @@ toolbar_screen_changed (GtkToolbar *tool
style_change_notify (toolbar);
icon_size_change_notify (toolbar);
-}
-
-static void
-gtk_toolbar_hierarchy_changed (GtkWidget *widget,
- GtkWidget *previous_toplevel)
-{
- GtkWidget *toplevel;
-
- if (previous_toplevel)
- g_signal_handlers_disconnect_by_func (previous_toplevel,
- toolbar_screen_changed,
- widget);
-
- toplevel = gtk_widget_get_toplevel (widget);
- if (GTK_WIDGET_TOPLEVEL (toplevel))
- g_signal_connect_swapped (toplevel,
- "notify::screen",
- G_CALLBACK (toolbar_screen_changed),
- widget);
-
- toolbar_screen_changed (GTK_TOOLBAR (widget));
}
static void
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.330
diff -u -p -r1.330 gtkwidget.c
--- gtk/gtkwidget.c 13 Oct 2002 20:44:17 -0000 1.330
+++ gtk/gtkwidget.c 5 Nov 2002 22:02:05 -0000
@@ -116,6 +116,7 @@ enum {
POPUP_MENU,
SHOW_HELP,
ACCEL_CLOSURES_CHANGED,
+ SCREEN_CHANGED,
LAST_SIGNAL
};
@@ -379,6 +380,7 @@ gtk_widget_class_init (GtkWidgetClass *k
klass->drag_motion = NULL;
klass->drag_drop = NULL;
klass->drag_data_received = NULL;
+ klass->screen_changed = NULL;
klass->show_help = gtk_widget_real_show_help;
@@ -1053,6 +1055,15 @@ gtk_widget_class_init (GtkWidgetClass *k
NULL, NULL,
_gtk_marshal_NONE__NONE,
G_TYPE_NONE, 0);
+ widget_signals[SCREEN_CHANGED] =
+ g_signal_new ("screen_changed",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkWidgetClass, hierarchy_changed),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GDK_TYPE_SCREEN);
binding_set = gtk_binding_set_by_class (klass);
gtk_binding_entry_add_signal (binding_set, GDK_F10, GDK_SHIFT_MASK,
@@ -4289,11 +4300,27 @@ gtk_widget_set_style_internal (GtkWidget
g_object_unref (widget);
}
+typedef struct {
+ GtkWidget *previous_toplevel;
+ GdkScreen *previous_screen;
+ GdkScreen *new_screen;
+} HierarchyChangedInfo;
+
+static void
+do_screen_change (GtkWidget *widget,
+ GdkScreen *old_screen,
+ GdkScreen *new_screen)
+{
+ if (old_screen != new_screen)
+ g_signal_emit (widget, widget_signals[SCREEN_CHANGED], 0, old_screen);
+}
+
static void
gtk_widget_propagate_hierarchy_changed_recurse (GtkWidget *widget,
gpointer client_data)
{
gboolean new_anchored;
+ HierarchyChangedInfo *info = client_data;
new_anchored = GTK_WIDGET_TOPLEVEL (widget) ||
(widget->parent && GTK_WIDGET_ANCHORED (widget->parent));
@@ -4307,8 +4334,9 @@ gtk_widget_propagate_hierarchy_changed_r
else
GTK_PRIVATE_UNSET_FLAG (widget, GTK_ANCHORED);
- g_signal_emit (widget, widget_signals[HIERARCHY_CHANGED], 0, client_data);
-
+ g_signal_emit (widget, widget_signals[HIERARCHY_CHANGED], 0, info->previous_toplevel);
+ do_screen_change (widget, info->previous_screen, info->new_screen);
+
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget),
gtk_widget_propagate_hierarchy_changed_recurse,
@@ -4331,13 +4359,72 @@ void
_gtk_widget_propagate_hierarchy_changed (GtkWidget *widget,
GtkWidget *previous_toplevel)
{
+ HierarchyChangedInfo info;
+
+ info.previous_toplevel = previous_toplevel;
+ info.previous_screen = previous_toplevel ? gtk_widget_get_screen (previous_toplevel) : NULL;
+
+ if (GTK_WIDGET_TOPLEVEL (widget) ||
+ (widget->parent && GTK_WIDGET_ANCHORED (widget->parent)))
+ info.new_screen = gtk_widget_get_screen (widget);
+ else
+ info.new_screen = NULL;
+
+ if (info.previous_screen)
+ g_object_ref (info.previous_screen);
if (previous_toplevel)
g_object_ref (previous_toplevel);
- gtk_widget_propagate_hierarchy_changed_recurse (widget, previous_toplevel);
-
+ gtk_widget_propagate_hierarchy_changed_recurse (widget, &info);
+
if (previous_toplevel)
g_object_unref (previous_toplevel);
+ if (info.previous_screen)
+ g_object_unref (info.previous_screen);
+}
+
+static void
+gtk_widget_propagate_screen_changed_recurse (GtkWidget *widget,
+ gpointer client_data)
+{
+ HierarchyChangedInfo *info = client_data;
+
+ g_object_ref (widget);
+
+ do_screen_change (widget, info->previous_screen, info->new_screen);
+
+ if (GTK_IS_CONTAINER (widget))
+ gtk_container_forall (GTK_CONTAINER (widget),
+ gtk_widget_propagate_hierarchy_changed_recurse,
+ client_data);
+
+ g_object_unref (widget);
+}
+
+/**
+ * _gtk_widget_propagate_screen_changed:
+ * @widget: a #GtkWidget
+ * @previous_screen: Previous screen
+ *
+ * Propagates changes in the screen for a widget to all
+ * children, emitting ::screen_changed.
+ **/
+void
+_gtk_widget_propagate_screen_changed (GtkWidget *widget,
+ GdkScreen *previous_screen)
+{
+ HierarchyChangedInfo info;
+
+ info.previous_screen = previous_screen;
+ info.new_screen = gtk_widget_get_screen (widget);
+
+ if (previous_screen)
+ g_object_ref (previous_screen);
+
+ gtk_widget_propagate_screen_changed_recurse (widget, &info);
+
+ if (previous_screen)
+ g_object_unref (previous_screen);
}
static void
@@ -4666,7 +4753,7 @@ gtk_widget_get_screen_unchecked (GtkWidg
*
* Get the #GdkScreen from the toplevel window associated with
* this widget. This function can only be called after the widget
- * has been added to a widget heirarchy with a #GtkWindow
+ * has been added to a widget hierarchy with a #GtkWindow
* at the top.
*
* In general, you should only create screen specific
Index: gtk/gtkwidget.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.h,v
retrieving revision 1.138
diff -u -p -r1.138 gtkwidget.h
--- gtk/gtkwidget.h 13 Oct 2002 20:44:18 -0000 1.138
+++ gtk/gtkwidget.h 5 Nov 2002 22:02:05 -0000
@@ -398,6 +398,8 @@ struct _GtkWidgetClass
*/
AtkObject* (* get_accessible) (GtkWidget *widget);
+ void (* screen_changed) (GtkWidget *widget,
+ GdkScreen *previous_screen);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
@@ -761,6 +763,8 @@ GtkWidgetAuxInfo *_gtk_widget_get_aux_in
gboolean create);
void _gtk_widget_propagate_hierarchy_changed (GtkWidget *widget,
GtkWidget *previous_toplevel);
+void _gtk_widget_propagate_screen_changed (GtkWidget *widget,
+ GdkScreen *previous_screen);
GdkColormap* _gtk_widget_peek_colormap (void);
Index: gtk/gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.230
diff -u -p -r1.230 gtkwindow.c
--- gtk/gtkwindow.c 2 Nov 2002 05:37:03 -0000 1.230
+++ gtk/gtkwindow.c 5 Nov 2002 22:02:05 -0000
@@ -5982,6 +5982,8 @@ gtk_window_set_screen (GtkWindow *window
GdkScreen *screen)
{
GtkWidget *widget;
+ GdkScreen *previous_screen;
+ GdkScreen *new_screen;
gboolean was_mapped;
g_return_if_fail (GTK_IS_WINDOW (window));
@@ -5991,17 +5993,20 @@ gtk_window_set_screen (GtkWindow *window
return;
widget = GTK_WIDGET (window);
-
+
+ previous_screen = window->screen;
was_mapped = GTK_WIDGET_MAPPED (widget);
if (was_mapped)
gtk_widget_unmap (widget);
if (GTK_WIDGET_REALIZED (widget))
gtk_widget_unrealize (widget);
-
+
gtk_window_free_key_hash (window);
window->screen = screen;
gtk_widget_reset_rc_styles (widget);
+ if (screen != previous_screen)
+ _gtk_widget_propagate_screen_changed (widget, previous_screen);
g_object_notify (G_OBJECT (window), "screen");
if (was_mapped)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]