Optional keybindings



As was discussed some earlier, here is a patch to allow keybindings to be
optional: if the action signal for a keybinding has a boolean return value
and returns FALSE, then it is as if that binding didn't exist.

This is needed in particular to fix a problem with activateable
widgets in notebooks. If you hit "space" with the focus on one, then
the space propagates up until it hits the notebook, which has a
binding for "Space" and eats the keystroke. (I think we also need
such binding for GtkPaned)

The notebook patch using this is attached; it makes bindings that should
only have an effect when the focus is on the tabs return FALSE if the
focus is on the child.

There are no compatibility problems with the binding change since action
signals with a boolean return were not previously allowed in this context.

It is a newly exported public API, but I don't see any way around
this ... we need the functionality internal to GTK+, and we can't hide it
since it is a matter of use of existing function calls than adding new
ones.

Regards,
                                        Owen

--- gtkbindings.c.pre	Tue Jan 15 15:59:26 2002
+++ gtkbindings.c	Tue Jan 15 16:23:11 2002
@@ -356,12 +356,13 @@ binding_compose_params (GtkObject       
   return valid;
 }
 
-static void
+static gboolean
 gtk_binding_entry_activate (GtkBindingEntry *entry,
 			    GtkObject	    *object)
 {
   GtkBindingSignal *sig;
   gboolean old_emission;
+  gboolean handled = FALSE;
   gint i;
   
   old_emission = entry->in_emission;
@@ -374,6 +375,7 @@ gtk_binding_entry_activate (GtkBindingEn
       GSignalQuery query;
       guint signal_id;
       GValue *params = NULL;
+      GValue return_val = { 0, };
       gchar *accelerator = NULL;
       
       signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
@@ -392,7 +394,7 @@ gtk_binding_entry_activate (GtkBindingEn
       
       g_signal_query (signal_id, &query);
       if (query.n_params != sig->n_args ||
-	  query.return_type != G_TYPE_NONE ||
+	  (query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) || 
 	  !binding_compose_params (object, sig->args, &query, &params))
 	{
 	  accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
@@ -417,8 +419,20 @@ gtk_binding_entry_activate (GtkBindingEn
       if (accelerator)
 	continue;
 
-      g_signal_emitv (params, signal_id, 0, NULL);
+      if (query.return_type == G_TYPE_BOOLEAN)
+	g_value_init (&return_val, G_TYPE_BOOLEAN);
+      
+      g_signal_emitv (params, signal_id, 0, &return_val);
 
+      if (query.return_type == G_TYPE_BOOLEAN)
+	{
+	  if (g_value_get_boolean (&return_val))
+	    handled = TRUE;
+	  g_value_unset (&return_val);
+	}
+      else
+	handled = TRUE;
+      
       for (i = 0; i < query.n_params + 1; i++)
 	g_value_unset (&params[i]);
       g_free (params);
@@ -432,6 +446,8 @@ gtk_binding_entry_activate (GtkBindingEn
   entry->in_emission = old_emission;
   if (entry->destroyed && !entry->in_emission)
     binding_entry_free (entry);
+
+  return handled;
 }
 
 GtkBindingSet*
@@ -515,11 +531,7 @@ gtk_binding_set_activate (GtkBindingSet	
   
   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
   if (entry)
-    {
-      gtk_binding_entry_activate (entry, object);
-      
-      return TRUE;
-    }
+    return gtk_binding_entry_activate (entry, object);
   
   return FALSE;
 }
@@ -815,9 +827,8 @@ binding_match_activate (GSList          
 
 	  binding_set = pspec->user_data;
 
-	  gtk_binding_entry_activate (binding_set->current, object);
-
-	  return TRUE;
+	  if (gtk_binding_entry_activate (binding_set->current, object))
+	    return TRUE;
 	}
     }
 
Index: gtknotebook.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtknotebook.c,v
retrieving revision 1.113
diff -u -p -r1.113 gtknotebook.c
--- gtknotebook.c	2002/01/15 17:40:44	1.113
+++ gtknotebook.c	2002/01/15 22:16:19
@@ -115,9 +115,9 @@ struct _GtkNotebookPage
 static void gtk_notebook_class_init          (GtkNotebookClass *klass);
 static void gtk_notebook_init                (GtkNotebook      *notebook);
 
-static void gtk_notebook_select_page         (GtkNotebook       *notebook,
-                                              gboolean           move_focus);
-static void gtk_notebook_focus_tab           (GtkNotebook       *notebook,
+static gboolean gtk_notebook_select_page     (GtkNotebook       *notebook,
+					      gboolean           move_focus);
+static gboolean gtk_notebook_focus_tab       (GtkNotebook       *notebook,
                                               GtkNotebookTab     type);
 static void gtk_notebook_change_current_page (GtkNotebook       *notebook,
 					      gint               offset);
@@ -448,7 +448,7 @@ gtk_notebook_class_init (GtkNotebookClas
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
                   NULL, NULL,
-                  _gtk_marshal_VOID__ENUM,
+                  _gtk_marshal_BOOLEAN__ENUM,
                   G_TYPE_NONE, 1,
                   GTK_TYPE_NOTEBOOK_TAB);
   notebook_signals[SELECT_PAGE] = 
@@ -457,8 +457,8 @@ gtk_notebook_class_init (GtkNotebookClas
                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                   G_STRUCT_OFFSET (GtkNotebookClass, select_page),
                   NULL, NULL,
-                  _gtk_marshal_VOID__BOOLEAN,
-                  G_TYPE_NONE, 1,
+                  _gtk_marshal_BOOLEAN__BOOLEAN,
+                  G_TYPE_BOOLEAN, 1,
                   G_TYPE_BOOLEAN);
   notebook_signals[CHANGE_CURRENT_PAGE] = 
     g_signal_new ("change_current_page",
@@ -467,7 +467,7 @@ gtk_notebook_class_init (GtkNotebookClas
                   G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
                   NULL, NULL,
                   gtk_marshal_VOID__INT,
-                  G_TYPE_NONE, 1,
+                  G_TYPE_BOOLEAN, 1,
                   G_TYPE_INT);
   
   binding_set = gtk_binding_set_by_class (object_class);
@@ -543,32 +543,45 @@ gtk_notebook_init (GtkNotebook *notebook
   notebook->have_visible_child = FALSE;
 }
 
-static void
+static gboolean
 gtk_notebook_select_page (GtkNotebook *notebook,
                           gboolean     move_focus)
 {
-  gtk_notebook_page_select (notebook, move_focus);
+  if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
+    {
+      gtk_notebook_page_select (notebook, move_focus);
+      return TRUE;
+    }
+  else
+    return FALSE;
 }
 
-static void
+static gboolean
 gtk_notebook_focus_tab (GtkNotebook       *notebook,
                         GtkNotebookTab     type)
 {
   GList *list;
-  
-  switch (type)
+
+  if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
     {
-    case GTK_NOTEBOOK_TAB_FIRST:
-      list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
-      if (list)
-	gtk_notebook_switch_focus_tab (notebook, list);
-      break;
-    case GTK_NOTEBOOK_TAB_LAST:
-      list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
-      if (list)
-	gtk_notebook_switch_focus_tab (notebook, list);
-      break;
+      switch (type)
+	{
+	case GTK_NOTEBOOK_TAB_FIRST:
+	  list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
+	  if (list)
+	    gtk_notebook_switch_focus_tab (notebook, list);
+	  break;
+	case GTK_NOTEBOOK_TAB_LAST:
+	  list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
+	  if (list)
+	    gtk_notebook_switch_focus_tab (notebook, list);
+	  break;
+	}
+
+      return TRUE;
     }
+  else
+    return FALSE;
 }
 
 static void
@@ -3773,7 +3786,7 @@ gtk_notebook_mnemonic_activate_switch_pa
     {
       GtkNotebookPage *page = list->data;
 
-      gtk_widget_grab_focus (notebook);	/* Do this first to avoid focusing new page */
+      gtk_widget_grab_focus (GTK_WIDGET (notebook));	/* Do this first to avoid focusing new page */
       gtk_notebook_switch_page (notebook, page,  -1);
       focus_tabs_in (notebook);
     }



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