New version of the grab group patch
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gnome org
- Subject: New version of the grab group patch
- Date: 08 Jun 2001 18:11:17 -0400
Here's a new version of the patch to add grab groups and
notification of grab shadowing that I sent to the list
a few months ago.
The big change from the last version is that there is now
a GtkWindowGroup structure, instead of the grouping being
implicitely defined by a "leader window".
This works a lot like GtkSizeGroup in that you have:
void gtk_window_group_add_window (GtkWindowGroup *window_group,
GtkWindow *window);
void gtk_window_group_remove_window (GtkWindowGroup *window_group,
GtkWindow *window);
Rather than a gtk_window_set_group ().
One interesting question is whether the code should
automatically or optionally make the windows in a window
group an ICCCM window group by setting a group leader... I'm
leaving this undone for now.
I consider this to close:
1579: Setting Gtk wwidget insensitive can lock GUI
51746: Notification of shadowing by gtk_grab_add()
Regards,
Owen
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.2030
diff -u -r1.2030 ChangeLog
--- ChangeLog 2001/06/08 16:06:50 1.2030
+++ ChangeLog 2001/06/08 22:02:09
@@ -1,3 +1,17 @@
+Fri Jun 8 17:56:52 2001 Owen Taylor <otaylor redhat com>
+
+ * gtk/gtkwindow.[ch] gtk/gtkmain.c: Add a GtkWindowGroup struct
+ that allows grouping together multiple windows so that grabs
+ within that set of windows only affect those windows.
+
+ * gtk/gtkmain.c gtk/gtkwidget.[ch]: Add a "grab_notify"
+ signal for notification when a widget becomes shadowed
+ by a grab or is no longer shadowed by a grab.
+
+ * gtk/gtkwidget.c (gtk_widget_propagate_state)
+ gtk/gtkmain.c: (gtk_widget_grab_add): Don't allow
+ insenstive widgets to maintain a grab.
+
Fri Jun 8 12:03:07 2001 Owen Taylor <otaylor redhat com>
* gdk/gdkkeys.[ch]: Add a direction-changed signal,
Index: gtk/gtkmain.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmain.c,v
retrieving revision 1.161
diff -u -r1.161 gtkmain.c
--- gtk/gtkmain.c 2001/05/12 13:16:40 1.161
+++ gtk/gtkmain.c 2001/06/08 22:02:09
@@ -110,6 +110,8 @@
static void gtk_print (gchar *str);
#endif
+static GtkWindowGroup *gtk_main_get_window_group (GtkWidget *widget);
+
const guint gtk_major_version = GTK_MAJOR_VERSION;
const guint gtk_minor_version = GTK_MINOR_VERSION;
const guint gtk_micro_version = GTK_MICRO_VERSION;
@@ -122,9 +124,6 @@
static GSList *main_loops = NULL; /* stack of currently executing main loops */
-static GSList *grabs = NULL; /* A stack of unique grabs. The grabbing
- * widget is the first one on the list.
- */
static GList *init_functions = NULL; /* A list of init functions.
*/
static GList *quit_functions = NULL; /* A list of quit functions.
@@ -750,6 +749,7 @@
{
GtkWidget *event_widget;
GtkWidget *grab_widget;
+ GtkWindowGroup *window_group;
GdkEvent *next_event;
GList *tmp_list;
@@ -814,12 +814,14 @@
* gtk_current_event_get().
*/
current_events = g_list_prepend (current_events, event);
+
+ window_group = gtk_main_get_window_group (event_widget);
/* If there is a grab in effect...
*/
- if (grabs)
+ if (window_group->grabs)
{
- grab_widget = grabs->data;
+ grab_widget = window_group->grabs->data;
/* If the grab widget is an ancestor of the event widget
* then we send the event to the original event widget.
@@ -851,7 +853,7 @@
case GDK_DELETE:
gtk_widget_ref (event_widget);
- if ((!grabs || gtk_widget_get_toplevel (grabs->data) == event_widget) &&
+ if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
!gtk_widget_event (event_widget, event))
gtk_widget_destroy (event_widget);
gtk_widget_unref (event_widget);
@@ -970,39 +972,131 @@
return FALSE;
}
+static GtkWindowGroup *
+gtk_main_get_window_group (GtkWidget *widget)
+{
+ GtkWidget *toplevel = NULL;
+
+ if (widget)
+ toplevel = gtk_widget_get_toplevel (widget);
+
+ if (toplevel && GTK_IS_WINDOW (toplevel))
+ return _gtk_window_get_group (GTK_WINDOW (toplevel));
+ else
+ return _gtk_window_get_group (NULL);
+}
+
+typedef struct
+{
+ gboolean was_grabbed;
+ GtkWidget *grab_widget;
+} GrabNotifyInfo;
+
+static void
+gtk_grab_notify_foreach (GtkWidget *child,
+ gpointer data)
+
+{
+ GrabNotifyInfo *info = data;
+
+ if (child != info->grab_widget)
+ {
+ g_object_ref (G_OBJECT (child));
+
+ gtk_signal_emit_by_name (GTK_OBJECT (child), "grab_notify", info->was_grabbed);
+
+ if (GTK_IS_CONTAINER (child))
+ gtk_container_foreach (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
+
+ g_object_unref (G_OBJECT (child));
+ }
+}
+
+static void
+gtk_grab_notify (GtkWindowGroup *group,
+ GtkWidget *grab_widget,
+ gboolean was_grabbed)
+{
+ GList *toplevels;
+ GrabNotifyInfo info;
+
+ info.grab_widget = grab_widget;
+ info.was_grabbed = was_grabbed;
+
+ g_object_ref (group);
+ g_object_ref (grab_widget);
+
+ toplevels = gtk_window_list_toplevels ();
+ g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
+
+ while (toplevels)
+ {
+ GtkWindow *toplevel = toplevels->data;
+ toplevels = g_list_delete_link (toplevels, toplevels);
+
+ if (group == toplevel->group)
+ gtk_container_foreach (GTK_CONTAINER (toplevel), gtk_grab_notify_foreach, &info);
+ g_object_unref (toplevel);
+ }
+
+ g_object_unref (group);
+ g_object_unref (grab_widget);
+}
+
void
gtk_grab_add (GtkWidget *widget)
{
+ GtkWindowGroup *group;
+ gboolean was_grabbed;
+
g_return_if_fail (widget != NULL);
- if (!GTK_WIDGET_HAS_GRAB (widget))
+ if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget))
{
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
- grabs = g_slist_prepend (grabs, widget);
+ group = gtk_main_get_window_group (widget);
+
+ was_grabbed = (group->grabs != NULL);
+
gtk_widget_ref (widget);
+ group->grabs = g_slist_prepend (group->grabs, widget);
+
+ if (!was_grabbed)
+ gtk_grab_notify (group, widget, FALSE);
}
}
GtkWidget*
gtk_grab_get_current (void)
{
- if (grabs)
- return GTK_WIDGET (grabs->data);
+ GtkWindowGroup *group;
+
+ group = gtk_main_get_window_group (NULL);
+
+ if (group->grabs)
+ return GTK_WIDGET (group->grabs->data);
return NULL;
}
void
gtk_grab_remove (GtkWidget *widget)
{
+ GtkWindowGroup *group;
+
g_return_if_fail (widget != NULL);
if (GTK_WIDGET_HAS_GRAB (widget))
{
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
+
+ group = gtk_main_get_window_group (widget);
+ group->grabs = g_slist_remove (group->grabs, widget);
- grabs = g_slist_remove (grabs, widget);
gtk_widget_unref (widget);
+
+ if (!group->grabs)
+ gtk_grab_notify (group, widget, TRUE);
}
}
Index: gtk/gtkplug.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkplug.c,v
retrieving revision 1.25
diff -u -r1.25 gtkplug.c
--- gtk/gtkplug.c 2001/06/08 18:09:34 1.25
+++ gtk/gtkplug.c 2001/06/08 22:02:09
@@ -119,10 +119,6 @@
window->type = GTK_WINDOW_TOPLEVEL;
window->auto_shrink = TRUE;
-
-#if 0
- gtk_window_set_grab_group (window, window);
-#endif
}
void
@@ -168,10 +164,11 @@
plug->socket_window = NULL;
}
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.221
diff -u -r1.221 gtkwidget.c
--- gtk/gtkwidget.c 2001/06/08 18:09:34 1.221
+++ gtk/gtkwidget.c 2001/06/08 22:02:10
@@ -65,6 +65,7 @@
HIERARCHY_CHANGED,
STYLE_SET,
DIRECTION_CHANGED,
+ GRAB_NOTIFY,
ADD_ACCELERATOR,
REMOVE_ACCELERATOR,
ACTIVATE_MNEMONIC,
@@ -632,6 +633,14 @@
gtk_marshal_VOID__ENUM,
GTK_TYPE_NONE, 1,
GTK_TYPE_TEXT_DIRECTION);
+ widget_signals[GRAB_NOTIFY] =
+ gtk_signal_new ("grab_notify",
+ GTK_RUN_FIRST,
+ GTK_CLASS_TYPE (object_class),
+ GTK_SIGNAL_OFFSET (GtkWidgetClass, grab_notify),
+ gtk_marshal_VOID__BOOLEAN,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_BOOL);
widget_signals[ADD_ACCELERATOR] =
gtk_accel_group_create_add (GTK_CLASS_TYPE (object_class), GTK_RUN_LAST,
GTK_SIGNAL_OFFSET (GtkWidgetClass, add_accelerator));
@@ -5287,7 +5296,12 @@
if (old_state != GTK_WIDGET_STATE (widget))
{
gtk_widget_ref (widget);
+
+ if (!GTK_WIDGET_IS_SENSITIVE (widget) && GTK_HAS_GRAB (widget))
+ gtk_grab_remove (widget);
+
gtk_signal_emit (GTK_OBJECT (widget), widget_signals[STATE_CHANGED], old_state);
+
if (GTK_IS_CONTAINER (widget))
{
Index: gtk/gtkwidget.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.h,v
retrieving revision 1.109
diff -u -r1.109 gtkwidget.h
--- gtk/gtkwidget.h 2001/06/08 18:09:34 1.109
+++ gtk/gtkwidget.h 2001/06/08 22:02:10
@@ -258,6 +258,8 @@
GtkStyle *previous_style);
void (* direction_changed) (GtkWidget *widget,
GtkTextDirection previous_direction);
+ void (* grab_notify) (GtkWidget *widget,
+ gboolean was_grabbed);
/* accelerators */
void (* add_accelerator) (GtkWidget *widget,
Index: gtk/gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.121
diff -u -r1.121 gtkwindow.c
--- gtk/gtkwindow.c 2001/06/08 18:09:34 1.121
+++ gtk/gtkwindow.c 2001/06/08 22:02:10
@@ -1599,6 +1599,9 @@
gtk_widget_unref (GTK_WIDGET (window));
}
+ if (window->group)
+ gtk_window_group_remove_window (window->group, window);
+
GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
@@ -3159,8 +3162,6 @@
}
}
-
-
/**
* gtk_window_present:
* @window: a #GtkWindow
@@ -3606,4 +3607,146 @@
button,
root_x, root_y,
timestamp);
+}
+
+
+static void
+gtk_window_group_class_init (GtkWindowGroupClass *klass)
+{
+}
+
+GtkType
+gtk_window_group_get_type (void)
+{
+ static GtkType window_group_type = 0;
+
+ if (!window_group_type)
+ {
+ static const GTypeInfo window_group_info =
+ {
+ sizeof (GtkWindowGroupClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gtk_window_group_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GtkWindowGroup),
+ 16, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ window_group_type = g_type_register_static (G_TYPE_OBJECT, "GtkWindowGroup", &window_group_info, 0);
+ }
+
+ return window_group_type;
+}
+
+/**
+ * gtk_window_group_new:
+ *
+ * Create a new #GtkWindowGroup object. Grabs added with
+ * gtk_window_grab_add() only affect windows within the
+ * same #GtkWindowGroup
+ *
+ * Return value:
+ **/
+GtkWindowGroup *
+gtk_window_group_new (void)
+{
+ return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
+}
+
+static void
+window_group_cleanup_grabs (GtkWindowGroup *group,
+ GtkWindow *window)
+{
+ GSList *tmp_list;
+ GSList *to_remove = NULL;
+
+ tmp_list = window_group->grabs;
+ while (tmp_list)
+ {
+ if (gtk_widget_get_toplevel (tmp_list->data) == window)
+ to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
+ tmp_list = tmp_list->next;
+ }
+
+ while (to_remove)
+ {
+ gtk_grab_remove (to_remove->data);
+ g_object_unref (to_remove->data);
+ to_remove = g_slist_delete_link (to_remove, to_remove);
+ }
+}
+
+/**
+ * gtk_window_group_add_widget:
+ * @window_group: a #GtkWindowGroup
+ * @window: the #GtkWindow to add
+ *
+ * Add a window to a #GtkWindowGroup.
+ **/
+void
+gtk_window_group_add_window (GtkWindowGroup *window_group,
+ GtkWindow *window)
+{
+ g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ if (window->group != window_group)
+ {
+ g_object_ref (window);
+ g_object_ref (window_group);
+
+ if (window->group)
+ gtk_window_group_remove_window (window->group, window);
+ else
+ window_group_cleanup_grabs (_gtk_window_get_group (NULL), window);
+
+ window->group = window_group;
+
+ g_object_unref (window);
+ }
+}
+
+/**
+ * gtk_window_group_remove_window:
+ * @window_group: a #GtkWindowGroup
+ * @window: the #GtkWindow to remove
+ *
+ * Removes a window from a #GtkWindowGroup.
+ **/
+void
+gtk_window_group_remove_window (GtkWindowGroup *window_group,
+ GtkWindow *window)
+{
+ g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
+ g_return_if_fail (GTK_IS_WIDGET (window));
+ g_return_if_fail (window->group == window_group);
+
+ g_object_ref (window);
+
+ window_group_cleanup_grabs (window_group, window);
+ window->group = NULL;
+
+ g_object_unref (G_OBJECT (window_group));
+ g_object_unref (window);
+}
+
+/* Return the group for the window or the default group
+ */
+GtkWindowGroup *
+_gtk_window_get_group (GtkWindow *window)
+{
+ if (window && window->group)
+ return window->group;
+ else
+ {
+ static GtkWindowGroup *default_group = NULL;
+
+ if (!default_group)
+ default_group = gtk_window_group_new ();
+
+ return default_group;
+ }
}
Index: gtk/gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.40
diff -u -r1.40 gtkwindow.h
--- gtk/gtkwindow.h 2001/04/26 14:42:35 1.40
+++ gtk/gtkwindow.h 2001/06/08 22:02:10
@@ -50,6 +50,8 @@
typedef struct _GtkWindow GtkWindow;
typedef struct _GtkWindowClass GtkWindowClass;
typedef struct _GtkWindowGeometryInfo GtkWindowGeometryInfo;
+typedef struct _GtkWindowGroup GtkWindowGroup;
+typedef struct _GtkWindowGroupClass GtkWindowGroupClass;
struct _GtkWindow
{
@@ -65,6 +67,7 @@
GtkWindow *transient_parent;
GtkWindowGeometryInfo *geometry_info;
GdkWindow *frame;
+ GtkWindowGroup *group;
guint16 resize_count;
@@ -123,7 +126,25 @@
GtkDirectionType direction);
};
+#define GTK_TYPE_WINDOW_GROUP (gtk_window_group_get_type ())
+#define GTK_WINDOW_GROUP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_WINDOW_GROUP, GtkWindowGroup))
+#define GTK_WINDOW_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WINDOW_GROUP, GtkWindowGroupClass))
+#define GTK_IS_WINDOW_GROUP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GTK_TYPE_WINDOW_GROUP))
+#define GTK_IS_WINDOW_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WINDOW_GROUP))
+#define GTK_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WINDOW_GROUP, GtkWindowGroupClass))
+struct _GtkWindowGroup
+{
+ GObject parent_instance;
+
+ GSList *grabs;
+};
+
+struct _GtkWindowGroupClass
+{
+ GObjectClass parent_class;
+};
+
GtkType gtk_window_get_type (void) G_GNUC_CONST;
GtkWidget* gtk_window_new (GtkWindowType type);
void gtk_window_set_title (GtkWindow *window,
@@ -175,9 +196,9 @@
gboolean setting);
/* If window is set modal, input will be grabbed when show and released when hide */
-void gtk_window_set_modal (GtkWindow *window,
- gboolean modal);
-GList* gtk_window_list_toplevels (void);
+void gtk_window_set_modal (GtkWindow *window,
+ gboolean modal);
+GList* gtk_window_list_toplevels (void);
void gtk_window_add_mnemonic (GtkWindow *window,
guint keyval,
@@ -225,23 +248,34 @@
gint width,
gint height);
+/* Window groups
+ */
+GType gtk_window_group_get_type (void) G_GNUC_CONST;;
+
+GtkWindowGroup * gtk_window_group_new (void);
+void gtk_window_group_add_window (GtkWindowGroup *window_group,
+ GtkWindow *window);
+void gtk_window_group_remove_window (GtkWindowGroup *window_group,
+ GtkWindow *window);
+
/* --- internal functions --- */
-void gtk_window_set_focus (GtkWindow *window,
- GtkWidget *focus);
-void gtk_window_set_default (GtkWindow *window,
- GtkWidget *defaultw);
-void gtk_window_remove_embedded_xid (GtkWindow *window,
- guint xid);
-void gtk_window_add_embedded_xid (GtkWindow *window,
- guint xid);
-void _gtk_window_reposition (GtkWindow *window,
- gint x,
- gint y);
-void _gtk_window_constrain_size (GtkWindow *window,
- gint width,
- gint height,
- gint *new_width,
- gint *new_height);
+void gtk_window_set_focus (GtkWindow *window,
+ GtkWidget *focus);
+void gtk_window_set_default (GtkWindow *window,
+ GtkWidget *defaultw);
+void gtk_window_remove_embedded_xid (GtkWindow *window,
+ guint xid);
+void gtk_window_add_embedded_xid (GtkWindow *window,
+ guint xid);
+void _gtk_window_reposition (GtkWindow *window,
+ gint x,
+ gint y);
+void _gtk_window_constrain_size (GtkWindow *window,
+ gint width,
+ gint height,
+ gint *new_width,
+ gint *new_height);
+GtkWindowGroup *_gtk_window_get_group (GtkWindow *window);
#ifdef __cplusplus
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]