]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkdisplay.c
Explode gdkinternals.h into per-class private headers
[~andy/gtk] / gdk / gdkdisplay.c
index 74f08fc1704b965f519057d64739b3300b5c6099..0bfd150f01cf550d92f052f282bdf332379b59b3 100644 (file)
  */
 
 #include "config.h"
-#include <math.h>
-#include <glib.h>
-#include "gdk.h"               /* gdk_event_send_client_message() */
+
 #include "gdkdisplay.h"
+#include "gdkdisplayprivate.h"
+
+#include "gdkevents.h"
 #include "gdkwindowimpl.h"
 #include "gdkinternals.h"
 #include "gdkmarshalers.h"
 #include "gdkscreen.h"
-#include "gdkalias.h"
+
+#include <glib.h>
+#include <math.h>
+
+
+/**
+ * SECTION:gdkdisplay
+ * @Short_description: Controls the keyboard/mouse pointer grabs and a set of <type>GdkScreen</type>s
+ * @Title: GdkDisplay
+ *
+ * #GdkDisplay objects purpose are two fold:
+ * <itemizedlist>
+ * <listitem><para>
+ *   To grab/ungrab keyboard focus and mouse pointer
+ * </para></listitem>
+ * <listitem><para>
+ *   To manage and provide information about the #GdkScreen(s)
+ *   available for this #GdkDisplay
+ * </para></listitem>
+ * </itemizedlist>
+ *
+ * #GdkDisplay objects are the GDK representation of the X Display which can be
+ * described as <emphasis>a workstation consisting of a keyboard a pointing
+ * device (such as a mouse) and one or more screens</emphasis>.
+ * It is used to open and keep track of various #GdkScreen objects currently
+ * instanciated by the application. It is also used to grab and release the keyboard
+ * and the mouse pointer.
+ */
+
 
 enum {
+  OPENED,
   CLOSED,
   LAST_SIGNAL
 };
 
-static void gdk_display_dispose    (GObject         *object);
-static void gdk_display_finalize   (GObject         *object);
+static void gdk_display_dispose     (GObject         *object);
+static void gdk_display_finalize    (GObject         *object);
+
+static void        multihead_get_device_state           (GdkDisplay       *display,
+                                                         GdkDevice        *device,
+                                                         GdkScreen       **screen,
+                                                         gint             *x,
+                                                         gint             *y,
+                                                         GdkModifierType  *mask);
+static GdkWindow * multihead_window_get_device_position (GdkDisplay       *display,
+                                                         GdkDevice        *device,
+                                                         GdkWindow        *window,
+                                                         gint             *x,
+                                                         gint             *y,
+                                                         GdkModifierType  *mask);
+static GdkWindow * multihead_window_at_device_position  (GdkDisplay       *display,
+                                                         GdkDevice        *device,
+                                                         gint             *win_x,
+                                                         gint             *win_y);
+
+static void        multihead_default_get_pointer        (GdkDisplay       *display,
+                                                         GdkScreen       **screen,
+                                                         gint             *x,
+                                                         gint             *y,
+                                                         GdkModifierType  *mask);
+static GdkWindow * multihead_default_window_get_pointer (GdkDisplay      *display,
+                                                         GdkWindow       *window,
+                                                         gint            *x,
+                                                         gint            *y,
+                                                         GdkModifierType *mask);
+static GdkWindow * multihead_default_window_at_pointer  (GdkDisplay      *display,
+                                                         gint            *win_x,
+                                                         gint            *win_y);
 
 
 static void       singlehead_get_pointer (GdkDisplay       *display,
@@ -61,24 +122,38 @@ static GdkWindow* singlehead_default_window_get_pointer (GdkWindow       *window
                                                         GdkModifierType *mask);
 static GdkWindow* singlehead_default_window_at_pointer  (GdkScreen       *screen,
                                                         gint            *win_x,
-                                                        gint            *win_y);
-static GdkWindow *gdk_window_real_window_get_pointer     (GdkDisplay       *display,
-                                                          GdkWindow        *window,
-                                                          gint             *x,
-                                                          gint             *y,
-                                                          GdkModifierType  *mask);
-static GdkWindow *gdk_display_real_get_window_at_pointer (GdkDisplay       *display,
-                                                          gint             *win_x,
-                                                          gint             *win_y);
+                                                        gint            *win_y);static GdkWindow *gdk_window_real_window_get_device_position     (GdkDisplay       *display,
+                                                                  GdkDevice        *device,
+                                                                  GdkWindow        *window,
+                                                                  gint             *x,
+                                                                  gint             *y,
+                                                                  GdkModifierType  *mask);
+static GdkWindow *gdk_display_real_get_window_at_device_position (GdkDisplay       *display,
+                                                                  GdkDevice        *device,
+                                                                  gint             *win_x,
+                                                                  gint             *win_y);
+static GdkAppLaunchContext *gdk_display_real_get_app_launch_context (GdkDisplay *display);
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
 static char *gdk_sm_client_id;
 
-static const GdkDisplayPointerHooks default_pointer_hooks = {
-  _gdk_windowing_get_pointer,
-  gdk_window_real_window_get_pointer,
-  gdk_display_real_get_window_at_pointer
+static const GdkDisplayDeviceHooks default_device_hooks = {
+  _gdk_windowing_get_device_state,
+  gdk_window_real_window_get_device_position,
+  gdk_display_real_get_window_at_device_position
+};
+
+static const GdkDisplayDeviceHooks multihead_pointer_hooks = {
+  multihead_get_device_state,
+  multihead_window_get_device_position,
+  multihead_window_at_device_position
+};
+
+static const GdkDisplayPointerHooks multihead_default_pointer_hooks = {
+  multihead_default_get_pointer,
+  multihead_default_window_get_pointer,
+  multihead_default_window_at_pointer
 };
 
 static const GdkDisplayPointerHooks singlehead_pointer_hooks = {
@@ -93,6 +168,7 @@ static const GdkPointerHooks singlehead_default_pointer_hooks = {
 };
 
 static const GdkPointerHooks *singlehead_current_pointer_hooks = &singlehead_default_pointer_hooks;
+static const GdkDisplayPointerHooks *multihead_current_pointer_hooks = &multihead_default_pointer_hooks;
 
 G_DEFINE_TYPE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
 
@@ -100,10 +176,27 @@ static void
 gdk_display_class_init (GdkDisplayClass *class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (class);
-  
+
   object_class->finalize = gdk_display_finalize;
   object_class->dispose = gdk_display_dispose;
 
+  class->get_app_launch_context = gdk_display_real_get_app_launch_context;
+
+  /**
+   * GdkDisplay::opened:
+   * @display: the object on which the signal is emitted
+   *
+   * The ::opened signal is emitted when the connection to the windowing
+   * system for @display is opened.
+   */
+  signals[OPENED] =
+    g_signal_new (g_intern_static_string ("opened"),
+                 G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
   /**
    * GdkDisplay::closed:
    * @display: the object on which the signal is emitted
@@ -120,49 +213,105 @@ gdk_display_class_init (GdkDisplayClass *class)
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GdkDisplayClass, closed),
                  NULL, NULL,
-                 gdk_marshal_VOID__BOOLEAN,
+                 _gdk_marshal_VOID__BOOLEAN,
                  G_TYPE_NONE,
                  1,
                  G_TYPE_BOOLEAN);
 }
 
 static void
-gdk_display_init (GdkDisplay *display)
+free_pointer_info (GdkPointerWindowInfo *info)
+{
+  g_object_unref (info->toplevel_under_pointer);
+  g_slice_free (GdkPointerWindowInfo, info);
+}
+
+static void
+free_device_grab (GdkDeviceGrabInfo *info)
+{
+  g_object_unref (info->window);
+  g_object_unref (info->native_window);
+  g_free (info);
+}
+
+static gboolean
+free_device_grabs_foreach (gpointer key,
+                           gpointer value,
+                           gpointer user_data)
+{
+  GList *list = value;
+
+  g_list_foreach (list, (GFunc) free_device_grab, NULL);
+  g_list_free (list);
+
+  return TRUE;
+}
+
+static void
+device_removed_cb (GdkDeviceManager *device_manager,
+                   GdkDevice        *device,
+                   GdkDisplay       *display)
+{
+  g_hash_table_remove (display->multiple_click_info, device);
+  g_hash_table_remove (display->device_grabs, device);
+  g_hash_table_remove (display->pointers_info, device);
+
+  /* FIXME: change core pointer and remove from device list */
+}
+
+static void
+gdk_display_opened (GdkDisplay *display)
 {
-  _gdk_displays = g_slist_prepend (_gdk_displays, display);
+  GdkDeviceManager *device_manager;
+
+  device_manager = gdk_display_get_device_manager (display);
 
-  display->button_click_time[0] = display->button_click_time[1] = 0;
-  display->button_window[0] = display->button_window[1] = NULL;
-  display->button_number[0] = display->button_number[1] = -1;
-  display->button_x[0] = display->button_x[1] = 0;
-  display->button_y[0] = display->button_y[1] = 0;
+  g_signal_connect (device_manager, "device-removed",
+                    G_CALLBACK (device_removed_cb), display);
+}
 
+static void
+gdk_display_init (GdkDisplay *display)
+{
   display->double_click_time = 250;
   display->double_click_distance = 5;
 
-  display->pointer_hooks = &default_pointer_hooks;
+  display->device_hooks = &default_device_hooks;
+
+  display->device_grabs = g_hash_table_new (NULL, NULL);
+  display->motion_hint_info = g_hash_table_new_full (NULL, NULL, NULL,
+                                                     (GDestroyNotify) g_free);
+
+  display->pointers_info = g_hash_table_new_full (NULL, NULL, NULL,
+                                                  (GDestroyNotify) free_pointer_info);
+
+  display->multiple_click_info = g_hash_table_new_full (NULL, NULL, NULL,
+                                                        (GDestroyNotify) g_free);
+
+  g_signal_connect (display, "opened",
+                    G_CALLBACK (gdk_display_opened), NULL);
 }
 
 static void
 gdk_display_dispose (GObject *object)
 {
   GdkDisplay *display = GDK_DISPLAY_OBJECT (object);
+  GdkDeviceManager *device_manager;
+
+  device_manager = gdk_display_get_device_manager (GDK_DISPLAY_OBJECT (object));
 
   g_list_foreach (display->queued_events, (GFunc)gdk_event_free, NULL);
   g_list_free (display->queued_events);
   display->queued_events = NULL;
   display->queued_tail = NULL;
 
-  _gdk_displays = g_slist_remove (_gdk_displays, object);
-
-  if (gdk_display_get_default() == display)
+  if (device_manager)
     {
-      if (_gdk_displays)
-        gdk_display_manager_set_default_display (gdk_display_manager_get(),
-                                                 _gdk_displays->data);
-      else
-        gdk_display_manager_set_default_display (gdk_display_manager_get(),
-                                                 NULL);
+      /* this is to make it drop devices which may require using the X
+       * display and therefore can't be cleaned up in finalize.
+       * It will also disconnect device_removed_cb
+       */
+      g_object_run_dispose (G_OBJECT (display->device_manager));
     }
 
   G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
@@ -171,6 +320,19 @@ gdk_display_dispose (GObject *object)
 static void
 gdk_display_finalize (GObject *object)
 {
+  GdkDisplay *display = GDK_DISPLAY_OBJECT (object);
+
+  g_hash_table_foreach_remove (display->device_grabs,
+                               free_device_grabs_foreach,
+                               NULL);
+  g_hash_table_destroy (display->device_grabs);
+
+  g_hash_table_destroy (display->pointers_info);
+  g_hash_table_destroy (display->multiple_click_info);
+
+  if (display->device_manager)
+    g_object_unref (display->device_manager);
+
   G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
 }
 
@@ -199,6 +361,24 @@ gdk_display_close (GdkDisplay *display)
     }
 }
 
+/**
+ * gdk_display_is_closed:
+ * @display: a #GdkDisplay
+ *
+ * Finds out if the display has been closed.
+ *
+ * Returns: %TRUE if the display is closed.
+ *
+ * Since: 2.22
+ */
+gboolean
+gdk_display_is_closed  (GdkDisplay  *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return display->closed;
+}
+
 /**
  * gdk_display_get_event:
  * @display: a #GdkDisplay
@@ -215,8 +395,8 @@ GdkEvent*
 gdk_display_get_event (GdkDisplay *display)
 {
   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-  
-  _gdk_events_queue (display);
+
+  GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
   return _gdk_event_unqueue (display);
 }
 
@@ -272,6 +452,46 @@ gdk_display_put_event (GdkDisplay     *display,
   g_main_context_wakeup (NULL); 
 }
 
+/**
+ * gdk_display_pointer_ungrab:
+ * @display: a #GdkDisplay.
+ * @time_: a timestap (e.g. %GDK_CURRENT_TIME).
+ *
+ * Release any pointer grab.
+ *
+ * Since: 2.2
+ *
+ * Deprecated: 3.0: Use gdk_device_ungrab(), together with gdk_device_grab()
+ *             instead.
+ */
+void
+gdk_display_pointer_ungrab (GdkDisplay *display,
+                           guint32     time_)
+{
+  GdkDeviceManager *device_manager;
+  GList *devices, *dev;
+  GdkDevice *device;
+
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+  device_manager = gdk_display_get_device_manager (display);
+  devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+  /* FIXME: Should this be generic to all backends? */
+  /* FIXME: What happens with extended devices? */
+  for (dev = devices; dev; dev = dev->next)
+    {
+      device = dev->data;
+
+      if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
+        continue;
+
+      gdk_device_ungrab (device, time_);
+    }
+
+  g_list_free (devices);
+}
+
 /**
  * gdk_pointer_ungrab:
  * @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no 
@@ -279,6 +499,9 @@ gdk_display_put_event (GdkDisplay     *display,
  *
  * Ungrabs the pointer on the default display, if it is grabbed by this 
  * application.
+ *
+ * Deprecated: 3.0: Use gdk_device_ungrab(), together with gdk_device_grab()
+ *             instead.
  **/
 void
 gdk_pointer_ungrab (guint32 time)
@@ -294,8 +517,10 @@ gdk_pointer_ungrab (guint32 time)
  *
  * Note that this does not take the inmplicit pointer grab on button
  * presses into account.
-
- * Return value: %TRUE if the pointer is currently grabbed by this application.* 
+ *
+ * Return value: %TRUE if the pointer is currently grabbed by this application.
+ *
+ * Deprecated: 3.0: Use gdk_display_device_is_grabbed() instead.
  **/
 gboolean
 gdk_pointer_is_grabbed (void)
@@ -303,6 +528,46 @@ gdk_pointer_is_grabbed (void)
   return gdk_display_pointer_is_grabbed (gdk_display_get_default ());
 }
 
+/**
+ * gdk_display_keyboard_ungrab:
+ * @display: a #GdkDisplay.
+ * @time_: a timestap (e.g #GDK_CURRENT_TIME).
+ *
+ * Release any keyboard grab
+ *
+ * Since: 2.2
+ *
+ * Deprecated: 3.0: Use gdk_device_ungrab(), together with gdk_device_grab()
+ *             instead.
+ */
+void
+gdk_display_keyboard_ungrab (GdkDisplay *display,
+                            guint32     time)
+{
+  GdkDeviceManager *device_manager;
+  GList *devices, *dev;
+  GdkDevice *device;
+
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+  device_manager = gdk_display_get_device_manager (display);
+  devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+  /* FIXME: Should this be generic to all backends? */
+  /* FIXME: What happens with extended devices? */
+  for (dev = devices; dev; dev = dev->next)
+    {
+      device = dev->data;
+
+      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+        continue;
+
+      gdk_device_ungrab (device, time);
+    }
+
+  g_list_free (devices);
+}
+
 /**
  * gdk_keyboard_ungrab:
  * @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no
@@ -310,6 +575,9 @@ gdk_pointer_is_grabbed (void)
  * 
  * Ungrabs the keyboard on the default display, if it is grabbed by this 
  * application.
+ *
+ * Deprecated: 3.0: Use gdk_device_ungrab(), together with gdk_device_grab()
+ *             instead.
  **/
 void
 gdk_keyboard_ungrab (guint32 time)
@@ -328,6 +596,29 @@ gdk_beep (void)
   gdk_display_beep (gdk_display_get_default ());
 }
 
+/**
+ * gdk_flush:
+ *
+ * Flushes the output buffers of all display connections and waits
+ * until all requests have been processed.
+ * This is rarely needed by applications.
+ */
+void
+gdk_flush (void)
+{
+  GSList *list, *l;
+
+  list = gdk_display_manager_list_displays (gdk_display_manager_get ());
+  for (l = list; l; l = l->next)
+    {
+      GdkDisplay *display = l->data;
+
+      GDK_DISPLAY_GET_CLASS (display)->sync (display);
+    }
+
+  g_slist_free (list);
+}
+
 /**
  * gdk_event_send_client_message:
  * @event: the #GdkEvent to send, which should be a #GdkEventClient.
@@ -370,37 +661,6 @@ gdk_event_send_clientmessage_toall (GdkEvent *event)
   gdk_screen_broadcast_client_message (gdk_screen_get_default (), event);
 }
 
-/**
- * gdk_device_get_core_pointer:
- * 
- * Returns the core pointer device for the default display.
- * 
- * Return value: the core pointer device; this is owned by the
- *   display and should not be freed.
- **/
-GdkDevice *
-gdk_device_get_core_pointer (void)
-{
-  return gdk_display_get_core_pointer (gdk_display_get_default ());
-}
-
-/**
- * gdk_display_get_core_pointer:
- * @display: a #GdkDisplay
- * 
- * Returns the core pointer device for the given display
- * 
- * Return value: the core pointer device; this is owned by the
- *   display and should not be freed.
- *
- * Since: 2.2
- **/
-GdkDevice *
-gdk_display_get_core_pointer (GdkDisplay *display)
-{
-  return display->core_pointer;
-}
-
 /**
  * gdk_set_sm_client_id:
  * @sm_client_id: the client id assigned by the session manager when the
@@ -445,46 +705,65 @@ _gdk_get_sm_client_id (void)
 }
 
 void
-_gdk_display_enable_motion_hints (GdkDisplay *display)
+_gdk_display_enable_motion_hints (GdkDisplay *display,
+                                  GdkDevice  *device)
 {
-  gulong next_serial;
-  
-  if (display->pointer_info.motion_hint_serial != 0)
+  gulong *device_serial, serial;
+
+  device_serial = g_hash_table_lookup (display->motion_hint_info, device);
+
+  if (!device_serial)
     {
-      next_serial = _gdk_windowing_window_get_next_serial (display);
-      if (next_serial < display->pointer_info.motion_hint_serial)
-       display->pointer_info.motion_hint_serial = next_serial;
+      device_serial = g_new0 (gulong, 1);
+      *device_serial = G_MAXULONG;
+      g_hash_table_insert (display->motion_hint_info, device, device_serial);
+    }
+
+  if (*device_serial != 0)
+    {
+      serial = _gdk_windowing_window_get_next_serial (display);
+      /* We might not actually generate the next request, so
+        make sure this triggers always, this may cause it to
+        trigger slightly too early, but this is just a hint
+        anyway. */
+      if (serial > 0)
+       serial--;
+      if (serial < *device_serial)
+       *device_serial = serial;
     }
 }
 
 /**
- * gdk_display_get_pointer:
- * @display: a #GdkDisplay
- * @screen: location to store the screen that the
- *          cursor is on, or %NULL.
- * @x: location to store root window X coordinate of pointer, or %NULL.
- * @y: location to store root window Y coordinate of pointer, or %NULL.
- * @mask: location to store current modifier mask, or %NULL
- * 
- * Gets the current location of the pointer and the current modifier
- * mask for a given display.
+ * gdk_display_get_device_state:
+ * @display: a #GdkDisplay.
+ * @device: pointer device to query status about.
+ * @screen: (out) (transfer none) (allow-none): location to store the #GdkScreen
+ *          the @device is on, or %NULL.
+ * @x: (out) (allow-none): location to store root window X coordinate of @device, or %NULL.
+ * @y: (out) (allow-none): location to store root window Y coordinate of @device, or %NULL.
+ * @mask: (out) (allow-none): location to store current modifier mask for @device, or %NULL.
  *
- * Since: 2.2
+ * Gets the current location and state of @device for a given display.
+ *
+ * Since: 3.0
  **/
 void
-gdk_display_get_pointer (GdkDisplay      *display,
-                        GdkScreen      **screen,
-                        gint            *x,
-                        gint            *y,
-                        GdkModifierType *mask)
+gdk_display_get_device_state (GdkDisplay       *display,
+                              GdkDevice        *device,
+                              GdkScreen       **screen,
+                              gint             *x,
+                              gint             *y,
+                              GdkModifierType  *mask)
 {
   GdkScreen *tmp_screen;
   gint tmp_x, tmp_y;
   GdkModifierType tmp_mask;
-  
+
   g_return_if_fail (GDK_IS_DISPLAY (display));
+  g_return_if_fail (GDK_IS_DEVICE (device));
+  g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
 
-  display->pointer_hooks->get_pointer (display, &tmp_screen, &tmp_x, &tmp_y, &tmp_mask);
+  display->device_hooks->get_device_state (display, device, &tmp_screen, &tmp_x, &tmp_y, &tmp_mask);
 
   if (screen)
     *screen = tmp_screen;
@@ -496,121 +775,264 @@ gdk_display_get_pointer (GdkDisplay      *display,
     *mask = tmp_mask;
 }
 
+/**
+ * gdk_display_get_window_at_device_position:
+ * @display: a #GdkDisplay.
+ * @device: pointer #GdkDevice to query info to.
+ * @win_x: (out) (allow-none): return location for the X coordinate of the device location,
+ *         relative to the window origin, or %NULL.
+ * @win_y: (out) (allow-none): return location for the Y coordinate of the device location,
+ *         relative to the window origin, or %NULL.
+ *
+ * Obtains the window underneath @device, returning the location of the device in @win_x and @win_y. Returns
+ * %NULL if the window tree under @device is not known to GDK (for example, belongs to another application).
+ *
+ * Returns: (transfer none): the #GdkWindow under the device position, or %NULL.
+ *
+ * Since: 3.0
+ **/
+GdkWindow *
+gdk_display_get_window_at_device_position (GdkDisplay *display,
+                                           GdkDevice  *device,
+                                           gint       *win_x,
+                                           gint       *win_y)
+{
+  gint tmp_x, tmp_y;
+  GdkWindow *window;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+  g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
+
+  window = display->device_hooks->window_at_device_position (display, device, &tmp_x, &tmp_y);
+
+  if (win_x)
+    *win_x = tmp_x;
+  if (win_y)
+    *win_y = tmp_y;
+
+  return window;
+}
+
+/**
+ * gdk_display_set_device_hooks:
+ * @display: a #GdkDisplay.
+ * @new_hooks: (allow-none): a table of pointers to functions for getting quantities related
+ *             to all devices position, or %NULL to restore the default table.
+ *
+ * This function allows for hooking into the operation of getting the current location of any
+ * #GdkDevice on a particular #GdkDisplay. This is only useful for such low-level tools as
+ * an event recorder. Applications should never have any reason to use this facility.
+ *
+ * Returns: (transfer none): The previous device hook table.
+ *
+ * Since: 3.0
+ **/
+GdkDisplayDeviceHooks *
+gdk_display_set_device_hooks (GdkDisplay                  *display,
+                              const GdkDisplayDeviceHooks *new_hooks)
+{
+  const GdkDisplayDeviceHooks *result;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  result = display->device_hooks;
+
+  if (new_hooks)
+    display->device_hooks = new_hooks;
+  else
+    display->device_hooks = &default_device_hooks;
+
+  return (GdkDisplayDeviceHooks *) result;
+}
+
+/**
+ * gdk_display_get_pointer:
+ * @display: a #GdkDisplay
+ * @screen: (allow-none): location to store the screen that the
+ *          cursor is on, or %NULL.
+ * @x: (out) (allow-none): location to store root window X coordinate of pointer, or %NULL.
+ * @y: (out) (allow-none): location to store root window Y coordinate of pointer, or %NULL.
+ * @mask: (out) (allow-none): location to store current modifier mask, or %NULL
+ *
+ * Gets the current location of the pointer and the current modifier
+ * mask for a given display.
+ *
+ * Since: 2.2
+ *
+ * Deprecated: 3.0: Use gdk_display_get_device_state() instead.
+ **/
+void
+gdk_display_get_pointer (GdkDisplay      *display,
+                        GdkScreen      **screen,
+                        gint            *x,
+                        gint            *y,
+                        GdkModifierType *mask)
+{
+  g_return_if_fail (GDK_IS_DISPLAY (display));
+
+  gdk_display_get_device_state (display, display->core_pointer, screen, x, y, mask);
+}
+
 static GdkWindow *
-gdk_display_real_get_window_at_pointer (GdkDisplay *display,
-                                        gint       *win_x,
-                                        gint       *win_y)
+gdk_display_real_get_window_at_device_position (GdkDisplay *display,
+                                                GdkDevice  *device,
+                                                gint       *win_x,
+                                                gint       *win_y)
 {
   GdkWindow *window;
   gint x, y;
 
-  window = _gdk_windowing_window_at_pointer (display, &x, &y, NULL);
+  window = _gdk_windowing_window_at_device_position (display, device, &x, &y, NULL, FALSE);
 
   /* This might need corrections, as the native window returned
      may contain client side children */
   if (window)
     {
       double xx, yy;
-      
+
       window = _gdk_window_find_descendant_at (window,
-                                              x, y, 
+                                              x, y,
                                               &xx, &yy);
       x = floor (xx + 0.5);
       y = floor (yy + 0.5);
     }
-  
+
   *win_x = x;
   *win_y = y;
-  
+
   return window;
 }
 
 static GdkWindow *
-gdk_window_real_window_get_pointer (GdkDisplay       *display,
-                                    GdkWindow        *window,
-                                    gint             *x,
-                                    gint             *y,
-                                    GdkModifierType  *mask)
+gdk_window_real_window_get_device_position (GdkDisplay       *display,
+                                            GdkDevice        *device,
+                                            GdkWindow        *window,
+                                            gint             *x,
+                                            gint             *y,
+                                            GdkModifierType  *mask)
 {
-  GdkWindowObject *private;
-  GdkWindow *pointer_window;
   gint tmpx, tmpy;
   GdkModifierType tmp_mask;
+  gboolean normal_child;
 
-  private = (GdkWindowObject *) window;
+  normal_child = GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_device_state (window,
+                                                                              device,
+                                                                              &tmpx, &tmpy,
+                                                                              &tmp_mask);
+  /* We got the coords on the impl, convert to the window */
+  tmpx -= window->abs_x;
+  tmpy -= window->abs_y;
 
-  pointer_window = _gdk_windowing_window_get_pointer (display,
-                                                      window,
-                                                      &tmpx, &tmpy,
-                                                      mask);
-  /* We got the coords on the impl, conver to the window */
-  tmpx -= private->abs_x;
-  tmpy -= private->abs_y;
-  
   if (x)
     *x = tmpx;
   if (y)
     *y = tmpy;
+  if (mask)
+    *mask = tmp_mask;
 
-  /* We need to recalculate the true child window with the pointer in it
-     due to possible client side child windows */
-  if (pointer_window != NULL)
-    {
-      /* First get the pointer coords relative to pointer_window */
-      _gdk_windowing_window_get_pointer (display,
-                                        pointer_window,
-                                        &tmpx, &tmpy,
-                                        &tmp_mask);
-      /* Then convert that to a client side window */
-      pointer_window = _gdk_window_find_descendant_at (pointer_window,
-                                                      tmpx, tmpy, 
-                                                      NULL, NULL);
-    }
-
-  return pointer_window;
+  if (normal_child)
+    return _gdk_window_find_child_at (window, tmpx, tmpy);
+  return NULL;
 }
 
 /**
  * gdk_display_get_window_at_pointer:
  * @display: a #GdkDisplay
- * @win_x: return location for x coordinate of the pointer location relative 
+ * @win_x: (out) (allow-none): return location for x coordinate of the pointer location relative
  *    to the window origin, or %NULL
- * @win_y: return location for y coordinate of the pointer location relative
+ * @win_y: (out) (allow-none): return location for y coordinate of the pointer location relative
  &    to the window origin, or %NULL
- * 
+ *
  * Obtains the window underneath the mouse pointer, returning the location
- * of the pointer in that window in @win_x, @win_y for @screen. Returns %NULL 
+ * of the pointer in that window in @win_x, @win_y for @screen. Returns %NULL
  * if the window under the mouse pointer is not known to GDK (for example, 
  * belongs to another application).
- * 
- * Returns: the window under the mouse pointer, or %NULL
+ *
+ * Returns: (transfer none): the window under the mouse pointer, or %NULL
  *
  * Since: 2.2
+ *
+ * Deprecated: 3.0: Use gdk_display_get_window_at_device_position() instead.
  **/
 GdkWindow *
 gdk_display_get_window_at_pointer (GdkDisplay *display,
                                   gint       *win_x,
                                   gint       *win_y)
 {
-  gint tmp_x, tmp_y;
-  GdkWindow *window;
-
   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
 
-  window = display->pointer_hooks->window_at_pointer (display, &tmp_x, &tmp_y);
+  return gdk_display_get_window_at_device_position (display, display->core_pointer, win_x, win_y);
+}
 
-  if (win_x)
-    *win_x = tmp_x;
-  if (win_y)
-    *win_y = tmp_y;
+static void
+multihead_get_device_state (GdkDisplay       *display,
+                            GdkDevice        *device,
+                            GdkScreen       **screen,
+                            gint             *x,
+                            gint             *y,
+                            GdkModifierType  *mask)
+{
+  multihead_current_pointer_hooks->get_pointer (display, screen, x, y, mask);
+}
 
-  return window;
+static GdkWindow *
+multihead_window_get_device_position (GdkDisplay      *display,
+                                      GdkDevice       *device,
+                                      GdkWindow       *window,
+                                      gint            *x,
+                                      gint            *y,
+                                      GdkModifierType *mask)
+{
+  return multihead_current_pointer_hooks->window_get_pointer (display, window, x, y, mask);
+}
+
+static GdkWindow *
+multihead_window_at_device_position (GdkDisplay *display,
+                                     GdkDevice  *device,
+                                     gint       *win_x,
+                                     gint       *win_y)
+{
+  return multihead_current_pointer_hooks->window_at_pointer (display, win_x, win_y);
+}
+
+static void
+multihead_default_get_pointer (GdkDisplay       *display,
+                               GdkScreen       **screen,
+                               gint             *x,
+                               gint             *y,
+                               GdkModifierType  *mask)
+{
+  return _gdk_windowing_get_device_state (display,
+                                          display->core_pointer,
+                                          screen, x, y, mask);
+}
+
+static GdkWindow *
+multihead_default_window_get_pointer (GdkDisplay      *display,
+                                      GdkWindow       *window,
+                                      gint            *x,
+                                      gint            *y,
+                                      GdkModifierType *mask)
+{
+  return gdk_window_real_window_get_device_position (display,
+                                                     display->core_pointer,
+                                                     window, x, y, mask);
+}
+
+static GdkWindow *
+multihead_default_window_at_pointer (GdkDisplay *display,
+                                     gint       *win_x,
+                                     gint       *win_y)
+{
+  return gdk_display_real_get_window_at_device_position (display,
+                                                         display->core_pointer,
+                                                         win_x, win_y);
 }
 
 /**
  * gdk_display_set_pointer_hooks:
  * @display: a #GdkDisplay
- * @new_hooks: a table of pointers to functions for getting
+ * @new_hooks: (allow-none): a table of pointers to functions for getting
  *   quantities related to the current pointer position,
  *   or %NULL to restore the default table.
  * 
@@ -620,23 +1042,26 @@ gdk_display_get_window_at_pointer (GdkDisplay *display,
  * event recorder. Applications should never have any
  * reason to use this facility.
  *
- * Return value: the previous pointer hook table
+ * Return value: (transfer none): the previous pointer hook table
  *
  * Since: 2.2
+ *
+ * Deprecated: 3.0: Use gdk_display_set_device_hooks() instead.
  **/
 GdkDisplayPointerHooks *
 gdk_display_set_pointer_hooks (GdkDisplay                   *display,
                               const GdkDisplayPointerHooks *new_hooks)
 {
-  const GdkDisplayPointerHooks *result;
+  const GdkDisplayPointerHooks *result = multihead_current_pointer_hooks;
 
   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-  result = display->pointer_hooks;
 
   if (new_hooks)
-    display->pointer_hooks = new_hooks;
+    multihead_current_pointer_hooks = new_hooks;
   else
-    display->pointer_hooks = &default_pointer_hooks;
+    multihead_current_pointer_hooks = &multihead_default_pointer_hooks;
+
+  gdk_display_set_device_hooks (display, &multihead_pointer_hooks);
 
   return (GdkDisplayPointerHooks *)result;
 }
@@ -683,8 +1108,13 @@ singlehead_default_window_get_pointer (GdkWindow       *window,
                                       gint            *y,
                                       GdkModifierType *mask)
 {
-  return gdk_window_real_window_get_pointer (gdk_drawable_get_display (window),
-                                             window, x, y, mask);
+  GdkDisplay *display;
+
+  display = gdk_window_get_display (window);
+
+  return gdk_window_real_window_get_device_position (display,
+                                                     display->core_pointer,
+                                                     window, x, y, mask);
 }
 
 static GdkWindow*
@@ -692,13 +1122,18 @@ singlehead_default_window_at_pointer  (GdkScreen       *screen,
                                       gint            *win_x,
                                       gint            *win_y)
 {
-  return gdk_display_real_get_window_at_pointer (gdk_screen_get_display (screen),
-                                                 win_x, win_y);
+  GdkDisplay *display;
+
+  display = gdk_screen_get_display (screen);
+
+  return gdk_display_real_get_window_at_device_position (display,
+                                                         display->core_pointer,
+                                                         win_x, win_y);
 }
 
 /**
  * gdk_set_pointer_hooks:
- * @new_hooks: a table of pointers to functions for getting
+ * @new_hooks: (allow-none): a table of pointers to functions for getting
  *   quantities related to the current pointer position,
  *   or %NULL to restore the default table.
  * 
@@ -712,6 +1147,8 @@ singlehead_default_window_at_pointer  (GdkScreen       *screen,
  * see gdk_display_set_pointer_hooks().
  * 
  * Return value: the previous pointer hook table
+ *
+ * Deprecated: 3.0: Use gdk_display_set_device_hooks() instead.
  **/
 GdkPointerHooks *
 gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
@@ -731,7 +1168,7 @@ gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
 
 static void
 generate_grab_broken_event (GdkWindow *window,
-                           gboolean   keyboard,
+                            GdkDevice *device,
                            gboolean   implicit,
                            GdkWindow *grab_window)
 {
@@ -739,66 +1176,54 @@ generate_grab_broken_event (GdkWindow *window,
 
   if (!GDK_WINDOW_DESTROYED (window))
     {
-      GdkEvent event;
-      event.type = GDK_GRAB_BROKEN;
-      event.grab_broken.window = window;
-      event.grab_broken.send_event = 0;
-      event.grab_broken.keyboard = keyboard;
-      event.grab_broken.implicit = implicit;
-      event.grab_broken.grab_window = grab_window;
-      gdk_event_put (&event);
+      GdkEvent *event;
+
+      event = gdk_event_new (GDK_GRAB_BROKEN);
+      event->grab_broken.window = g_object_ref (window);
+      event->grab_broken.send_event = FALSE;
+      event->grab_broken.implicit = implicit;
+      event->grab_broken.grab_window = grab_window;
+      gdk_event_set_device (event, device);
+      event->grab_broken.keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) ? TRUE : FALSE;
+
+      gdk_event_put (event);
+      gdk_event_free (event);
     }
 }
 
-/* Get the pointer grab in effects for events we just sent */
-GdkPointerGrabInfo *
-_gdk_display_get_active_pointer_grab (GdkDisplay *display)
-{
-  GdkPointerGrabInfo *info;
-
-  if (display->pointer_grabs == NULL)
-    return NULL;
-
-  info = display->pointer_grabs->data;
-
-  if (info->activated)
-    return info;
-  
-  return NULL;
-}
-
-
-GdkPointerGrabInfo *
-_gdk_display_get_last_pointer_grab (GdkDisplay *display)
+GdkDeviceGrabInfo *
+_gdk_display_get_last_device_grab (GdkDisplay *display,
+                                   GdkDevice  *device)
 {
   GList *l;
 
-  l = display->pointer_grabs;
+  l = g_hash_table_lookup (display->device_grabs, device);
 
-  if (l == NULL)
-    return NULL;
-
-  while (l->next != NULL)
-    l = l->next;
+  if (l)
+    {
+      l = g_list_last (l);
+      return l->data;
+    }
 
-  return (GdkPointerGrabInfo *)l->data;
+  return NULL;
 }
 
-
-GdkPointerGrabInfo *
-_gdk_display_add_pointer_grab (GdkDisplay *display,
-                              GdkWindow *window,
-                              GdkWindow *native_window,
-                              gboolean owner_events,
-                              GdkEventMask event_mask,
-                              unsigned long serial_start,
-                              guint32 time,
-                              gboolean implicit)
+GdkDeviceGrabInfo *
+_gdk_display_add_device_grab (GdkDisplay       *display,
+                              GdkDevice        *device,
+                              GdkWindow        *window,
+                              GdkWindow        *native_window,
+                              GdkGrabOwnership  grab_ownership,
+                              gboolean          owner_events,
+                              GdkEventMask      event_mask,
+                              unsigned long     serial_start,
+                              guint32           time,
+                              gboolean          implicit)
 {
-  GdkPointerGrabInfo *info, *other_info;
-  GList *l;
+  GdkDeviceGrabInfo *info, *other_info;
+  GList *grabs, *l;
 
-  info = g_new0 (GdkPointerGrabInfo, 1);
+  info = g_new0 (GdkDeviceGrabInfo, 1);
 
   info->window = g_object_ref (window);
   info->native_window = g_object_ref (native_window);
@@ -808,19 +1233,22 @@ _gdk_display_add_pointer_grab (GdkDisplay *display,
   info->event_mask = event_mask;
   info->time = time;
   info->implicit = implicit;
+  info->ownership = grab_ownership;
+
+  grabs = g_hash_table_lookup (display->device_grabs, device);
 
   /* Find the first grab that has a larger start time (if any) and insert
    * before that. I.E we insert after already existing grabs with same
    * start time */
-  for (l = display->pointer_grabs; l != NULL; l = l->next)
+  for (l = grabs; l != NULL; l = l->next)
     {
       other_info = l->data;
-      
+
       if (info->serial_start < other_info->serial_start)
        break;
     }
-  display->pointer_grabs =
-    g_list_insert_before (display->pointer_grabs, l, info);
+
+  grabs = g_list_insert_before (grabs, l, info);
 
   /* Make sure the new grab end before next grab */
   if (l)
@@ -828,9 +1256,9 @@ _gdk_display_add_pointer_grab (GdkDisplay *display,
       other_info = l->data;
       info->serial_end = other_info->serial_start;
     }
-  
+
   /* Find any previous grab and update its end time */
-  l = g_list_find  (display->pointer_grabs, info);
+  l = g_list_find (grabs, info);
   l = l->prev;
   if (l)
     {
@@ -838,31 +1266,31 @@ _gdk_display_add_pointer_grab (GdkDisplay *display,
       other_info->serial_end = serial_start;
     }
 
-  return info;
-}
+  g_hash_table_insert (display->device_grabs, device, grabs);
 
-static void
-free_pointer_grab (GdkPointerGrabInfo *info)
-{
-  g_object_unref (info->window);
-  g_object_unref (info->native_window);
-  g_free (info);
+  return info;
 }
 
-/* _gdk_syntesize_crossing_events only works inside one toplevel.
+/* _gdk_synthesize_crossing_events only works inside one toplevel.
    This function splits things into two calls if needed, converting the
    coordinates to the right toplevel */
 static void
-synthesize_crossing_events (GdkDisplay *display,
-                           GdkWindow *src_window,
-                           GdkWindow *dest_window,
-                           GdkCrossingMode crossing_mode,
-                           guint32 time,
-                           gulong serial)
+synthesize_crossing_events (GdkDisplay      *display,
+                            GdkDevice       *device,
+                            GdkDevice       *source_device,
+                           GdkWindow       *src_window,
+                           GdkWindow       *dest_window,
+                           GdkCrossingMode  crossing_mode,
+                           guint32          time,
+                           gulong           serial)
 {
   GdkWindow *src_toplevel, *dest_toplevel;
   GdkModifierType state;
   int x, y;
+
+  /* We use the native crossing events if all native */
+  if (_gdk_native_windows)
+    return;
   
   if (src_window)
     src_toplevel = gdk_window_get_toplevel (src_window);
@@ -880,86 +1308,113 @@ synthesize_crossing_events (GdkDisplay *display,
       src_toplevel == dest_toplevel)
     {
       /* Same toplevels */
-      _gdk_windowing_window_get_pointer (display,
-                                        dest_toplevel,
-                                        &x, &y, &state);
-      _gdk_syntesize_crossing_events (display,
-                                     src_window,
-                                     dest_window,
-                                     crossing_mode,
-                                     x, y, state,
-                                     time,
-                                     NULL,
-                                     serial);
+      gdk_window_get_pointer (dest_toplevel,
+                             &x, &y, &state);
+      _gdk_synthesize_crossing_events (display,
+                                      src_window,
+                                      dest_window,
+                                       device, source_device,
+                                      crossing_mode,
+                                      x, y, state,
+                                      time,
+                                      NULL,
+                                      serial, FALSE);
     }
   else if (dest_toplevel == NULL)
     {
-      _gdk_windowing_window_get_pointer (display,
-                                        src_toplevel,
-                                        &x, &y, &state);
-      _gdk_syntesize_crossing_events (display,
-                                     src_window,
-                                     NULL,
-                                     crossing_mode,
-                                     x, y, state,
-                                     time,
-                                     NULL,
-                                     serial);
+      gdk_window_get_pointer (src_toplevel,
+                             &x, &y, &state);
+      _gdk_synthesize_crossing_events (display,
+                                       src_window,
+                                       NULL,
+                                       device, source_device,
+                                       crossing_mode,
+                                       x, y, state,
+                                       time,
+                                       NULL,
+                                       serial, FALSE);
     }
   else
     {
       /* Different toplevels */
-      _gdk_windowing_window_get_pointer (display,
-                                        src_toplevel,
-                                        &x, &y, &state);
-      _gdk_syntesize_crossing_events (display,
-                                     src_window,
-                                     NULL,
-                                     crossing_mode,
-                                     x, y, state,
-                                     time,
-                                     NULL,
-                                     serial);
-      _gdk_windowing_window_get_pointer (display,
-                                        dest_toplevel,
-                                        &x, &y, &state);
-      _gdk_syntesize_crossing_events (display,
-                                     NULL,
-                                     dest_window,
-                                     crossing_mode,
-                                     x, y, state,
-                                     time,
-                                     NULL,
-                                     serial);
+      gdk_window_get_pointer (src_toplevel,
+                             &x, &y, &state);
+      _gdk_synthesize_crossing_events (display,
+                                      src_window,
+                                      NULL,
+                                       device, source_device,
+                                      crossing_mode,
+                                      x, y, state,
+                                      time,
+                                      NULL,
+                                      serial, FALSE);
+      gdk_window_get_pointer (dest_toplevel,
+                             &x, &y, &state);
+      _gdk_synthesize_crossing_events (display,
+                                      NULL,
+                                      dest_window,
+                                       device, source_device,
+                                      crossing_mode,
+                                      x, y, state,
+                                      time,
+                                      NULL,
+                                      serial, FALSE);
     }
 }
 
+static GdkWindow *
+get_current_toplevel (GdkDisplay      *display,
+                      GdkDevice       *device,
+                      int             *x_out,
+                      int             *y_out,
+                     GdkModifierType *state_out)
+{
+  GdkWindow *pointer_window;
+  int x, y;
+  GdkModifierType state;
+
+  pointer_window = _gdk_windowing_window_at_device_position (display, device, &x, &y, &state, TRUE);
+
+  if (pointer_window != NULL &&
+      (GDK_WINDOW_DESTROYED (pointer_window) ||
+       GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
+       GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
+    pointer_window = NULL;
+
+  *x_out = x;
+  *y_out = y;
+  *state_out = state;
+  return pointer_window;
+}
 
 static void
-switch_to_pointer_grab (GdkDisplay *display,
-                       GdkPointerGrabInfo *grab,
-                       GdkPointerGrabInfo *last_grab,
-                       guint32 time,
-                       gulong serial)
-{
-  GdkWindow *src_window, *pointer_window;
-  GdkWindowObject *w;
+switch_to_pointer_grab (GdkDisplay        *display,
+                        GdkDevice         *device,
+                        GdkDevice         *source_device,
+                       GdkDeviceGrabInfo *grab,
+                       GdkDeviceGrabInfo *last_grab,
+                       guint32            time,
+                       gulong             serial)
+{
+  GdkWindow *src_window, *pointer_window, *new_toplevel;
+  GdkPointerWindowInfo *info;
   GList *old_grabs;
   GdkModifierType state;
   int x, y;
 
   /* Temporarily unset pointer to make sure we send the crossing events below */
-  old_grabs = display->pointer_grabs;
-  display->pointer_grabs = NULL;
-  
+  old_grabs = g_hash_table_lookup (display->device_grabs, device);
+  g_hash_table_steal (display->device_grabs, device);
+  info = _gdk_display_get_pointer_info (display, device);
+
   if (grab)
     {
       /* New grab is in effect */
-      
+
       /* We need to generate crossing events for the grab.
        * However, there are never any crossing events for implicit grabs
        * TODO: ... Actually, this could happen if the pointer window
-       *           doesn't have button mask so a parent gets the event... 
+       *           doesn't have button mask so a parent gets the event...
        */
       if (!grab->implicit)
        {
@@ -968,210 +1423,202 @@ switch_to_pointer_grab (GdkDisplay *display,
          if (last_grab)
            src_window = last_grab->window;
          else
-           src_window = display->pointer_info.window_under_pointer;
-         
+           src_window = info->window_under_pointer;
+
          if (src_window != grab->window)
-           {
-             synthesize_crossing_events (display,
-                                         src_window, grab->window,
-                                         GDK_CROSSING_GRAB, time, serial);
-           }
-         
+            synthesize_crossing_events (display, device, source_device,
+                                        src_window, grab->window,
+                                        GDK_CROSSING_GRAB, time, serial);
+
          /* !owner_event Grabbing a window that we're not inside, current status is
             now NULL (i.e. outside grabbed window) */
-         if (!grab->owner_events && display->pointer_info.window_under_pointer != grab->window)
-           _gdk_display_set_window_under_pointer (display, NULL);
+         if (!grab->owner_events && info->window_under_pointer != grab->window)
+           _gdk_display_set_window_under_pointer (display, device, NULL);
        }
-  
+
       grab->activated = TRUE;
     }
-  else if (last_grab)
+
+  if (last_grab)
     {
-      pointer_window = _gdk_windowing_window_at_pointer (display,  &x, &y, &state);
-      if (pointer_window != NULL &&
-         (GDK_WINDOW_DESTROYED (pointer_window) ||
-          GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
-          GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
-       pointer_window = NULL;
-      
-      /* We force checked what window we're in, so we need to
-       * update the toplevel_under_pointer info, as that won't get told of
-       * this change.
-       */
-      if (display->pointer_info.toplevel_under_pointer)
-       g_object_unref (display->pointer_info.toplevel_under_pointer);
-      display->pointer_info.toplevel_under_pointer = NULL;
-      
-      if (pointer_window)
+      new_toplevel = NULL;
+
+      if (grab == NULL /* ungrab */ ||
+         (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
        {
-         /* Convert to toplevel */
-         w = (GdkWindowObject *)pointer_window;
-         while (/*w->parent != NULL && */
-                w->parent->window_type != GDK_WINDOW_ROOT)
+         /* We force check what window we're in, and update the toplevel_under_pointer info,
+          * as that won't get told of this change with toplevel enter events.
+          */
+         if (info->toplevel_under_pointer)
+           g_object_unref (info->toplevel_under_pointer);
+         info->toplevel_under_pointer = NULL;
+
+         new_toplevel = get_current_toplevel (display, device, &x, &y, &state);
+         if (new_toplevel)
            {
-             x += w->x;
-             y += w->y;
-             w = w->parent;
+             /* w is now toplevel and x,y in toplevel coords */
+             info->toplevel_under_pointer = g_object_ref (new_toplevel);
+             info->toplevel_x = x;
+             info->toplevel_y = y;
+             info->state = state;
            }
-         
-         /* w is now toplevel and x,y in toplevel coords */
-         display->pointer_info.toplevel_under_pointer = g_object_ref (w);
-         
-         /* Find (possibly virtual) child window */
-         pointer_window =
-           _gdk_window_find_descendant_at ((GdkWindow *)w,
-                                           x, y,
-                                           NULL, NULL);
        }
 
-      if (pointer_window != last_grab->window)
-       synthesize_crossing_events (display,
-                                   last_grab->window, pointer_window,
-                                   GDK_CROSSING_UNGRAB, time, serial);
-      
-      /* We're now ungrabbed, update the window_under_pointer */
-      _gdk_display_set_window_under_pointer (display, pointer_window);
-      
-      if (last_grab->implicit_ungrab)
-       generate_grab_broken_event (last_grab->window,
-                                   FALSE, TRUE, 
-                                   NULL);
+      if (grab == NULL) /* Ungrabbed, send events */
+       {
+         pointer_window = NULL;
+         if (new_toplevel)
+           {
+             /* Find (possibly virtual) child window */
+             pointer_window =
+               _gdk_window_find_descendant_at (new_toplevel,
+                                               x, y,
+                                               NULL, NULL);
+           }
+
+         if (pointer_window != last_grab->window)
+            synthesize_crossing_events (display, device, source_device,
+                                        last_grab->window, pointer_window,
+                                        GDK_CROSSING_UNGRAB, time, serial);
+
+         /* We're now ungrabbed, update the window_under_pointer */
+         _gdk_display_set_window_under_pointer (display, device, pointer_window);
+       }
     }
-  
-  display->pointer_grabs = old_grabs;
 
+  g_hash_table_insert (display->device_grabs, device, old_grabs);
 }
 
 void
-_gdk_display_pointer_grab_update (GdkDisplay *display,
-                                 gulong current_serial)
+_gdk_display_device_grab_update (GdkDisplay *display,
+                                 GdkDevice  *device,
+                                 GdkDevice  *source_device,
+                                 gulong      current_serial)
 {
-  GdkPointerGrabInfo *current_grab, *next_grab;
+  GdkDeviceGrabInfo *current_grab, *next_grab;
+  GList *grabs;
   guint32 time;
-  
+
   time = display->last_event_time;
+  grabs = g_hash_table_lookup (display->device_grabs, device);
 
-  while (display->pointer_grabs != NULL)
+  while (grabs != NULL)
     {
-      current_grab = display->pointer_grabs->data;
+      current_grab = grabs->data;
 
       if (current_grab->serial_start > current_serial)
        return; /* Hasn't started yet */
-      
-      if (current_grab->serial_end > current_serial ||
-         (current_grab->serial_end == current_serial &&
-          current_grab->grab_one_pointer_release_event))
+
+      if (current_grab->serial_end > current_serial)
        {
          /* This one hasn't ended yet.
             its the currently active one or scheduled to be active */
 
          if (!current_grab->activated)
-           switch_to_pointer_grab (display, current_grab, NULL, time, current_serial);
-         
+            {
+              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+                switch_to_pointer_grab (display, device, source_device, current_grab, NULL, time, current_serial);
+            }
+
          break;
        }
 
-
       next_grab = NULL;
-      if (display->pointer_grabs->next)
+      if (grabs->next)
        {
          /* This is the next active grab */
-         next_grab = display->pointer_grabs->next->data;
-         
+         next_grab = grabs->next->data;
+
          if (next_grab->serial_start > current_serial)
            next_grab = NULL; /* Actually its not yet active */
        }
 
-      if (next_grab == NULL ||
-         current_grab->window != next_grab->window)
+      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
+         (next_grab != NULL && current_grab->window != next_grab->window))
        generate_grab_broken_event (GDK_WINDOW (current_grab->window),
-                                   FALSE, current_grab->implicit,
+                                    device,
+                                   current_grab->implicit,
                                    next_grab? next_grab->window : NULL);
 
-
       /* Remove old grab */
-      display->pointer_grabs =
-       g_list_delete_link (display->pointer_grabs,
-                           display->pointer_grabs);
-      
-      switch_to_pointer_grab (display,
-                             next_grab, current_grab,
-                             time, current_serial);
-      
-      free_pointer_grab (current_grab);
-    }
-}
-
-static gboolean
-is_parent_of (GdkWindow *parent,
-              GdkWindow *child)
-{
-  GdkWindow *w;
+      grabs = g_list_delete_link (grabs, grabs);
+      g_hash_table_insert (display->device_grabs, device, grabs);
 
-  w = child;
-  while (w != NULL)
-    {
-      if (w == parent)
-       return TRUE;
+      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+        switch_to_pointer_grab (display, device, source_device,
+                                next_grab, current_grab,
+                                time, current_serial);
 
-      w = gdk_window_get_parent (w);
+      free_device_grab (current_grab);
     }
-
-  return FALSE;
 }
 
 static GList *
-find_pointer_grab (GdkDisplay *display,
-                  gulong serial)
+grab_list_find (GList  *grabs,
+                gulong  serial)
 {
-  GdkPointerGrabInfo *grab;
-  GList *l;
+  GdkDeviceGrabInfo *grab;
 
-  for (l = display->pointer_grabs; l != NULL; l = l->next)
+  while (grabs)
     {
-      grab = l->data;
+      grab = grabs->data;
 
       if (serial >= grab->serial_start && serial < grab->serial_end)
-       return l;
+       return grabs;
+
+      grabs = grabs->next;
     }
-  
+
   return NULL;
 }
 
+static GList *
+find_device_grab (GdkDisplay *display,
+                   GdkDevice  *device,
+                   gulong      serial)
+{
+  GList *l;
 
+  l = g_hash_table_lookup (display->device_grabs, device);
+  return grab_list_find (l, serial);
+}
 
-GdkPointerGrabInfo *
-_gdk_display_has_pointer_grab (GdkDisplay *display,
-                              gulong serial)
+GdkDeviceGrabInfo *
+_gdk_display_has_device_grab (GdkDisplay *display,
+                              GdkDevice  *device,
+                              gulong      serial)
 {
   GList *l;
 
-  l = find_pointer_grab (display, serial);
+  l = find_device_grab (display, device, serial);
   if (l)
     return l->data;
-  
+
   return NULL;
 }
 
-/* Returns true if last grab was ended */
+/* Returns true if last grab was ended
+ * If if_child is non-NULL, end the grab only if the grabbed
+ * window is the same as if_child or a descendant of it */
 gboolean
-_gdk_display_end_pointer_grab (GdkDisplay *display,
-                              gulong serial,
-                              GdkWindow *if_child,
-                              gboolean implicit)
+_gdk_display_end_device_grab (GdkDisplay *display,
+                              GdkDevice  *device,
+                              gulong      serial,
+                              GdkWindow  *if_child,
+                              gboolean    implicit)
 {
-  GdkPointerGrabInfo *grab;
+  GdkDeviceGrabInfo *grab;
   GList *l;
 
-  l = find_pointer_grab (display, serial);
-  
+  l = find_device_grab (display, device, serial);
+
   if (l == NULL)
     return FALSE;
 
   grab = l->data;
   if (grab &&
       (if_child == NULL ||
-       is_parent_of (grab->window, if_child)))
+       _gdk_window_event_parent_of (if_child, grab->window)))
     {
       grab->serial_end = serial;
       grab->implicit_ungrab = implicit;
@@ -1181,93 +1628,128 @@ _gdk_display_end_pointer_grab (GdkDisplay *display,
   return FALSE;
 }
 
-void
-_gdk_display_set_has_keyboard_grab (GdkDisplay *display,
-                                   GdkWindow *window,
-                                   GdkWindow *native_window,
-                                   gboolean owner_events,
-                                   unsigned long serial,
-                                   guint32 time)
-{
-  if (display->keyboard_grab.window != NULL &&
-      display->keyboard_grab.window != window)
-    generate_grab_broken_event (display->keyboard_grab.window,
-                               TRUE, FALSE, window);
-  
-  display->keyboard_grab.window = window;
-  display->keyboard_grab.native_window = native_window;
-  display->keyboard_grab.owner_events = owner_events;
-  display->keyboard_grab.serial = serial;
-  display->keyboard_grab.time = time;      
+/* Returns TRUE if device events are not blocked by any grab */
+gboolean
+_gdk_display_check_grab_ownership (GdkDisplay *display,
+                                   GdkDevice  *device,
+                                   gulong      serial)
+{
+  GHashTableIter iter;
+  gpointer key, value;
+  GdkGrabOwnership higher_ownership, device_ownership;
+  gboolean device_is_keyboard;
+
+  g_hash_table_iter_init (&iter, display->device_grabs);
+  higher_ownership = device_ownership = GDK_OWNERSHIP_NONE;
+  device_is_keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD);
+
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      GdkDeviceGrabInfo *grab;
+      GdkDevice *dev;
+      GList *grabs;
+
+      dev = key;
+      grabs = value;
+      grabs = grab_list_find (grabs, serial);
+
+      if (!grabs)
+        continue;
+
+      /* Discard device if it's not of the same type */
+      if ((device_is_keyboard && gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD) ||
+          (!device_is_keyboard && gdk_device_get_source (dev) == GDK_SOURCE_KEYBOARD))
+        continue;
+
+      grab = grabs->data;
+
+      if (dev == device)
+        device_ownership = grab->ownership;
+      else
+        {
+          if (grab->ownership > higher_ownership)
+            higher_ownership = grab->ownership;
+        }
+    }
+
+  if (higher_ownership > device_ownership)
+    {
+      /* There's a higher priority ownership
+       * going on for other device(s)
+       */
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
-void
-_gdk_display_unset_has_keyboard_grab (GdkDisplay *display,
-                                     gboolean implicit)
+GdkPointerWindowInfo *
+_gdk_display_get_pointer_info (GdkDisplay *display,
+                               GdkDevice  *device)
 {
-  if (implicit)
-    generate_grab_broken_event (display->keyboard_grab.window,
-                               TRUE, FALSE, NULL);
-  display->keyboard_grab.window = NULL;  
+  GdkPointerWindowInfo *info;
+
+  if (G_UNLIKELY (!device))
+    return NULL;
+
+  info = g_hash_table_lookup (display->pointers_info, device);
+
+  if (G_UNLIKELY (!info))
+    {
+      info = g_slice_new0 (GdkPointerWindowInfo);
+      g_hash_table_insert (display->pointers_info, device, info);
+    }
+
+  return info;
 }
 
-/**
- * gdk_keyboard_grab_info_libgtk_only:
- * @display: the display for which to get the grab information
- * @grab_window: location to store current grab window
- * @owner_events: location to store boolean indicating whether
- *   the @owner_events flag to gdk_keyboard_grab() was %TRUE.
- * 
- * Determines information about the current keyboard grab.
- * This is not public API and must not be used by applications.
- * 
- * Return value: %TRUE if this application currently has the
- *  keyboard grabbed.
- **/
-gboolean
-gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
-                                   GdkWindow **grab_window,
-                                   gboolean   *owner_events)
+void
+_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
+                                   GdkDisplayPointerInfoForeach  func,
+                                   gpointer                      user_data)
 {
-  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+  GHashTableIter iter;
+  gpointer key, value;
+
+  g_hash_table_iter_init (&iter, display->pointers_info);
 
-  if (display->keyboard_grab.window)
+  while (g_hash_table_iter_next (&iter, &key, &value))
     {
-      if (grab_window)
-        *grab_window = display->keyboard_grab.window;
-      if (owner_events)
-        *owner_events = display->keyboard_grab.owner_events;
+      GdkPointerWindowInfo *info = value;
+      GdkDevice *device = key;
 
-      return TRUE;
+      (func) (display, device, info, user_data);
     }
-  else
-    return FALSE;
 }
 
 /**
- * gdk_pointer_grab_info_libgtk_only:
- * @display: the #GdkDisplay for which to get the grab information
- * @grab_window: location to store current grab window
- * @owner_events: location to store boolean indicating whether
- *   the @owner_events flag to gdk_pointer_grab() was %TRUE.
- * 
- * Determines information about the current pointer grab.
+ * gdk_device_grab_info_libgtk_only:
+ * @display: the display for which to get the grab information
+ * @device: device to get the grab information from
+ * @grab_window: (out) (transfer none): location to store current grab window
+ * @owner_events: (out): location to store boolean indicating whether
+ *   the @owner_events flag to gdk_keyboard_grab() or
+ *   gdk_pointer_grab() was %TRUE.
+ *
+ * Determines information about the current keyboard grab.
  * This is not public API and must not be used by applications.
- * 
+ *
  * Return value: %TRUE if this application currently has the
- *  pointer grabbed.
+ *  keyboard grabbed.
  **/
 gboolean
-gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
-                                  GdkWindow **grab_window,
-                                  gboolean   *owner_events)
+gdk_device_grab_info_libgtk_only (GdkDisplay  *display,
+                                  GdkDevice   *device,
+                                  GdkWindow  **grab_window,
+                                  gboolean    *owner_events)
 {
-  GdkPointerGrabInfo *info;
-  
+  GdkDeviceGrabInfo *info;
+
   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
+
+  info = _gdk_display_get_last_device_grab (display, device);
 
-  info = _gdk_display_get_active_pointer_grab (display);
-  
   if (info)
     {
       if (grab_window)
@@ -1281,7 +1763,6 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
     return FALSE;
 }
 
-
 /**
  * gdk_display_pointer_is_grabbed:
  * @display: a #GdkDisplay
@@ -1291,18 +1772,528 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
  * Returns: %TRUE if an active X pointer grab is in effect
  *
  * Since: 2.2
+ *
+ * Deprecated: 3.0: Use gdk_display_device_is_grabbed() instead.
  */
 gboolean
 gdk_display_pointer_is_grabbed (GdkDisplay *display)
 {
-  GdkPointerGrabInfo *info;
-  
+  GdkDeviceManager *device_manager;
+  GList *devices, *dev;
+  GdkDevice *device;
+
   g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
 
-  info = _gdk_display_get_active_pointer_grab (display);
-  
+  device_manager = gdk_display_get_device_manager (display);
+  devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+  for (dev = devices; dev; dev = dev->next)
+    {
+      device = dev->data;
+
+      if (gdk_device_get_source (device) == GDK_SOURCE_MOUSE &&
+          gdk_display_device_is_grabbed (display, device))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * gdk_display_device_is_grabbed:
+ * @display: a #GdkDisplay
+ * @device: a #GdkDevice
+ *
+ * Returns %TRUE if there is an ongoing grab on @device for @display.
+ *
+ * Returns: %TRUE if there is a grab in effect for @device.
+ **/
+gboolean
+gdk_display_device_is_grabbed (GdkDisplay *display,
+                               GdkDevice  *device)
+{
+  GdkDeviceGrabInfo *info;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
+  g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
+
+  /* What we're interested in is the steady state (ie last grab),
+     because we're interested e.g. if we grabbed so that we
+     can ungrab, even if our grab is not active just yet. */
+  info = _gdk_display_get_last_device_grab (display, device);
+
   return (info && !info->implicit);
 }
 
-#define __GDK_DISPLAY_C__
-#include "gdkaliasdef.c"
+/**
+ * gdk_display_get_device_manager:
+ * @display: a #GdkDisplay.
+ *
+ * Returns the #GdkDeviceManager associated to @display.
+ *
+ * Returns: (transfer none): A #GdkDeviceManager, or %NULL. This memory is
+ *          owned by GDK and must not be freed or unreferenced.
+ *
+ * Since: 3.0
+ **/
+GdkDeviceManager *
+gdk_display_get_device_manager (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+  return display->device_manager;
+}
+
+/**
+ * gdk_display_get_name:
+ * @display: a #GdkDisplay
+ *
+ * Gets the name of the display.
+ *
+ * Returns: a string representing the display name. This string is owned
+ * by GDK and should not be modified or freed.
+ *
+ * Since: 2.2
+ */
+G_CONST_RETURN gchar *
+gdk_display_get_name (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->get_name (display);
+}
+
+gchar *
+gdk_get_display (void)
+{
+  return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
+}
+
+/**
+ * gdk_display_get_n_screens:
+ * @display: a #GdkDisplay
+ *
+ * Gets the number of screen managed by the @display.
+ *
+ * Returns: number of screens.
+ *
+ * Since: 2.2
+ */
+gint
+gdk_display_get_n_screens (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->get_n_screens (display);
+}
+
+/**
+ * gdk_display_get_screen:
+ * @display: a #GdkDisplay
+ * @screen_num: the screen number
+ *
+ * Returns a screen object for one of the screens of the display.
+ *
+ * Returns: (transfer none): the #GdkScreen object
+ *
+ * Since: 2.2
+ */
+GdkScreen *
+gdk_display_get_screen (GdkDisplay *display,
+                       gint        screen_num)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->get_screen (display, screen_num);
+}
+
+/**
+ * gdk_display_get_default_screen:
+ * @display: a #GdkDisplay
+ *
+ * Get the default #GdkScreen for @display.
+ *
+ * Returns: (transfer none): the default #GdkScreen object for @display
+ *
+ * Since: 2.2
+ */
+GdkScreen *
+gdk_display_get_default_screen (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->get_default_screen (display);
+}
+
+/**
+ * gdk_display_beep:
+ * @display: a #GdkDisplay
+ *
+ * Emits a short beep on @display
+ *
+ * Since: 2.2
+ */
+void
+gdk_display_beep (GdkDisplay *display)
+{
+  GDK_DISPLAY_GET_CLASS(display)->beep (display);
+}
+
+/**
+ * gdk_display_sync:
+ * @display: a #GdkDisplay
+ *
+ * Flushes any requests queued for the windowing system and waits until all
+ * requests have been handled. This is often used for making sure that the
+ * display is synchronized with the current state of the program. Calling
+ * gdk_display_sync() before gdk_error_trap_pop() makes sure that any errors
+ * generated from earlier requests are handled before the error trap is
+ * removed.
+ *
+ * This is most useful for X11. On windowing systems where requests are
+ * handled synchronously, this function will do nothing.
+ *
+ * Since: 2.2
+ */
+void
+gdk_display_sync (GdkDisplay *display)
+{
+  GDK_DISPLAY_GET_CLASS(display)->sync (display);
+}
+
+/**
+ * gdk_display_flush:
+ * @display: a #GdkDisplay
+ *
+ * Flushes any requests queued for the windowing system; this happens automatically
+ * when the main loop blocks waiting for new events, but if your application
+ * is drawing without returning control to the main loop, you may need
+ * to call this function explicitely. A common case where this function
+ * needs to be called is when an application is executing drawing commands
+ * from a thread other than the thread where the main loop is running.
+ *
+ * This is most useful for X11. On windowing systems where requests are
+ * handled synchronously, this function will do nothing.
+ *
+ * Since: 2.4
+ */
+void
+gdk_display_flush (GdkDisplay *display)
+{
+  GDK_DISPLAY_GET_CLASS(display)->flush (display);
+}
+
+/**
+ * gdk_display_get_default_group:
+ * @display: a #GdkDisplay
+ *
+ * Returns the default group leader window for all toplevel windows
+ * on @display. This window is implicitly created by GDK.
+ * See gdk_window_set_group().
+ *
+ * Return value: (transfer none): The default group leader window
+ * for @display
+ *
+ * Since: 2.4
+ **/
+GdkWindow *
+gdk_display_get_default_group (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->get_default_group (display);
+}
+
+/**
+ * gdk_display_supports_selection_notification:
+ * @display: a #GdkDisplay
+ *
+ * Returns whether #GdkEventOwnerChange events will be
+ * sent when the owner of a selection changes.
+ *
+ * Return value: whether #GdkEventOwnerChange events will
+ *               be sent.
+ *
+ * Since: 2.6
+ **/
+gboolean
+gdk_display_supports_selection_notification (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->supports_selection_notification (display);
+}
+
+/**
+ * gdk_display_request_selection_notification:
+ * @display: a #GdkDisplay
+ * @selection: the #GdkAtom naming the selection for which
+ *             ownership change notification is requested
+ *
+ * Request #GdkEventOwnerChange events for ownership changes
+ * of the selection named by the given atom.
+ *
+ * Return value: whether #GdkEventOwnerChange events will
+ *               be sent.
+ *
+ * Since: 2.6
+ **/
+gboolean
+gdk_display_request_selection_notification (GdkDisplay *display,
+                                           GdkAtom     selection)
+
+{
+  return GDK_DISPLAY_GET_CLASS(display)->request_selection_notification (display, selection);
+}
+
+/**
+ * gdk_display_supports_clipboard_persistence
+ * @display: a #GdkDisplay
+ *
+ * Returns whether the speicifed display supports clipboard
+ * persistance; i.e. if it's possible to store the clipboard data after an
+ * application has quit. On X11 this checks if a clipboard daemon is
+ * running.
+ *
+ * Returns: %TRUE if the display supports clipboard persistance.
+ *
+ * Since: 2.6
+ */
+gboolean
+gdk_display_supports_clipboard_persistence (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->supports_clipboard_persistence (display);
+}
+
+/**
+ * gdk_display_store_clipboard
+ * @display:          a #GdkDisplay
+ * @clipboard_window: a #GdkWindow belonging to the clipboard owner
+ * @time_:            a timestamp
+ * @targets:         an array of targets that should be saved, or %NULL
+ *                    if all available targets should be saved.
+ * @n_targets:        length of the @targets array
+ *
+ * Issues a request to the clipboard manager to store the
+ * clipboard data. On X11, this is a special program that works
+ * according to the freedesktop clipboard specification, available at
+ * <ulink url="http://www.freedesktop.org/Standards/clipboard-manager-spec">
+ * http://www.freedesktop.org/Standards/clipboard-manager-spec</ulink>.
+ *
+ * Since: 2.6
+ */
+void
+gdk_display_store_clipboard (GdkDisplay    *display,
+                            GdkWindow     *clipboard_window,
+                            guint32        time_,
+                            const GdkAtom *targets,
+                            gint           n_targets)
+{
+  GDK_DISPLAY_GET_CLASS(display)->store_clipboard (display, clipboard_window, time_, targets, n_targets);
+}
+
+/**
+ * gdk_display_supports_shapes:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if gdk_window_shape_combine_mask() can
+ * be used to create shaped windows on @display.
+ *
+ * Returns: %TRUE if shaped windows are supported
+ *
+ * Since: 2.10
+ */
+gboolean
+gdk_display_supports_shapes (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->supports_shapes (display);
+}
+
+/**
+ * gdk_display_supports_input_shapes:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if gdk_window_input_shape_combine_mask() can
+ * be used to modify the input shape of windows on @display.
+ *
+ * Returns: %TRUE if windows with modified input shape are supported
+ *
+ * Since: 2.10
+ */
+gboolean
+gdk_display_supports_input_shapes (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->supports_input_shapes (display);
+}
+
+/**
+ * gdk_display_supports_composite:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if gdk_window_set_composited() can be used
+ * to redirect drawing on the window using compositing.
+ *
+ * Currently this only works on X11 with XComposite and
+ * XDamage extensions available.
+ *
+ * Returns: %TRUE if windows may be composited.
+ *
+ * Since: 2.12
+ */
+gboolean
+gdk_display_supports_composite (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->supports_composite (display);
+}
+
+/**
+ * gdk_display_list_devices:
+ * @display: a #GdkDisplay
+ *
+ * Returns the list of available input devices attached to @display.
+ * The list is statically allocated and should not be freed.
+ *
+ * Return value: (transfer none) (element-type GdkDevice):
+ *     a list of #GdkDevice
+ *
+ * Since: 2.2
+ *
+ * Deprecated: 3.0: Use gdk_device_manager_list_devices() instead.
+ **/
+GList *
+gdk_display_list_devices (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->list_devices (display);
+}
+
+/**
+ * gdk_event_send_client_message_for_display:
+ * @display: the #GdkDisplay for the window where the message is to be sent.
+ * @event: the #GdkEvent to send, which should be a #GdkEventClient.
+ * @winid: the window to send the client message to.
+ *
+ * On X11, sends an X ClientMessage event to a given window. On
+ * Windows, sends a message registered with the name
+ * GDK_WIN32_CLIENT_MESSAGE.
+ *
+ * This could be used for communicating between different
+ * applications, though the amount of data is limited to 20 bytes on
+ * X11, and to just four bytes on Windows.
+ *
+ * Returns: non-zero on success.
+ *
+ * Since: 2.2
+ */
+gboolean
+gdk_event_send_client_message_for_display (GdkDisplay     *display,
+                                          GdkEvent       *event,
+                                          GdkNativeWindow winid)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->send_client_message (display, event, winid);
+}
+
+/**
+ * gdk_display_add_client_message_filter:
+ * @display: a #GdkDisplay for which this message filter applies
+ * @message_type: the type of ClientMessage events to receive.
+ *   This will be checked against the @message_type field
+ *   of the XClientMessage event struct.
+ * @func: the function to call to process the event.
+ * @data: user data to pass to @func.
+ *
+ * Adds a filter to be called when X ClientMessage events are received.
+ * See gdk_window_add_filter() if you are interested in filtering other
+ * types of events.
+ *
+ * Since: 2.2
+ **/
+void
+gdk_display_add_client_message_filter (GdkDisplay   *display,
+                                      GdkAtom       message_type,
+                                      GdkFilterFunc func,
+                                      gpointer      data)
+{
+  GDK_DISPLAY_GET_CLASS(display)->add_client_message_filter (display, message_type, func, data);
+}
+
+/**
+ * gdk_add_client_message_filter:
+ * @message_type: the type of ClientMessage events to receive. This will be
+ *     checked against the <structfield>message_type</structfield> field of the
+ *     XClientMessage event struct.
+ * @func: the function to call to process the event.
+ * @data: user data to pass to @func.
+ *
+ * Adds a filter to the default display to be called when X ClientMessage events
+ * are received. See gdk_display_add_client_message_filter().
+ **/
+void
+gdk_add_client_message_filter (GdkAtom       message_type,
+                              GdkFilterFunc func,
+                              gpointer      data)
+{
+  gdk_display_add_client_message_filter (gdk_display_get_default (),
+                                        message_type, func, data);
+}
+
+static GdkAppLaunchContext *
+gdk_display_real_get_app_launch_context (GdkDisplay *display)
+{
+  GdkAppLaunchContext *ctx;
+
+  ctx = gdk_app_launch_context_new ();
+  gdk_app_launch_context_set_display (ctx, display);
+
+  return ctx;
+}
+
+/**
+ * gdk_display_get_app_launch_context:
+ * @display: a #GdkDisplay
+ *
+ * Returns a #GdkAppLaunchContext suitable for launching
+ * applications on the given display.
+ *
+ * Returns: a new #GdkAppLaunchContext for @display.
+ *     Free with g_object_unref() when done
+ *
+ * Since: 3.0
+ */
+GdkAppLaunchContext *
+gdk_display_get_app_launch_context (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS(display)->get_app_launch_context (display);
+}
+
+/**
+ * gdk_drag_get_protocol_for_display:
+ * @display: the #GdkDisplay where the destination window resides
+ * @xid: the windowing system id of the destination window.
+ * @protocol: location where the supported DND protocol is returned.
+ *
+ * Finds out the DND protocol supported by a window.
+ *
+ * Return value: the windowing system id of the window where the drop
+ *    should happen. This may be @xid or the id of a proxy window,
+ *    or zero if @xid does not support Drag and Drop.
+ *
+ * Since: 2.2
+ */
+GdkNativeWindow
+gdk_drag_get_protocol_for_display (GdkDisplay      *display,
+                                   GdkNativeWindow  xid,
+                                   GdkDragProtocol *protocol)
+{
+  return GDK_DISPLAY_GET_CLASS (display)->get_drag_protocol (display, xid, protocol, NULL);
+}
+
+/**
+ * gdk_display_open:
+ * @display_name: the name of the display to open
+ *
+ * Opens a display.
+ *
+ * Return value: (transfer none): a #GdkDisplay, or %NULL if the display
+ *               could not be opened.
+ *
+ * Since: 2.2
+ */
+GdkDisplay *
+gdk_display_open (const gchar *display_name)
+{
+  return gdk_display_manager_open_display (gdk_display_manager_get (), display_name);
+}
+
+gboolean
+gdk_display_has_pending (GdkDisplay *display)
+{
+  return GDK_DISPLAY_GET_CLASS (display)->has_pending (display);
+}