Hiding the widget with the focus/default



I discovered a problem while while making GtkInputDialog 
multihead-aware.

Consider the following heirarchy

 A. GtkInputDialog
  \
   Vbox
    \
     B. Device control widgets
     |
     C. GtkLabel "No devices"

When we move the dialog from Display 1 (several devices) to 
Display 2 (no XInput devices), we hide B and show C.

So, the sequence looks like:

 unmap A
 unrealize A
 
  ::screen-changed ... hide B, show C

 realize A
 map A

Say the focus widget is inside B at the start of the sequence,
then it remains there. But when A is re-realized, the widgets
in C are not rerealized since they are not visible.

This causes the code in gtkwindow.c to send events to the focus
widget to break since there is:

  fevent->focus_change.window = g_object_ref (widget->window);

Now, we could simply change this to:

  fevent->focus_change.window = widget->window;
  if (fevent->focus_change.window)
    g_object_ref (fevent->focus_change.window);

But it strikes me as wrong to have the focus on a hidden window,
so I came up with the following patch which unsets the focus
from within widgets when they are hidden.

Unfortunately, we can't make this an invariant, since we need
to support:

 create_heirarchy
 grab_focus (some_widget_in_heirarchy)
 show_all (toplevel);

So, it's just a special-case hack. But it's probably a useful hack?

I'd appreciate it if anyone wanted to review this patch ... it's
actually smaller than it looks since most of it is just code
movement.

Thanks,
                                        Owen

Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.333
diff -u -p -r1.333 gtkwidget.c
--- gtk/gtkwidget.c	9 Nov 2002 16:46:24 -0000	1.333
+++ gtk/gtkwidget.c	12 Nov 2002 00:01:00 -0000
@@ -1522,41 +1522,12 @@ gtk_widget_unparent (GtkWidget *widget)
   g_object_freeze_notify (G_OBJECT (widget));
   nqueue = g_object_notify_queue_freeze (G_OBJECT (widget), _gtk_widget_child_property_notify_context);
 
-  /* unset focused and default children properly, this code
-   * should eventually move into some gtk_window_unparent_branch() or
-   * similar function.
-   */
-  
   toplevel = gtk_widget_get_toplevel (widget);
-  if (GTK_CONTAINER (widget->parent)->focus_child == widget)
-    {
-      gtk_container_set_focus_child (GTK_CONTAINER (widget->parent), NULL);
-
-      if (GTK_WIDGET_TOPLEVEL (toplevel))
-	{
-	  GtkWidget *child;
-      
-	  child = GTK_WINDOW (toplevel)->focus_widget;
-	  
-	  while (child && child != widget)
-	    child = child->parent;
-	  
-	  if (child == widget)
-	    gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
-	}
-    }
   if (GTK_WIDGET_TOPLEVEL (toplevel))
-    {
-      GtkWidget *child;
-      
-      child = GTK_WINDOW (toplevel)->default_widget;
-      
-      while (child && child != widget)
-	child = child->parent;
-      
-      if (child == widget)
-	gtk_window_set_default (GTK_WINDOW (toplevel), NULL);
-    }
+    _gtk_window_unset_focus_default (GTK_WINDOW (toplevel), widget);
+
+  if (GTK_CONTAINER (widget->parent)->focus_child == widget)
+    gtk_container_set_focus_child (GTK_CONTAINER (widget->parent), NULL);
 
   /* If we are unanchoring the child, we save around the toplevel
    * to emit hierarchy changed
@@ -1762,6 +1733,10 @@ gtk_widget_hide (GtkWidget *widget)
   
   if (GTK_WIDGET_VISIBLE (widget))
     {
+      GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+      if (toplevel != widget && GTK_WIDGET_TOPLEVEL (toplevel))
+	_gtk_window_unset_focus_default (GTK_WINDOW (toplevel), widget);
+
       g_object_ref (widget);
       g_signal_emit (widget, widget_signals[HIDE], 0);
       if (!GTK_WIDGET_TOPLEVEL (widget))
@@ -4709,7 +4684,16 @@ gtk_widget_set_child_visible (GtkWidget 
   if (is_visible)
     GTK_PRIVATE_SET_FLAG (widget, GTK_CHILD_VISIBLE);
   else
-    GTK_PRIVATE_UNSET_FLAG (widget, GTK_CHILD_VISIBLE);
+    {
+      GtkWidget *toplevel;
+      
+      GTK_PRIVATE_UNSET_FLAG (widget, GTK_CHILD_VISIBLE);
+
+      toplevel = gtk_widget_get_toplevel (widget);
+      if (toplevel != widget && GTK_WIDGET_TOPLEVEL (toplevel))
+	_gtk_window_unset_focus_default (GTK_WINDOW (toplevel), widget);
+    }
+
   if (widget->parent && GTK_WIDGET_REALIZED (widget->parent))
     {
       if (GTK_WIDGET_MAPPED (widget->parent) &&
Index: gtk/gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.232
diff -u -p -r1.232 gtkwindow.c
--- gtk/gtkwindow.c	8 Nov 2002 23:03:36 -0000	1.232
+++ gtk/gtkwindow.c	12 Nov 2002 00:01:00 -0000
@@ -4336,6 +4336,41 @@ gtk_window_real_set_focus (GtkWindow *wi
     }
 }
 
+/**
+ * _gtk_window_unset_focus_default:
+ * @window: a #GtkWindow
+ * @widget: a widget inside of @window
+ * 
+ * Checks whether the focus and default widgets of @window are
+ * @widget or a descendent of @widget, and if so, unset them.
+ **/
+void
+_gtk_window_unset_focus_default (GtkWindow *window,
+				 GtkWidget *widget)
+
+{
+  GtkWidget *child;
+      
+  if (GTK_CONTAINER (widget->parent)->focus_child == widget)
+    {
+      child = window->focus_widget;
+      
+      while (child && child != widget)
+	child = child->parent;
+  
+      if (child == widget)
+	gtk_window_set_focus (GTK_WINDOW (window), NULL);
+    }
+      
+  child = window->default_widget;
+      
+  while (child && child != widget)
+    child = child->parent;
+      
+  if (child == widget)
+    gtk_window_set_default (window, NULL);
+}
+
 /*********************************
  * Functions related to resizing *
  *********************************/
Index: gtk/gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.67
diff -u -p -r1.67 gtkwindow.h
--- gtk/gtkwindow.h	2 Nov 2002 05:37:04 -0000	1.67
+++ gtk/gtkwindow.h	12 Nov 2002 00:01:00 -0000
@@ -364,6 +364,9 @@ gboolean        _gtk_window_activate_key
 
 void            _gtk_window_set_has_toplevel_focus (GtkWindow *window,
 						    gboolean   has_toplevel_focus);
+void            _gtk_window_unset_focus_default    (GtkWindow *window,
+						    GtkWidget *widget);
+
 void            _gtk_window_set_is_active          (GtkWindow *window,
 						    gboolean   is_active);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]