]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkdisplay-x11.c
[introspection] add transfer none annotation to gdk_keyval_name return
[~andy/gtk] / gdk / x11 / gdkdisplay-x11.c
index 7195c0118551c967cf7a063f61495d40052f339b..2bdfd454020194dc5c4f402a9fe3312eedd4d737 100644 (file)
 
 #include "config.h"
 
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
+#include "gdkdisplay-x11.h"
 
-#include <glib.h>
 #include "gdkx.h"
 #include "gdkasync.h"
 #include "gdkdisplay.h"
-#include "gdkdisplay-x11.h"
 #include "gdkeventsource.h"
 #include "gdkeventtranslator.h"
 #include "gdkscreen.h"
 #include "gdkdevicemanager.h"
 #include "xsettings-client.h"
 
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
 #include <X11/Xatom.h>
 
 #ifdef HAVE_XKB
 #include <X11/extensions/Xrandr.h>
 #endif
 
+typedef struct _GdkErrorTrap  GdkErrorTrap;
+
+struct _GdkErrorTrap
+{
+  /* Next sequence when trap was pushed, i.e. first sequence to
+   * ignore
+   */
+  gulong start_sequence;
+
+  /* Next sequence when trap was popped, i.e. first sequence
+   * to not ignore. 0 if trap is still active.
+   */
+  gulong end_sequence;
+
+  /* Most recent error code within the sequence */
+  int error_code;
+};
 
 static void   gdk_display_x11_dispose            (GObject            *object);
 static void   gdk_display_x11_finalize           (GObject            *object);
@@ -247,7 +266,7 @@ gdk_check_wm_desktop_changed (GdkWindow *window)
                       0, G_MAXLONG, False, XA_CARDINAL, &type,
                       &format, &nitems,
                       &bytes_after, &data);
-  gdk_error_trap_pop ();
+  gdk_error_trap_pop_ignored ();
 
   if (type != None)
     {
@@ -288,7 +307,7 @@ gdk_check_wm_state_changed (GdkWindow *window)
                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
                      0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
                      &bytes_after, &data);
-  gdk_error_trap_pop ();
+  gdk_error_trap_pop_ignored ();
 
   if (type != None)
     {
@@ -717,7 +736,7 @@ gdk_display_x11_translate_event (GdkEventTranslator *translator,
                  event->configure.x = tx;
                  event->configure.y = ty;
                }
-             gdk_error_trap_pop ();
+             gdk_error_trap_pop_ignored ();
            }
          else
            {
@@ -1136,7 +1155,8 @@ _gdk_input_init (GdkDisplay *display)
       if (device->source == GDK_SOURCE_KEYBOARD)
         continue;
 
-      display_x11->input_devices = g_list_prepend (display_x11->input_devices, l->data);
+      display_x11->input_devices = g_list_prepend (display_x11->input_devices,
+                                                   g_object_ref (l->data));
     }
 
   g_list_free (list);
@@ -1158,7 +1178,8 @@ _gdk_input_init (GdkDisplay *display)
     }
 
   /* Add the core pointer to the devices list */
-  display_x11->input_devices = g_list_prepend (display_x11->input_devices, display->core_pointer);
+  display_x11->input_devices = g_list_prepend (display_x11->input_devices,
+                                               g_object_ref (display->core_pointer));
 
   g_list_free (list);
 }
@@ -1197,7 +1218,6 @@ gdk_display_open (const gchar *display_name)
   display = g_object_new (GDK_TYPE_DISPLAY_X11, NULL);
   display_x11 = GDK_DISPLAY_X11 (display);
 
-  display_x11->use_xshm = TRUE;
   display_x11->xdisplay = xdisplay;
 
 #ifdef HAVE_X11R6  
@@ -1258,8 +1278,6 @@ gdk_display_open (const gchar *display_name)
 
   display_x11->leader_window_title_set = FALSE;
 
-  display_x11->have_render = GDK_UNKNOWN;
-
 #ifdef HAVE_XFIXES
   if (XFixesQueryExtension (display_x11->xdisplay, 
                            &display_x11->xfixes_event_base, 
@@ -1330,7 +1348,6 @@ gdk_display_open (const gchar *display_name)
     XQueryPointer (display_x11->xdisplay, 
                   GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window,
                   &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
-    gdk_flush ();
     if (G_UNLIKELY (gdk_error_trap_pop () == BadWindow)) 
       {
        g_warning ("Connection to display %s appears to be untrusted. Pointer and keyboard grabs and inter-client communication may not work as expected.", gdk_display_get_name (display));
@@ -1427,7 +1444,6 @@ gdk_display_open (const gchar *display_name)
   }
 #endif
 
-  _gdk_windowing_image_init (display);
   _gdk_input_init (display);
   _gdk_dnd_init (display);
 
@@ -1435,8 +1451,7 @@ gdk_display_open (const gchar *display_name)
     _gdk_x11_screen_setup (display_x11->screens[i]);
 
   g_signal_emit_by_name (display, "opened");
-  g_signal_emit_by_name (gdk_display_manager_get(),
-                        "display_opened", display);
+  g_signal_emit_by_name (gdk_display_manager_get (), "display-opened", display);
 
   return display;
 }
@@ -1896,6 +1911,21 @@ gdk_display_x11_finalize (GObject *object)
 
   XCloseDisplay (display_x11->xdisplay);
 
+  /* error traps */
+  while (display_x11->error_traps != NULL)
+    {
+      GdkErrorTrap *trap = display_x11->error_traps->data;
+
+      display_x11->error_traps =
+        g_slist_delete_link (display_x11->error_traps,
+                             display_x11->error_traps);
+
+      if (trap->end_sequence == 0)
+        g_warning ("Display finalized with an unpopped error trap");
+
+      g_slice_free (GdkErrorTrap, trap);
+    }
+
   G_OBJECT_CLASS (_gdk_display_x11_parent_class)->finalize (object);
 }
 
@@ -1972,12 +2002,7 @@ _gdk_windowing_set_default_display (GdkDisplay *display)
   const gchar *startup_id;
   
   if (!display)
-    {
-      gdk_display = NULL;
-      return;
-    }
-
-  gdk_display = GDK_DISPLAY_XDISPLAY (display);
+    return;
 
   g_free (display_x11->startup_notification_id);
   display_x11->startup_notification_id = NULL;
@@ -1985,45 +2010,15 @@ _gdk_windowing_set_default_display (GdkDisplay *display)
   startup_id = g_getenv ("DESKTOP_STARTUP_ID");
   if (startup_id && *startup_id != '\0')
     {
-      gchar *time_str;
-
       if (!g_utf8_validate (startup_id, -1, NULL))
-       g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
+        g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
       else
-       display_x11->startup_notification_id = g_strdup (startup_id);
-
-      /* Find the launch time from the startup_id, if it's there.  Newer spec
-       * states that the startup_id is of the form <unique>_TIME<timestamp>
-       */
-      time_str = g_strrstr (startup_id, "_TIME");
-      if (time_str != NULL)
-        {
-         gulong retval;
-          gchar *end;
-          errno = 0;
-
-          /* Skip past the "_TIME" part */
-          time_str += 5;
-
-          retval = strtoul (time_str, &end, 0);
-          if (end != time_str && errno == 0)
-            display_x11->user_time = retval;
-        }
+        gdk_x11_display_set_startup_notification_id (display, startup_id);
       
       /* Clear the environment variable so it won't be inherited by
        * child processes and confuse things.  
        */
       g_unsetenv ("DESKTOP_STARTUP_ID");
-
-      /* Set the startup id on the leader window so it
-       * applies to all windows we create on this display
-       */
-      XChangeProperty (display_x11->xdisplay,
-                      display_x11->leader_window,
-                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
-                      gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
-                      PropModeReplace,
-                      (guchar *)startup_id, strlen (startup_id));
     }
 }
 
@@ -2388,7 +2383,7 @@ gdk_display_store_clipboard (GdkDisplay    *display,
                         GDK_WINDOW_XID (clipboard_window), time_);
       
     }
-  gdk_error_trap_pop ();
+  gdk_error_trap_pop_ignored ();
 
 }
 
@@ -2462,6 +2457,69 @@ gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
   return GDK_DISPLAY_X11 (display)->startup_notification_id;
 }
 
+/**
+ * gdk_x11_display_set_startup_notification_id:
+ * @display: a #GdkDisplay
+ * @startup_id: the startup notification ID (must be valid utf8)
+ *
+ * Sets the startup notification ID for a display.
+ *
+ * This is usually taken from the value of the DESKTOP_STARTUP_ID
+ * environment variable, but in some cases (such as the application not
+ * being launched using exec()) it can come from other sources.
+ *
+ * If the ID contains the string "_TIME" then the portion following that
+ * string is taken to be the X11 timestamp of the event that triggered
+ * the application to be launched and the GDK current event time is set
+ * accordingly.
+ *
+ * The startup ID is also what is used to signal that the startup is
+ * complete (for example, when opening a window or when calling
+ * gdk_notify_startup_complete()).
+ *
+ * Since: 3.0
+ **/
+void
+gdk_x11_display_set_startup_notification_id (GdkDisplay  *display,
+                                             const gchar *startup_id)
+{
+  GdkDisplayX11 *display_x11;
+  gchar *time_str;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  g_free (display_x11->startup_notification_id);
+  display_x11->startup_notification_id = g_strdup (startup_id);
+
+  /* Find the launch time from the startup_id, if it's there.  Newer spec
+   * states that the startup_id is of the form <unique>_TIME<timestamp>
+   */
+  time_str = g_strrstr (startup_id, "_TIME");
+  if (time_str != NULL)
+    {
+      gulong retval;
+      gchar *end;
+      errno = 0;
+
+      /* Skip past the "_TIME" part */
+      time_str += 5;
+
+      retval = strtoul (time_str, &end, 0);
+      if (end != time_str && errno == 0)
+        display_x11->user_time = retval;
+    }
+
+  /* Set the startup id on the leader window so it
+   * applies to all windows we create on this display
+   */
+  XChangeProperty (display_x11->xdisplay,
+                   display_x11->leader_window,
+                   gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
+                   gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+                   PropModeReplace,
+                   (guchar *)startup_id, strlen (startup_id));
+}
+
 /**
  * gdk_display_supports_composite:
  * @display: a #GdkDisplay
@@ -2493,7 +2551,8 @@ gdk_display_supports_composite (GdkDisplay *display)
  * Returns the list of available input devices attached to @display.
  * The list is statically allocated and should not be freed.
  *
- * Return value: a list of #GdkDevice
+ * Return value: (transfer none) (element-type GdkDevice):
+ *     a list of #GdkDevice
  *
  * Since: 2.2
  *
@@ -2665,3 +2724,254 @@ gdk_x11_register_standard_event_type (GdkDisplay *display,
 
   display_x11->event_types = g_slist_prepend (display_x11->event_types, event_type);
 }
+
+/* compare X sequence numbers handling wraparound */
+#define SEQUENCE_COMPARE(a,op,b) (((long) (a) - (long) (b)) op 0)
+
+/* delivers an error event from the error handler in gdkmain-x11.c */
+void
+_gdk_x11_display_error_event (GdkDisplay  *display,
+                              XErrorEvent *error)
+{
+  GdkDisplayX11 *display_x11;
+  GSList *tmp_list;
+  gboolean ignore;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  ignore = FALSE;
+  for (tmp_list = display_x11->error_traps;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      GdkErrorTrap *trap;
+
+      trap = tmp_list->data;
+
+      if (SEQUENCE_COMPARE (trap->start_sequence, <=, error->serial) &&
+          (trap->end_sequence == 0 ||
+           SEQUENCE_COMPARE (trap->end_sequence, >, error->serial)))
+        {
+          ignore = TRUE;
+          trap->error_code = error->error_code;
+          break; /* only innermost trap gets the error code */
+        }
+    }
+
+  if (!ignore)
+    {
+      gchar buf[64];
+      gchar *msg;
+
+      XGetErrorText (display_x11->xdisplay, error->error_code, buf, 63);
+
+      msg =
+        g_strdup_printf ("The program '%s' received an X Window System error.\n"
+                         "This probably reflects a bug in the program.\n"
+                         "The error was '%s'.\n"
+                         "  (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
+                         "  (Note to programmers: normally, X errors are reported asynchronously;\n"
+                         "   that is, you will receive the error a while after causing it.\n"
+                         "   To debug your program, run it with the --sync command line\n"
+                         "   option to change this behavior. You can then get a meaningful\n"
+                         "   backtrace from your debugger if you break on the gdk_x_error() function.)",
+                         g_get_prgname (),
+                         buf,
+                         error->serial,
+                         error->error_code,
+                         error->request_code,
+                         error->minor_code);
+
+#ifdef G_ENABLE_DEBUG
+      g_error ("%s", msg);
+#else /* !G_ENABLE_DEBUG */
+      g_warning ("%s\n", msg);
+
+      exit (1);
+#endif /* G_ENABLE_DEBUG */
+    }
+}
+
+static void
+delete_outdated_error_traps (GdkDisplayX11 *display_x11)
+{
+  GSList *tmp_list;
+  gulong processed_sequence;
+
+  processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
+
+  tmp_list = display_x11->error_traps;
+  while (tmp_list != NULL)
+    {
+      GdkErrorTrap *trap = tmp_list->data;
+
+      if (trap->end_sequence != 0 &&
+          SEQUENCE_COMPARE (trap->end_sequence, <=, processed_sequence))
+        {
+          GSList *free_me = tmp_list;
+
+          tmp_list = tmp_list->next;
+          display_x11->error_traps =
+            g_slist_delete_link (display_x11->error_traps, free_me);
+          g_slice_free (GdkErrorTrap, trap);
+        }
+      else
+        {
+          tmp_list = tmp_list->next;
+        }
+    }
+}
+
+/**
+ * gdk_x11_display_error_trap_push:
+ * @display: a #GdkDisplay
+ *
+ * Begins a range of X requests on @display for which X error events
+ * will be ignored. Unignored errors (when no trap is pushed) will abort
+ * the application. Use gdk_x11_display_error_trap_pop() or
+ * gdk_x11_display_error_trap_pop_ignored()to lift a trap pushed
+ * with this function.
+ *
+ * See also gdk_error_trap_push() to push a trap on all displays.
+ *
+ * Since: 3.0
+ */
+void
+gdk_x11_display_error_trap_push (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11;
+  GdkErrorTrap *trap;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  delete_outdated_error_traps (display_x11);
+
+  /* set up the Xlib callback to tell us about errors */
+  _gdk_x11_error_handler_push ();
+
+  trap = g_slice_new0 (GdkErrorTrap);
+
+  trap->start_sequence = XNextRequest (display_x11->xdisplay);
+  trap->error_code = Success;
+
+  display_x11->error_traps =
+    g_slist_prepend (display_x11->error_traps, trap);
+}
+
+static gint
+gdk_x11_display_error_trap_pop_internal (GdkDisplay *display,
+                                         gboolean    need_code)
+{
+  GdkDisplayX11 *display_x11;
+  GdkErrorTrap *trap;
+  GSList *tmp_list;
+  int result;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  g_return_val_if_fail (display_x11->error_traps != NULL, Success);
+
+  /* Find the first trap that hasn't been popped already */
+  trap = NULL; /* quiet gcc */
+  for (tmp_list = display_x11->error_traps;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      trap = tmp_list->data;
+
+      if (trap->end_sequence == 0)
+        break;
+    }
+
+  g_return_val_if_fail (trap != NULL, Success);
+  g_assert (trap->end_sequence == 0);
+
+  /* May need to sync to fill in trap->error_code if we care about
+   * getting an error code.
+   */
+  if (need_code)
+    {
+      gulong processed_sequence;
+      gulong next_sequence;
+
+      next_sequence = XNextRequest (display_x11->xdisplay);
+      processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
+
+      /* If our last request was already processed, there is no point
+       * in syncing. i.e. if last request was a round trip (or even if
+       * we got an event with the serial of a non-round-trip)
+       */
+      if ((next_sequence - 1) != processed_sequence)
+        {
+          XSync (display_x11->xdisplay, False);
+        }
+
+      result = trap->error_code;
+    }
+  else
+    {
+      result = Success;
+    }
+
+  /* record end of trap, giving us a range of
+   * error sequences we'll ignore.
+   */
+  trap->end_sequence = XNextRequest (display_x11->xdisplay);
+
+  /* remove the Xlib callback */
+  _gdk_x11_error_handler_pop ();
+
+  /* we may already be outdated */
+  delete_outdated_error_traps (display_x11);
+
+  return result;
+}
+
+/**
+ * gdk_x11_display_error_trap_pop:
+ * @display: the display
+ *
+ * Pops the error trap pushed by gdk_x11_display_error_trap_push().
+ * Will XSync() if necessary and will always block until
+ * the error is known to have occurred or not occurred,
+ * so the error code can be returned.
+ *
+ * If you don't need to use the return value,
+ * gdk_x11_display_error_trap_pop_ignored() would be more efficient.
+ *
+ * See gdk_error_trap_pop() for the all-displays-at-once
+ * equivalent.
+ *
+ * Since: 3.0
+ *
+ * Return value: X error code or 0 on success
+ */
+gint
+gdk_x11_display_error_trap_pop (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY_X11 (display), Success);
+
+  return gdk_x11_display_error_trap_pop_internal (display, TRUE);
+}
+
+/**
+ * gdk_x11_display_error_trap_pop_ignored:
+ * @display: the display
+ *
+ * Pops the error trap pushed by gdk_x11_display_error_trap_push().
+ * Does not block to see if an error occurred; merely records the
+ * range of requests to ignore errors for, and ignores those errors
+ * if they arrive asynchronously.
+ *
+ * See gdk_error_trap_pop_ignored() for the all-displays-at-once
+ * equivalent.
+ *
+ * Since: 3.0
+ */
+void
+gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display)
+{
+  g_return_if_fail (GDK_IS_DISPLAY_X11 (display));
+
+  gdk_x11_display_error_trap_pop_internal (display, FALSE);
+}