[perl-Gtk2] Gtk2::Menu: trap exceptions in popup callbacks



commit f99e67667d6453f753f8588ca837984752521622
Author: Kevin Ryde <user42 zip com au>
Date:   Sun Apr 25 17:11:33 2010 +0200

    Gtk2::Menu: trap exceptions in popup callbacks
    
    Uncaught exceptions in a popup callback can result in persistent mouse and
    keyboard grabs, locking the screen until the program is killed.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=613973

 t/GtkMenu.t   |   19 ++++++++++++++++++-
 xs/GtkMenu.xs |   38 ++++++++++++++++++++++++--------------
 2 files changed, 42 insertions(+), 15 deletions(-)
---
diff --git a/t/GtkMenu.t b/t/GtkMenu.t
index 27b4cd7..61874bd 100644
--- a/t/GtkMenu.t
+++ b/t/GtkMenu.t
@@ -8,7 +8,7 @@
 # 	- rm
 #########################
 
-use Gtk2::TestHelper tests => 64;
+use Gtk2::TestHelper tests => 66;
 
 ok( my $menubar = Gtk2::MenuBar->new );
 
@@ -171,6 +171,23 @@ unless ($i_know_you) {
   is ($detach_func, undef, 'detach callback func freed after called');
 }
 
+{
+  my $popup_runs = 0;
+  my $saw_warning = '';
+  { local $SIG{__WARN__} = sub { $saw_warning = $_[0] };
+    $menu->popup(undef, undef, sub {
+                   $popup_runs = 1;
+                   die;
+                 }, undef, 1, 0);
+  }
+  diag "popup position runs=$popup_runs warn='$saw_warning'";
+  $menu->popdown;
+  ok ($popup_runs,
+      'popup positioning die() - popup runs');
+  ok ($saw_warning,
+      'popup positioning die() - die not fatal, turned into warning');
+}
+
 SKIP: {
 	skip 'new 2.14 stuff', 2
 		unless Gtk2->CHECK_VERSION(2, 14, 0);
diff --git a/xs/GtkMenu.xs b/xs/GtkMenu.xs
index 283e39b..ee6d20d 100644
--- a/xs/GtkMenu.xs
+++ b/xs/GtkMenu.xs
@@ -57,24 +57,34 @@ gtk2perl_menu_position_func (GtkMenu * menu,
 	if (callback->data)
 		XPUSHs (sv_2mortal (newSVsv (callback->data)));
 
-	PUTBACK;
-
-	n = call_sv (callback->func, G_ARRAY);
+	/* A die() from callback->func is suspected to be bad or very bad.
+	   Circa Gtk 2.18 a jump out of $menu->popup seems to leave an X
+	   grab with no way to get rid of it (no keyboard Esc, and no mouse
+	   click handlers).  The position func can also be called later for
+	   things like resizing or move to a different GdkScreen, and such a
+	   call might come straight from the main loop, where a die() would
+	   jump out of Gtk2->main.  */
 
+	PUTBACK;
+	n = call_sv (callback->func, G_ARRAY | G_EVAL);
 	SPAGAIN;
 
-	if (n < 2 || n > 3)
-		croak ("menu position callback must return two integers "
-		       "(x, and y) or two integers and a boolean (x, y, and "
-		       "push_in)");
-
-	/* POPs and POPi take things off the *end* of the stack! */
-	if (n > 2) {
-		SV *sv = POPs;
-		*push_in = sv_2bool (sv);
+	if (SvTRUE (ERRSV)) {
+		g_warning ("menu position callback ignoring error: %s",
+			   SvPVutf8_nolen (ERRSV));
+	} else if (n < 2 || n > 3) {
+		g_warning ("menu position callback must return two integers "
+			   "(x, and y) or two integers and a boolean "
+			   "(x, y, and push_in)");
+	} else {
+		/* POPs and POPi take things off the *end* of the stack! */
+		if (n > 2) {
+			SV *sv = POPs;
+			*push_in = sv_2bool (sv);
+		}
+		if (n > 1) *y = POPi;
+		if (n > 0) *x = POPi;
 	}
-	if (n > 1) *y = POPi;
-	if (n > 0) *x = POPi;
 
 	PUTBACK;
 	FREETMPS;



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