[PATCH] On Linux, disable grabs if we appear to run in GNU gdb



If we are on Linux, use /proc/<pid>/cmdline to try to figure out if we
are running in GNU gdb. Disable grabs if we are, because with grabs
enabled there is a tendency to cause what appears as X11 freezes to an
untrained eye when breakpoints are hit while a grab is active. Allow
this behavior to be overridden by passing --force-grabs to the
program. Patch inspired by the Qt toolkit.
---
 gdk/gdk.c          |   39 +++++++++++++++++++++++++++++++++++++++
 gdk/gdk.h          |    1 +
 gdk/gdkglobals.c   |    1 +
 gdk/gdkinternals.h |    1 +
 gtk/gtkmain.c      |    2 ++
 5 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/gdk/gdk.c b/gdk/gdk.c
index da5d633..4b760c2 100644
--- a/gdk/gdk.c
+++ b/gdk/gdk.c
@@ -28,6 +28,9 @@
 
 #include <string.h>
 #include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
 #include "gdk.h"
 #include "gdkinternals.h"
@@ -159,6 +162,8 @@ static const GOptionEntry gdk_args[] = {
   { "screen",       0, 0, G_OPTION_ARG_INT,      &_gdk_screen_number,
     /* Description of --screen=SCREEN in --help output */      N_("X screen to use"),
     /* Placeholder in --screen=SCREEN in --help output */      N_("SCREEN") },
+  { "force-grabs",  0, 0, G_OPTION_ARG_NONE,     &_gdk_force_grabs,
+    /* Description of --force-grabs in --help output */        N_("Use grabs even if running in GNU gdb"), NULL },
 #ifdef G_ENABLE_DEBUG
   { "gdk-debug",    0, 0, G_OPTION_ARG_CALLBACK, gdk_arg_debug_cb,  
     /* Description of --gdk-debug=FLAGS in --help output */    N_("Gdk debugging flags to set"),
@@ -213,6 +218,40 @@ gdk_pre_parse_libgtk_only (void)
   _gdk_windowing_init ();  
 }
 
+void
+gdk_post_parse_libgtk_only (void)
+{
+#ifdef G_ENABLE_DEBUG
+  /* Handle automatic disable of grabs */
+#ifdef __linux__
+  if (!_gdk_force_grabs &&
+      !(_gdk_debug_flags & GDK_DEBUG_NOGRABS))
+    {
+      gchar *filename = g_strdup_printf ("/proc/%d/cmdline", getppid ());
+      gchar *contents = NULL;
+
+      if (g_file_get_contents (filename, &contents, NULL, NULL) &&
+          strstr (contents, "gdb"))
+        {
+          g_printerr ("GTK+: Appearing to run in GNU gdb (%s begins with '%s'),\n"
+                      "      grabs are now disabled to prevent problems when breakpoints are\n"
+                      "      hit in the middle of a grab. Note that with grabs disabled some\n"
+                      "      things can start to behave funny such as menus, scale buttons,\n"
+                      "      drag and drop and other things that relies on grabs. You can\n"
+                      "      override the disabling of grabs by passing --force-grabs to the\n"
+                      "      application. Note that grabs also can be disabled by setting the\n"
+                      "      environment variable GDK_DEBUG to 'nograbs' if GTK+ is compiled\n"
+                      "      with debug support.\n", filename, contents);
+          _gdk_debug_flags |= GDK_DEBUG_NOGRABS;
+        }
+
+      g_free (filename);
+      g_free (contents);
+    }
+#endif  /* __linux__ */
+#endif  /* G_ENABLE_DEBUG */
+}
+
   
 /**
  * gdk_parse_args:
diff --git a/gdk/gdk.h b/gdk/gdk.h
index d834bb1..3d14e50 100644
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -74,6 +74,7 @@ gboolean  gdk_init_check   	        (gint	   	*argc,
 					 gchar        ***argv);
 void gdk_add_option_entries_libgtk_only (GOptionGroup *group);
 void gdk_pre_parse_libgtk_only          (void);
+void gdk_post_parse_libgtk_only         (void);
 
 #ifndef GDK_DISABLE_DEPRECATED
 void  	  gdk_exit		   	(gint	    	 error_code);
diff --git a/gdk/gdkglobals.c b/gdk/gdkglobals.c
index 35e9908..8e052b4 100644
--- a/gdk/gdkglobals.c
+++ b/gdk/gdkglobals.c
@@ -38,6 +38,7 @@ gint                _gdk_error_warnings = TRUE;
 GList              *_gdk_default_filters = NULL;
 gchar              *_gdk_display_name = NULL;
 gint                _gdk_screen_number = -1;
+gboolean            _gdk_force_grabs = FALSE;
 gchar              *_gdk_display_arg_name = NULL;
 
 GSList             *_gdk_displays = NULL;
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index a668e68..794381d 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -282,6 +282,7 @@ extern GDestroyNotify _gdk_event_notify;
 extern GSList    *_gdk_displays;
 extern gchar     *_gdk_display_name;
 extern gint       _gdk_screen_number;
+extern gboolean   _gdk_force_grabs;
 extern gchar     *_gdk_display_arg_name;
 
 void      _gdk_events_queue  (GdkDisplay *display);
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 11aee08..484e585 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -686,6 +686,8 @@ do_post_parse_initialization (int    *argc,
 
   gettext_initialization ();
 
+  gdk_post_parse_libgtk_only ();
+
   if (g_fatal_warnings)
     {
       GLogLevelFlags fatal_mask;
-- 
1.6.2.5


--------------070001030604010704000701--


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