Grabbing pointer and keyboard correctly



In response to:

 http://bugzilla.gnome.org/show_bug.cgi?id=75748

Which complains about the gnome-date-edit window not getting
the focus, and attributes it to GTK+ (though gnome-date-edit
wasn't even grabbing the keyboard...) I made up the following
patch.

This code corresponds to how GtkMenu does popups (though is
considerably simpler) and people would be advised to copy
this in other places where a "pseudo-menu" is needed.

Regards,
                                        Owen

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/libgnomeui/ChangeLog,v
retrieving revision 1.131
diff -u -p -r1.131 ChangeLog
--- ChangeLog	21 Mar 2002 06:52:41 -0000	1.131
+++ ChangeLog	21 Mar 2002 21:52:07 -0000
@@ -1,3 +1,19 @@
+Thu Mar 21 16:47:55 2002  Owen Taylor  <otaylor redhat com>
+
+	* libgnomeui/gnome-dateedit.c (select_clicked): 
+	Fix grabbing so that:
+
+	 - it grabs the keyboard to the window, not just the mouse
+	 - it handles failure, and doesn't leave a window up
+	   with no grab.
+	 - it grabs before popping up the window. (Not really
+	   needed here because we pop up on button release, but 
+	   generally a good thing.)
+
+	* libgnomeui/gnome-dateedit.c (hide_popup): Don't
+	need to ungrab the pointer, since hiding a window
+	automatically ungrabs.
+
 2002-03-20  Cody Russell  <cody jhu edu>
 
 	* libgnomeui/gnome-icon-list.c: Fix a warning that appears with
Index: libgnomeui/gnome-dateedit.c
===================================================================
RCS file: /cvs/gnome/libgnomeui/libgnomeui/gnome-dateedit.c,v
retrieving revision 1.68
diff -u -p -r1.68 gnome-dateedit.c
--- libgnomeui/gnome-dateedit.c	26 Feb 2002 18:28:45 -0000	1.68
+++ libgnomeui/gnome-dateedit.c	21 Mar 2002 21:52:07 -0000
@@ -112,7 +112,6 @@ hide_popup (GnomeDateEdit *gde)
 {
 	gtk_widget_hide (gde->_priv->cal_popup);
 	gtk_grab_remove (gde->_priv->cal_popup);
-	gdk_pointer_ungrab (GDK_CURRENT_TIME);
 }
 
 static void
@@ -237,6 +236,26 @@ position_popup (GnomeDateEdit *gde)
 	gtk_window_move (GTK_WINDOW (gde->_priv->cal_popup), x, y);
 }
 
+static gboolean
+popup_grab_on_window (GdkWindow *window,
+		      guint32    activate_time)
+{
+	if ((gdk_pointer_grab (window, TRUE,
+			       GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+			       GDK_POINTER_MOTION_MASK,
+			       NULL, NULL, activate_time) == 0)) {
+		if (gdk_keyboard_grab (window, TRUE,
+				       activate_time) == 0)
+			return TRUE;
+		else {
+			gdk_pointer_ungrab (activate_time);
+			return FALSE;
+		}
+	}
+
+	return FALSE;
+}
+
 static void
 select_clicked (GtkWidget *widget, GnomeDateEdit *gde)
 {
@@ -244,6 +263,15 @@ select_clicked (GtkWidget *widget, Gnome
 	GDate *date;
 	int month;
 
+	/* Temporarily grab pointer and keyboard on a window we know exists; we
+	 * do this so that the grab (with owner events == TRUE) affects
+	 * events generated when the window is mapped, such as enter
+	 * notify events on subwidgets. If the grab fails, bail out.
+	 */
+	if (!popup_grab_on_window (widget->window,
+				   gtk_get_current_event_time ()))
+		return;
+	
 	str = gtk_entry_get_text (GTK_ENTRY (gde->_priv->date_entry));
 
 	date = g_date_new ();
@@ -285,16 +313,16 @@ select_clicked (GtkWidget *widget, Gnome
 
         position_popup (gde);
 
+	gtk_grab_add (gde->_priv->cal_popup);
+
 	gtk_widget_show (gde->_priv->cal_popup);
 	gtk_widget_grab_focus (gde->_priv->calendar);
 
-	gtk_grab_add (gde->_priv->cal_popup);
-
-	gdk_pointer_grab (gde->_priv->cal_popup->window, TRUE,
-			  (GDK_BUTTON_PRESS_MASK
-			   | GDK_BUTTON_RELEASE_MASK
-			   | GDK_POINTER_MOTION_MASK),
-			  NULL, NULL, GDK_CURRENT_TIME);
+	/* Now transfer our grabs to the popup window; this
+	 * should always succeed.
+	 */
+	popup_grab_on_window (gde->_priv->cal_popup->window,
+			      gtk_get_current_event_time ());
 }
 
 typedef struct {



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