]> Pileus Git - ~andy/gtk/blob - gdk/gdkdisplay.c
Merge branch 'windows_list'
[~andy/gtk] / gdk / gdkdisplay.c
1 /* GDK - The GIMP Drawing Kit
2  * gdkdisplay.c
3  * 
4  * Copyright 2001 Sun Microsystems Inc. 
5  *
6  * Erwann Chenede <erwann.chenede@sun.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "config.h"
25 #include <math.h>
26 #include <glib.h>
27 #include "gdk.h"                /* gdk_event_send_client_message() */
28 #include "gdkdisplay.h"
29 #include "gdkwindowimpl.h"
30 #include "gdkinternals.h"
31 #include "gdkmarshalers.h"
32 #include "gdkscreen.h"
33
34
35 enum {
36   OPENED,
37   CLOSED,
38   LAST_SIGNAL
39 };
40
41 static void gdk_display_dispose     (GObject         *object);
42 static void gdk_display_finalize    (GObject         *object);
43
44 static void        multihead_get_device_state           (GdkDisplay       *display,
45                                                          GdkDevice        *device,
46                                                          GdkScreen       **screen,
47                                                          gint             *x,
48                                                          gint             *y,
49                                                          GdkModifierType  *mask);
50 static GdkWindow * multihead_window_get_device_position (GdkDisplay       *display,
51                                                          GdkDevice        *device,
52                                                          GdkWindow        *window,
53                                                          gint             *x,
54                                                          gint             *y,
55                                                          GdkModifierType  *mask);
56 static GdkWindow * multihead_window_at_device_position  (GdkDisplay       *display,
57                                                          GdkDevice        *device,
58                                                          gint             *win_x,
59                                                          gint             *win_y);
60
61 static void        multihead_default_get_pointer        (GdkDisplay       *display,
62                                                          GdkScreen       **screen,
63                                                          gint             *x,
64                                                          gint             *y,
65                                                          GdkModifierType  *mask);
66 static GdkWindow * multihead_default_window_get_pointer (GdkDisplay      *display,
67                                                          GdkWindow       *window,
68                                                          gint            *x,
69                                                          gint            *y,
70                                                          GdkModifierType *mask);
71 static GdkWindow * multihead_default_window_at_pointer  (GdkDisplay      *display,
72                                                          gint            *win_x,
73                                                          gint            *win_y);
74
75
76 static void       singlehead_get_pointer (GdkDisplay       *display,
77                                           GdkScreen       **screen,
78                                           gint             *x,
79                                           gint             *y,
80                                           GdkModifierType  *mask);
81 static GdkWindow* singlehead_window_get_pointer (GdkDisplay       *display,
82                                                  GdkWindow        *window,
83                                                  gint             *x,
84                                                  gint             *y,
85                                                  GdkModifierType  *mask);
86 static GdkWindow* singlehead_window_at_pointer  (GdkDisplay       *display,
87                                                  gint             *win_x,
88                                                  gint             *win_y);
89
90 static GdkWindow* singlehead_default_window_get_pointer (GdkWindow       *window,
91                                                          gint            *x,
92                                                          gint            *y,
93                                                          GdkModifierType *mask);
94 static GdkWindow* singlehead_default_window_at_pointer  (GdkScreen       *screen,
95                                                          gint            *win_x,
96                                                          gint            *win_y);
97 static GdkWindow *gdk_window_real_window_get_device_position     (GdkDisplay       *display,
98                                                                   GdkDevice        *device,
99                                                                   GdkWindow        *window,
100                                                                   gint             *x,
101                                                                   gint             *y,
102                                                                   GdkModifierType  *mask);
103 static GdkWindow *gdk_display_real_get_window_at_device_position (GdkDisplay       *display,
104                                                                   GdkDevice        *device,
105                                                                   gint             *win_x,
106                                                                   gint             *win_y);
107
108 static guint signals[LAST_SIGNAL] = { 0 };
109
110 static char *gdk_sm_client_id;
111
112 static const GdkDisplayDeviceHooks default_device_hooks = {
113   _gdk_windowing_get_device_state,
114   gdk_window_real_window_get_device_position,
115   gdk_display_real_get_window_at_device_position
116 };
117
118 static const GdkDisplayDeviceHooks multihead_pointer_hooks = {
119   multihead_get_device_state,
120   multihead_window_get_device_position,
121   multihead_window_at_device_position
122 };
123
124 static const GdkDisplayPointerHooks multihead_default_pointer_hooks = {
125   multihead_default_get_pointer,
126   multihead_default_window_get_pointer,
127   multihead_default_window_at_pointer
128 };
129
130 static const GdkDisplayPointerHooks singlehead_pointer_hooks = {
131   singlehead_get_pointer,
132   singlehead_window_get_pointer,
133   singlehead_window_at_pointer
134 };
135
136 static const GdkPointerHooks singlehead_default_pointer_hooks = {
137   singlehead_default_window_get_pointer,
138   singlehead_default_window_at_pointer
139 };
140
141 static const GdkPointerHooks *singlehead_current_pointer_hooks = &singlehead_default_pointer_hooks;
142 static const GdkDisplayPointerHooks *multihead_current_pointer_hooks = &multihead_default_pointer_hooks;
143
144 G_DEFINE_TYPE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
145
146 static void
147 gdk_display_class_init (GdkDisplayClass *class)
148 {
149   GObjectClass *object_class = G_OBJECT_CLASS (class);
150
151   object_class->finalize = gdk_display_finalize;
152   object_class->dispose = gdk_display_dispose;
153
154   /**
155    * GdkDisplay::opened:
156    * @display: the object on which the signal is emitted
157    *
158    * The ::opened signal is emitted when the connection to the windowing
159    * system for @display is opened.
160    */
161   signals[OPENED] =
162     g_signal_new (g_intern_static_string ("opened"),
163                   G_OBJECT_CLASS_TYPE (object_class),
164                   G_SIGNAL_RUN_LAST,
165                   0, NULL, NULL,
166                   g_cclosure_marshal_VOID__VOID,
167                   G_TYPE_NONE, 0);
168
169   /**
170    * GdkDisplay::closed:
171    * @display: the object on which the signal is emitted
172    * @is_error: %TRUE if the display was closed due to an error
173    *
174    * The ::closed signal is emitted when the connection to the windowing
175    * system for @display is closed.
176    *
177    * Since: 2.2
178    */   
179   signals[CLOSED] =
180     g_signal_new (g_intern_static_string ("closed"),
181                   G_OBJECT_CLASS_TYPE (object_class),
182                   G_SIGNAL_RUN_LAST,
183                   G_STRUCT_OFFSET (GdkDisplayClass, closed),
184                   NULL, NULL,
185                   _gdk_marshal_VOID__BOOLEAN,
186                   G_TYPE_NONE,
187                   1,
188                   G_TYPE_BOOLEAN);
189 }
190
191 static void
192 free_pointer_info (GdkPointerWindowInfo *info)
193 {
194   g_object_unref (info->toplevel_under_pointer);
195   g_slice_free (GdkPointerWindowInfo, info);
196 }
197
198 static void
199 free_device_grab (GdkDeviceGrabInfo *info)
200 {
201   g_object_unref (info->window);
202   g_object_unref (info->native_window);
203   g_free (info);
204 }
205
206 static gboolean
207 free_device_grabs_foreach (gpointer key,
208                            gpointer value,
209                            gpointer user_data)
210 {
211   GList *list = value;
212
213   g_list_foreach (list, (GFunc) free_device_grab, NULL);
214   g_list_free (list);
215
216   return TRUE;
217 }
218
219 static void
220 device_removed_cb (GdkDeviceManager *device_manager,
221                    GdkDevice        *device,
222                    GdkDisplay       *display)
223 {
224   g_hash_table_remove (display->multiple_click_info, device);
225   g_hash_table_remove (display->device_grabs, device);
226   g_hash_table_remove (display->pointers_info, device);
227
228   /* FIXME: change core pointer and remove from device list */
229 }
230
231 static void
232 gdk_display_opened (GdkDisplay *display)
233 {
234   GdkDeviceManager *device_manager;
235
236   device_manager = gdk_display_get_device_manager (display);
237
238   g_signal_connect (device_manager, "device-removed",
239                     G_CALLBACK (device_removed_cb), display);
240 }
241
242 static void
243 gdk_display_init (GdkDisplay *display)
244 {
245   _gdk_displays = g_slist_prepend (_gdk_displays, display);
246
247   display->double_click_time = 250;
248   display->double_click_distance = 5;
249
250   display->device_hooks = &default_device_hooks;
251
252   display->device_grabs = g_hash_table_new (NULL, NULL);
253   display->motion_hint_info = g_hash_table_new_full (NULL, NULL, NULL,
254                                                      (GDestroyNotify) g_free);
255
256   display->pointers_info = g_hash_table_new_full (NULL, NULL, NULL,
257                                                   (GDestroyNotify) free_pointer_info);
258
259   display->multiple_click_info = g_hash_table_new_full (NULL, NULL, NULL,
260                                                         (GDestroyNotify) g_free);
261
262   g_signal_connect (display, "opened",
263                     G_CALLBACK (gdk_display_opened), NULL);
264 }
265
266 static void
267 gdk_display_dispose (GObject *object)
268 {
269   GdkDisplay *display = GDK_DISPLAY_OBJECT (object);
270   GdkDeviceManager *device_manager;
271
272   device_manager = gdk_display_get_device_manager (GDK_DISPLAY_OBJECT (object));
273
274   g_list_foreach (display->queued_events, (GFunc)gdk_event_free, NULL);
275   g_list_free (display->queued_events);
276   display->queued_events = NULL;
277   display->queued_tail = NULL;
278
279   _gdk_displays = g_slist_remove (_gdk_displays, object);
280
281   if (gdk_display_get_default() == display)
282     {
283       if (_gdk_displays)
284         gdk_display_manager_set_default_display (gdk_display_manager_get(),
285                                                  _gdk_displays->data);
286       else
287         gdk_display_manager_set_default_display (gdk_display_manager_get(),
288                                                  NULL);
289     }
290
291   if (device_manager)
292     g_signal_handlers_disconnect_by_func (device_manager, device_removed_cb, object);
293
294   G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
295 }
296
297 static void
298 gdk_display_finalize (GObject *object)
299 {
300   GdkDisplay *display = GDK_DISPLAY_OBJECT (object);
301
302   g_hash_table_foreach_remove (display->device_grabs,
303                                free_device_grabs_foreach,
304                                NULL);
305   g_hash_table_destroy (display->device_grabs);
306
307   g_hash_table_destroy (display->pointers_info);
308   g_hash_table_destroy (display->multiple_click_info);
309
310   if (display->device_manager)
311     g_object_unref (display->device_manager);
312
313   G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
314 }
315
316 /**
317  * gdk_display_close:
318  * @display: a #GdkDisplay
319  *
320  * Closes the connection to the windowing system for the given display,
321  * and cleans up associated resources.
322  *
323  * Since: 2.2
324  */
325 void
326 gdk_display_close (GdkDisplay *display)
327 {
328   g_return_if_fail (GDK_IS_DISPLAY (display));
329
330   if (!display->closed)
331     {
332       display->closed = TRUE;
333       
334       g_signal_emit (display, signals[CLOSED], 0, FALSE);
335       g_object_run_dispose (G_OBJECT (display));
336       
337       g_object_unref (display);
338     }
339 }
340
341 /**
342  * gdk_display_get_event:
343  * @display: a #GdkDisplay
344  * 
345  * Gets the next #GdkEvent to be processed for @display, fetching events from the
346  * windowing system if necessary.
347  * 
348  * Return value: the next #GdkEvent to be processed, or %NULL if no events
349  * are pending. The returned #GdkEvent should be freed with gdk_event_free().
350  *
351  * Since: 2.2
352  **/
353 GdkEvent*
354 gdk_display_get_event (GdkDisplay *display)
355 {
356   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
357   
358   _gdk_events_queue (display);
359   return _gdk_event_unqueue (display);
360 }
361
362 /**
363  * gdk_display_peek_event:
364  * @display: a #GdkDisplay 
365  * 
366  * Gets a copy of the first #GdkEvent in the @display's event queue, without
367  * removing the event from the queue.  (Note that this function will
368  * not get more events from the windowing system.  It only checks the events
369  * that have already been moved to the GDK event queue.)
370  * 
371  * Return value: a copy of the first #GdkEvent on the event queue, or %NULL 
372  * if no events are in the queue. The returned #GdkEvent should be freed with
373  * gdk_event_free().
374  *
375  * Since: 2.2
376  **/
377 GdkEvent*
378 gdk_display_peek_event (GdkDisplay *display)
379 {
380   GList *tmp_list;
381
382   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
383
384   tmp_list = _gdk_event_queue_find_first (display);
385   
386   if (tmp_list)
387     return gdk_event_copy (tmp_list->data);
388   else
389     return NULL;
390 }
391
392 /**
393  * gdk_display_put_event:
394  * @display: a #GdkDisplay
395  * @event: a #GdkEvent.
396  *
397  * Appends a copy of the given event onto the front of the event
398  * queue for @display.
399  *
400  * Since: 2.2
401  **/
402 void
403 gdk_display_put_event (GdkDisplay     *display,
404                        const GdkEvent *event)
405 {
406   g_return_if_fail (GDK_IS_DISPLAY (display));
407   g_return_if_fail (event != NULL);
408
409   _gdk_event_queue_append (display, gdk_event_copy (event));
410   /* If the main loop is blocking in a different thread, wake it up */
411   g_main_context_wakeup (NULL); 
412 }
413
414 /**
415  * gdk_display_pointer_ungrab:
416  * @display: a #GdkDisplay.
417  * @time_: a timestap (e.g. %GDK_CURRENT_TIME).
418  *
419  * Release any pointer grab.
420  *
421  * Since: 2.2
422  *
423  * Deprecated: 3.0: Use gdk_device_ungrab(), together with gdk_device_grab()
424  *             instead.
425  */
426 void
427 gdk_display_pointer_ungrab (GdkDisplay *display,
428                             guint32     time_)
429 {
430   GdkDeviceManager *device_manager;
431   GList *devices, *dev;
432   GdkDevice *device;
433
434   g_return_if_fail (GDK_IS_DISPLAY (display));
435
436   device_manager = gdk_display_get_device_manager (display);
437   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
438
439   /* FIXME: Should this be generic to all backends? */
440   /* FIXME: What happens with extended devices? */
441   for (dev = devices; dev; dev = dev->next)
442     {
443       device = dev->data;
444
445       if (device->source != GDK_SOURCE_MOUSE)
446         continue;
447
448       gdk_device_ungrab (device, time_);
449     }
450
451   g_list_free (devices);
452 }
453
454 /**
455  * gdk_pointer_ungrab:
456  * @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no 
457  *  timestamp is available.
458  *
459  * Ungrabs the pointer on the default display, if it is grabbed by this 
460  * application.
461  *
462  * Deprecated: 3.0: Use gdk_device_ungrab(), together with gdk_device_grab()
463  *             instead.
464  **/
465 void
466 gdk_pointer_ungrab (guint32 time)
467 {
468   gdk_display_pointer_ungrab (gdk_display_get_default (), time);
469 }
470
471 /**
472  * gdk_pointer_is_grabbed:
473  * 
474  * Returns %TRUE if the pointer on the default display is currently 
475  * grabbed by this application.
476  *
477  * Note that this does not take the inmplicit pointer grab on button
478  * presses into account.
479  *
480  * Return value: %TRUE if the pointer is currently grabbed by this application.
481  *
482  * Deprecated: 3.0: Use gdk_display_device_is_grabbed() instead.
483  **/
484 gboolean
485 gdk_pointer_is_grabbed (void)
486 {
487   return gdk_display_pointer_is_grabbed (gdk_display_get_default ());
488 }
489
490 /**
491  * gdk_display_keyboard_ungrab:
492  * @display: a #GdkDisplay.
493  * @time_: a timestap (e.g #GDK_CURRENT_TIME).
494  *
495  * Release any keyboard grab
496  *
497  * Since: 2.2
498  *
499  * Deprecated: 3.0: Use gdk_device_ungrab(), together with gdk_device_grab()
500  *             instead.
501  */
502 void
503 gdk_display_keyboard_ungrab (GdkDisplay *display,
504                              guint32     time)
505 {
506   GdkDeviceManager *device_manager;
507   GList *devices, *dev;
508   GdkDevice *device;
509
510   g_return_if_fail (GDK_IS_DISPLAY (display));
511
512   device_manager = gdk_display_get_device_manager (display);
513   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
514
515   /* FIXME: Should this be generic to all backends? */
516   /* FIXME: What happens with extended devices? */
517   for (dev = devices; dev; dev = dev->next)
518     {
519       device = dev->data;
520
521       if (device->source != GDK_SOURCE_KEYBOARD)
522         continue;
523
524       gdk_device_ungrab (device, time);
525     }
526
527   g_list_free (devices);
528 }
529
530 /**
531  * gdk_keyboard_ungrab:
532  * @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no
533  *        timestamp is available.
534  * 
535  * Ungrabs the keyboard on the default display, if it is grabbed by this 
536  * application.
537  *
538  * Deprecated: 3.0: Use gdk_device_ungrab(), together with gdk_device_grab()
539  *             instead.
540  **/
541 void
542 gdk_keyboard_ungrab (guint32 time)
543 {
544   gdk_display_keyboard_ungrab (gdk_display_get_default (), time);
545 }
546
547 /**
548  * gdk_beep:
549  * 
550  * Emits a short beep on the default display.
551  **/
552 void
553 gdk_beep (void)
554 {
555   gdk_display_beep (gdk_display_get_default ());
556 }
557
558 /**
559  * gdk_event_send_client_message:
560  * @event: the #GdkEvent to send, which should be a #GdkEventClient.
561  * @winid:  the window to send the X ClientMessage event to.
562  * 
563  * Sends an X ClientMessage event to a given window (which must be
564  * on the default #GdkDisplay.)
565  * This could be used for communicating between different applications,
566  * though the amount of data is limited to 20 bytes.
567  * 
568  * Return value: non-zero on success.
569  **/
570 gboolean
571 gdk_event_send_client_message (GdkEvent        *event,
572                                GdkNativeWindow  winid)
573 {
574   g_return_val_if_fail (event != NULL, FALSE);
575
576   return gdk_event_send_client_message_for_display (gdk_display_get_default (),
577                                                     event, winid);
578 }
579
580 /**
581  * gdk_event_send_clientmessage_toall:
582  * @event: the #GdkEvent to send, which should be a #GdkEventClient.
583  *
584  * Sends an X ClientMessage event to all toplevel windows on the default
585  * #GdkScreen.
586  *
587  * Toplevel windows are determined by checking for the WM_STATE property, as
588  * described in the Inter-Client Communication Conventions Manual (ICCCM).
589  * If no windows are found with the WM_STATE property set, the message is sent
590  * to all children of the root window.
591  **/
592 void
593 gdk_event_send_clientmessage_toall (GdkEvent *event)
594 {
595   g_return_if_fail (event != NULL);
596
597   gdk_screen_broadcast_client_message (gdk_screen_get_default (), event);
598 }
599
600 /**
601  * gdk_device_get_core_pointer:
602  * 
603  * Returns the core pointer device for the default display.
604  * 
605  * Return value: the core pointer device; this is owned by the
606  *   display and should not be freed.
607  *
608  * Deprecated: 3.0: Use gdk_display_get_client_pointer() instead, or
609  *             gdk_event_get_device() if a #GdkEvent with pointer device
610  *             information is available.
611  **/
612 GdkDevice *
613 gdk_device_get_core_pointer (void)
614 {
615   return gdk_display_get_core_pointer (gdk_display_get_default ());
616 }
617
618 /**
619  * gdk_display_get_core_pointer:
620  * @display: a #GdkDisplay
621  * 
622  * Returns the core pointer device for the given display
623  * 
624  * Return value: the core pointer device; this is owned by the
625  *   display and should not be freed.
626  *
627  * Since: 2.2
628  *
629  * Deprecated: 3.0: Use gdk_display_get_client_pointer() instead, or
630  *             gdk_event_get_device() if a #GdkEvent with device
631  *             information is available.
632  **/
633 GdkDevice *
634 gdk_display_get_core_pointer (GdkDisplay *display)
635 {
636   return display->core_pointer;
637 }
638
639 /**
640  * gdk_set_sm_client_id:
641  * @sm_client_id: the client id assigned by the session manager when the
642  *    connection was opened, or %NULL to remove the property.
643  * 
644  * Sets the <literal>SM_CLIENT_ID</literal> property on the application's leader window so that
645  * the window manager can save the application's state using the X11R6 ICCCM
646  * session management protocol.
647  *
648  * See the X Session Management Library documentation for more information on
649  * session management and the Inter-Client Communication Conventions Manual
650  * (ICCCM) for information on the <literal>WM_CLIENT_LEADER</literal> property. 
651  * (Both documents are part of the X Window System distribution.)
652  **/
653 void
654 gdk_set_sm_client_id (const gchar* sm_client_id)
655 {
656   GSList *displays, *tmp_list;
657   
658   g_free (gdk_sm_client_id);
659   gdk_sm_client_id = g_strdup (sm_client_id);
660
661   displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
662   for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
663     _gdk_windowing_display_set_sm_client_id (tmp_list->data, sm_client_id);
664
665   g_slist_free (displays);
666 }
667
668 /**
669  * _gdk_get_sm_client_id:
670  * 
671  * Gets the client ID set with gdk_set_sm_client_id(), if any.
672  * 
673  * Return value: Session ID, or %NULL if gdk_set_sm_client_id()
674  *               has never been called.
675  **/
676 const char *
677 _gdk_get_sm_client_id (void)
678 {
679   return gdk_sm_client_id;
680 }
681
682 void
683 _gdk_display_enable_motion_hints (GdkDisplay *display,
684                                   GdkDevice  *device)
685 {
686   gulong *device_serial, serial;
687
688   device_serial = g_hash_table_lookup (display->motion_hint_info, device);
689
690   if (!device_serial)
691     {
692       device_serial = g_new0 (gulong, 1);
693       *device_serial = G_MAXULONG;
694       g_hash_table_insert (display->motion_hint_info, device, device_serial);
695     }
696
697   if (*device_serial != 0)
698     {
699       serial = _gdk_windowing_window_get_next_serial (display);
700       /* We might not actually generate the next request, so
701          make sure this triggers always, this may cause it to
702          trigger slightly too early, but this is just a hint
703          anyway. */
704       if (serial > 0)
705         serial--;
706       if (serial < *device_serial)
707         *device_serial = serial;
708     }
709 }
710
711 /**
712  * gdk_display_get_device_state:
713  * @display: a #GdkDisplay.
714  * @device: device to query status to.
715  * @screen: location to store the #GdkScreen the @device is on, or %NULL.
716  * @x: location to store root window X coordinate of @device, or %NULL.
717  * @y: location to store root window Y coordinate of @device, or %NULL.
718  * @mask: location to store current modifier mask for @device, or %NULL.
719  *
720  * Gets the current location and state of @device for a given display.
721  *
722  * Since: 3.0
723  **/
724 void
725 gdk_display_get_device_state (GdkDisplay       *display,
726                               GdkDevice        *device,
727                               GdkScreen       **screen,
728                               gint             *x,
729                               gint             *y,
730                               GdkModifierType  *mask)
731 {
732   GdkScreen *tmp_screen;
733   gint tmp_x, tmp_y;
734   GdkModifierType tmp_mask;
735
736   g_return_if_fail (GDK_IS_DISPLAY (display));
737   g_return_if_fail (GDK_IS_DEVICE (device));
738
739   display->device_hooks->get_device_state (display, device, &tmp_screen, &tmp_x, &tmp_y, &tmp_mask);
740
741   if (screen)
742     *screen = tmp_screen;
743   if (x)
744     *x = tmp_x;
745   if (y)
746     *y = tmp_y;
747   if (mask)
748     *mask = tmp_mask;
749 }
750
751 /**
752  * gdk_display_get_window_at_device_position:
753  * @display: a #GdkDisplay.
754  * @device: #GdkDevice to query info to.
755  * @win_x: return location for the X coordinate of the device location, relative to the window origin, or %NULL.
756  * @win_y: return location for the Y coordinate of the device location, relative to the window origin, or %NULL.
757  *
758  * Obtains the window underneath @device, returning the location of the device in @win_x and @win_y. Returns
759  * %NULL if the window tree under @device is not known to GDK (for example, belongs to another application).
760  *
761  * Returns: the #GdkWindow under the device position, or %NULL.
762  *
763  * Since: 3.0
764  **/
765 GdkWindow *
766 gdk_display_get_window_at_device_position (GdkDisplay *display,
767                                            GdkDevice  *device,
768                                            gint       *win_x,
769                                            gint       *win_y)
770 {
771   gint tmp_x, tmp_y;
772   GdkWindow *window;
773
774   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
775   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
776
777   window = display->device_hooks->window_at_device_position (display, device, &tmp_x, &tmp_y);
778
779   if (win_x)
780     *win_x = tmp_x;
781   if (win_y)
782     *win_y = tmp_y;
783
784   return window;
785 }
786
787 /**
788  * gdk_display_set_device_hooks:
789  * @display: a #GdkDisplay.
790  * @new_hooks: a table of pointers to functions for getting quantities related to all
791  *             devices position, or %NULL to restore the default table.
792  *
793  * This function allows for hooking into the operation of getting the current location of any
794  * #GdkDevice on a particular #GdkDisplay. This is only useful for such low-level tools as
795  * an event recorder. Applications should never have any reason to use this facility.
796  *
797  * Returns: The previous device hook table.
798  *
799  * Since: 3.0
800  **/
801 GdkDisplayDeviceHooks *
802 gdk_display_set_device_hooks (GdkDisplay                  *display,
803                               const GdkDisplayDeviceHooks *new_hooks)
804 {
805   const GdkDisplayDeviceHooks *result;
806
807   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
808   result = display->device_hooks;
809
810   if (new_hooks)
811     display->device_hooks = new_hooks;
812   else
813     display->device_hooks = &default_device_hooks;
814
815   return (GdkDisplayDeviceHooks *) result;
816 }
817
818 /**
819  * gdk_display_get_pointer:
820  * @display: a #GdkDisplay
821  * @screen: (allow-none): location to store the screen that the
822  *          cursor is on, or %NULL.
823  * @x: (out) (allow-none): location to store root window X coordinate of pointer, or %NULL.
824  * @y: (out) (allow-none): location to store root window Y coordinate of pointer, or %NULL.
825  * @mask: (out) (allow-none): location to store current modifier mask, or %NULL
826  *
827  * Gets the current location of the pointer and the current modifier
828  * mask for a given display.
829  *
830  * Since: 2.2
831  *
832  * Deprecated: 3.0: Use gdk_display_get_device_state() instead.
833  **/
834 void
835 gdk_display_get_pointer (GdkDisplay      *display,
836                          GdkScreen      **screen,
837                          gint            *x,
838                          gint            *y,
839                          GdkModifierType *mask)
840 {
841   g_return_if_fail (GDK_IS_DISPLAY (display));
842
843   gdk_display_get_device_state (display, display->core_pointer, screen, x, y, mask);
844 }
845
846 static GdkWindow *
847 gdk_display_real_get_window_at_device_position (GdkDisplay *display,
848                                                 GdkDevice  *device,
849                                                 gint       *win_x,
850                                                 gint       *win_y)
851 {
852   GdkWindow *window;
853   gint x, y;
854
855   window = _gdk_windowing_window_at_device_position (display, device, &x, &y, NULL, FALSE);
856
857   /* This might need corrections, as the native window returned
858      may contain client side children */
859   if (window)
860     {
861       double xx, yy;
862
863       window = _gdk_window_find_descendant_at (window,
864                                                x, y,
865                                                &xx, &yy);
866       x = floor (xx + 0.5);
867       y = floor (yy + 0.5);
868     }
869
870   *win_x = x;
871   *win_y = y;
872
873   return window;
874 }
875
876 static GdkWindow *
877 gdk_window_real_window_get_device_position (GdkDisplay       *display,
878                                             GdkDevice        *device,
879                                             GdkWindow        *window,
880                                             gint             *x,
881                                             gint             *y,
882                                             GdkModifierType  *mask)
883 {
884   GdkWindowObject *private;
885   gint tmpx, tmpy;
886   GdkModifierType tmp_mask;
887   gboolean normal_child;
888
889   private = (GdkWindowObject *) window;
890
891   normal_child = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_device_state (window,
892                                                                               device,
893                                                                               &tmpx, &tmpy,
894                                                                               &tmp_mask);
895   /* We got the coords on the impl, convert to the window */
896   tmpx -= private->abs_x;
897   tmpy -= private->abs_y;
898
899   if (x)
900     *x = tmpx;
901   if (y)
902     *y = tmpy;
903   if (mask)
904     *mask = tmp_mask;
905
906   if (normal_child)
907     return _gdk_window_find_child_at (window, tmpx, tmpy);
908   return NULL;
909 }
910
911 /**
912  * gdk_display_get_window_at_pointer:
913  * @display: a #GdkDisplay
914  * @win_x: (out) (allow-none): return location for x coordinate of the pointer location relative
915  *    to the window origin, or %NULL
916  * @win_y: (out) (allow-none): return location for y coordinate of the pointer location relative
917  &    to the window origin, or %NULL
918  *
919  * Obtains the window underneath the mouse pointer, returning the location
920  * of the pointer in that window in @win_x, @win_y for @screen. Returns %NULL
921  * if the window under the mouse pointer is not known to GDK (for example, 
922  * belongs to another application).
923  *
924  * Returns: (transfer none): the window under the mouse pointer, or %NULL
925  *
926  * Since: 2.2
927  *
928  * Deprecated: 3.0: Use gdk_display_get_window_at_device_position() instead.
929  **/
930 GdkWindow *
931 gdk_display_get_window_at_pointer (GdkDisplay *display,
932                                    gint       *win_x,
933                                    gint       *win_y)
934 {
935   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
936
937   return gdk_display_get_window_at_device_position (display, display->core_pointer, win_x, win_y);
938 }
939
940 static void
941 multihead_get_device_state (GdkDisplay       *display,
942                             GdkDevice        *device,
943                             GdkScreen       **screen,
944                             gint             *x,
945                             gint             *y,
946                             GdkModifierType  *mask)
947 {
948   multihead_current_pointer_hooks->get_pointer (display, screen, x, y, mask);
949 }
950
951 static GdkWindow *
952 multihead_window_get_device_position (GdkDisplay      *display,
953                                       GdkDevice       *device,
954                                       GdkWindow       *window,
955                                       gint            *x,
956                                       gint            *y,
957                                       GdkModifierType *mask)
958 {
959   return multihead_current_pointer_hooks->window_get_pointer (display, window, x, y, mask);
960 }
961
962 static GdkWindow *
963 multihead_window_at_device_position (GdkDisplay *display,
964                                      GdkDevice  *device,
965                                      gint       *win_x,
966                                      gint       *win_y)
967 {
968   return multihead_current_pointer_hooks->window_at_pointer (display, win_x, win_y);
969 }
970
971 static void
972 multihead_default_get_pointer (GdkDisplay       *display,
973                                GdkScreen       **screen,
974                                gint             *x,
975                                gint             *y,
976                                GdkModifierType  *mask)
977 {
978   return _gdk_windowing_get_device_state (display,
979                                           display->core_pointer,
980                                           screen, x, y, mask);
981 }
982
983 static GdkWindow *
984 multihead_default_window_get_pointer (GdkDisplay      *display,
985                                       GdkWindow       *window,
986                                       gint            *x,
987                                       gint            *y,
988                                       GdkModifierType *mask)
989 {
990   return gdk_window_real_window_get_device_position (display,
991                                                      display->core_pointer,
992                                                      window, x, y, mask);
993 }
994
995 static GdkWindow *
996 multihead_default_window_at_pointer (GdkDisplay *display,
997                                      gint       *win_x,
998                                      gint       *win_y)
999 {
1000   return gdk_display_real_get_window_at_device_position (display,
1001                                                          display->core_pointer,
1002                                                          win_x, win_y);
1003 }
1004
1005 /**
1006  * gdk_display_set_pointer_hooks:
1007  * @display: a #GdkDisplay
1008  * @new_hooks: a table of pointers to functions for getting
1009  *   quantities related to the current pointer position,
1010  *   or %NULL to restore the default table.
1011  * 
1012  * This function allows for hooking into the operation
1013  * of getting the current location of the pointer on a particular
1014  * display. This is only useful for such low-level tools as an
1015  * event recorder. Applications should never have any
1016  * reason to use this facility.
1017  *
1018  * Return value: the previous pointer hook table
1019  *
1020  * Since: 2.2
1021  *
1022  * Deprecated: 3.0: Use gdk_display_set_device_hooks() instead.
1023  **/
1024 GdkDisplayPointerHooks *
1025 gdk_display_set_pointer_hooks (GdkDisplay                   *display,
1026                                const GdkDisplayPointerHooks *new_hooks)
1027 {
1028   const GdkDisplayPointerHooks *result = multihead_current_pointer_hooks;
1029
1030   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1031
1032   if (new_hooks)
1033     multihead_current_pointer_hooks = new_hooks;
1034   else
1035     multihead_current_pointer_hooks = &multihead_default_pointer_hooks;
1036
1037   gdk_display_set_device_hooks (display, &multihead_pointer_hooks);
1038
1039   return (GdkDisplayPointerHooks *)result;
1040 }
1041
1042 static void
1043 singlehead_get_pointer (GdkDisplay       *display,
1044                         GdkScreen       **screen,
1045                         gint             *x,
1046                         gint             *y,
1047                         GdkModifierType  *mask)
1048 {
1049   GdkScreen *default_screen = gdk_display_get_default_screen (display);
1050   GdkWindow *root_window = gdk_screen_get_root_window (default_screen);
1051
1052   *screen = default_screen;
1053
1054   singlehead_current_pointer_hooks->get_pointer (root_window, x, y, mask);
1055 }
1056
1057 static GdkWindow*
1058 singlehead_window_get_pointer (GdkDisplay       *display,
1059                                GdkWindow        *window,
1060                                gint             *x,
1061                                gint             *y,
1062                                GdkModifierType  *mask)
1063 {
1064   return singlehead_current_pointer_hooks->get_pointer (window, x, y, mask);
1065 }
1066
1067 static GdkWindow*
1068 singlehead_window_at_pointer   (GdkDisplay *display,
1069                                 gint       *win_x,
1070                                 gint       *win_y)
1071 {
1072   GdkScreen *default_screen = gdk_display_get_default_screen (display);
1073
1074   return singlehead_current_pointer_hooks->window_at_pointer (default_screen,
1075                                                               win_x, win_y);
1076 }
1077
1078 static GdkWindow*
1079 singlehead_default_window_get_pointer (GdkWindow       *window,
1080                                        gint            *x,
1081                                        gint            *y,
1082                                        GdkModifierType *mask)
1083 {
1084   GdkDisplay *display;
1085
1086   display = gdk_drawable_get_display (window);
1087
1088   return gdk_window_real_window_get_device_position (display,
1089                                                      display->core_pointer,
1090                                                      window, x, y, mask);
1091 }
1092
1093 static GdkWindow*
1094 singlehead_default_window_at_pointer  (GdkScreen       *screen,
1095                                        gint            *win_x,
1096                                        gint            *win_y)
1097 {
1098   GdkDisplay *display;
1099
1100   display = gdk_screen_get_display (screen);
1101
1102   return gdk_display_real_get_window_at_device_position (display,
1103                                                          display->core_pointer,
1104                                                          win_x, win_y);
1105 }
1106
1107 /**
1108  * gdk_set_pointer_hooks:
1109  * @new_hooks: a table of pointers to functions for getting
1110  *   quantities related to the current pointer position,
1111  *   or %NULL to restore the default table.
1112  * 
1113  * This function allows for hooking into the operation
1114  * of getting the current location of the pointer. This
1115  * is only useful for such low-level tools as an
1116  * event recorder. Applications should never have any
1117  * reason to use this facility.
1118  *
1119  * This function is not multihead safe. For multihead operation,
1120  * see gdk_display_set_pointer_hooks().
1121  * 
1122  * Return value: the previous pointer hook table
1123  *
1124  * Deprecated: 3.0: Use gdk_display_set_device_hooks() instead.
1125  **/
1126 GdkPointerHooks *
1127 gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
1128 {
1129   const GdkPointerHooks *result = singlehead_current_pointer_hooks;
1130
1131   if (new_hooks)
1132     singlehead_current_pointer_hooks = new_hooks;
1133   else
1134     singlehead_current_pointer_hooks = &singlehead_default_pointer_hooks;
1135
1136   gdk_display_set_pointer_hooks (gdk_display_get_default (),
1137                                  &singlehead_pointer_hooks);
1138   
1139   return (GdkPointerHooks *)result;
1140 }
1141
1142 static void
1143 generate_grab_broken_event (GdkWindow *window,
1144                             GdkDevice *device,
1145                             gboolean   implicit,
1146                             GdkWindow *grab_window)
1147 {
1148   g_return_if_fail (window != NULL);
1149
1150   if (!GDK_WINDOW_DESTROYED (window))
1151     {
1152       GdkEvent *event;
1153
1154       event = gdk_event_new (GDK_GRAB_BROKEN);
1155       event->grab_broken.window = g_object_ref (window);
1156       event->grab_broken.send_event = FALSE;
1157       event->grab_broken.implicit = implicit;
1158       event->grab_broken.grab_window = grab_window;
1159       gdk_event_set_device (event, device);
1160       event->grab_broken.keyboard = (device->source == GDK_SOURCE_KEYBOARD) ? TRUE : FALSE;
1161
1162       gdk_event_put (event);
1163       gdk_event_free (event);
1164     }
1165 }
1166
1167 GdkDeviceGrabInfo *
1168 _gdk_display_get_last_device_grab (GdkDisplay *display,
1169                                    GdkDevice  *device)
1170 {
1171   GList *l;
1172
1173   l = g_hash_table_lookup (display->device_grabs, device);
1174
1175   if (l)
1176     {
1177       l = g_list_last (l);
1178       return l->data;
1179     }
1180
1181   return NULL;
1182 }
1183
1184 GdkDeviceGrabInfo *
1185 _gdk_display_add_device_grab (GdkDisplay       *display,
1186                               GdkDevice        *device,
1187                               GdkWindow        *window,
1188                               GdkWindow        *native_window,
1189                               GdkGrabOwnership  grab_ownership,
1190                               gboolean          owner_events,
1191                               GdkEventMask      event_mask,
1192                               unsigned long     serial_start,
1193                               guint32           time,
1194                               gboolean          implicit)
1195 {
1196   GdkDeviceGrabInfo *info, *other_info;
1197   GList *grabs, *l;
1198
1199   info = g_new0 (GdkDeviceGrabInfo, 1);
1200
1201   info->window = g_object_ref (window);
1202   info->native_window = g_object_ref (native_window);
1203   info->serial_start = serial_start;
1204   info->serial_end = G_MAXULONG;
1205   info->owner_events = owner_events;
1206   info->event_mask = event_mask;
1207   info->time = time;
1208   info->implicit = implicit;
1209   info->ownership = grab_ownership;
1210
1211   grabs = g_hash_table_lookup (display->device_grabs, device);
1212
1213   /* Find the first grab that has a larger start time (if any) and insert
1214    * before that. I.E we insert after already existing grabs with same
1215    * start time */
1216   for (l = grabs; l != NULL; l = l->next)
1217     {
1218       other_info = l->data;
1219
1220       if (info->serial_start < other_info->serial_start)
1221         break;
1222     }
1223
1224   grabs = g_list_insert_before (grabs, l, info);
1225
1226   /* Make sure the new grab end before next grab */
1227   if (l)
1228     {
1229       other_info = l->data;
1230       info->serial_end = other_info->serial_start;
1231     }
1232
1233   /* Find any previous grab and update its end time */
1234   l = g_list_find (grabs, info);
1235   l = l->prev;
1236   if (l)
1237     {
1238       other_info = l->data;
1239       other_info->serial_end = serial_start;
1240     }
1241
1242   g_hash_table_insert (display->device_grabs, device, grabs);
1243
1244   return info;
1245 }
1246
1247 /* _gdk_synthesize_crossing_events only works inside one toplevel.
1248    This function splits things into two calls if needed, converting the
1249    coordinates to the right toplevel */
1250 static void
1251 synthesize_crossing_events (GdkDisplay      *display,
1252                             GdkDevice       *device,
1253                             GdkWindow       *src_window,
1254                             GdkWindow       *dest_window,
1255                             GdkCrossingMode  crossing_mode,
1256                             guint32          time,
1257                             gulong           serial)
1258 {
1259   GdkWindow *src_toplevel, *dest_toplevel;
1260   GdkModifierType state;
1261   int x, y;
1262
1263   /* We use the native crossing events if all native */
1264   if (_gdk_native_windows)
1265     return;
1266   
1267   if (src_window)
1268     src_toplevel = gdk_window_get_toplevel (src_window);
1269   else
1270     src_toplevel = NULL;
1271   if (dest_window)
1272     dest_toplevel = gdk_window_get_toplevel (dest_window);
1273   else
1274     dest_toplevel = NULL;
1275
1276   if (src_toplevel == NULL && dest_toplevel == NULL)
1277     return;
1278   
1279   if (src_toplevel == NULL ||
1280       src_toplevel == dest_toplevel)
1281     {
1282       /* Same toplevels */
1283       gdk_window_get_pointer (dest_toplevel,
1284                               &x, &y, &state);
1285       _gdk_synthesize_crossing_events (display,
1286                                        src_window,
1287                                        dest_window,
1288                                        device,
1289                                        crossing_mode,
1290                                        x, y, state,
1291                                        time,
1292                                        NULL,
1293                                        serial, FALSE);
1294     }
1295   else if (dest_toplevel == NULL)
1296     {
1297       gdk_window_get_pointer (src_toplevel,
1298                               &x, &y, &state);
1299       _gdk_synthesize_crossing_events (display,
1300                                        src_window,
1301                                        NULL,
1302                                        device,
1303                                        crossing_mode,
1304                                        x, y, state,
1305                                        time,
1306                                        NULL,
1307                                        serial, FALSE);
1308     }
1309   else
1310     {
1311       /* Different toplevels */
1312       gdk_window_get_pointer (src_toplevel,
1313                               &x, &y, &state);
1314       _gdk_synthesize_crossing_events (display,
1315                                        src_window,
1316                                        NULL,
1317                                        device,
1318                                        crossing_mode,
1319                                        x, y, state,
1320                                        time,
1321                                        NULL,
1322                                        serial, FALSE);
1323       gdk_window_get_pointer (dest_toplevel,
1324                               &x, &y, &state);
1325       _gdk_synthesize_crossing_events (display,
1326                                        NULL,
1327                                        dest_window,
1328                                        device,
1329                                        crossing_mode,
1330                                        x, y, state,
1331                                        time,
1332                                        NULL,
1333                                        serial, FALSE);
1334     }
1335 }
1336
1337 static GdkWindow *
1338 get_current_toplevel (GdkDisplay      *display,
1339                       GdkDevice       *device,
1340                       int             *x_out,
1341                       int             *y_out,
1342                       GdkModifierType *state_out)
1343 {
1344   GdkWindow *pointer_window;
1345   int x, y;
1346   GdkModifierType state;
1347
1348   pointer_window = _gdk_windowing_window_at_device_position (display, device, &x, &y, &state, TRUE);
1349
1350   if (pointer_window != NULL &&
1351       (GDK_WINDOW_DESTROYED (pointer_window) ||
1352        GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
1353        GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
1354     pointer_window = NULL;
1355
1356   *x_out = x;
1357   *y_out = y;
1358   *state_out = state;
1359   return pointer_window;
1360 }
1361
1362 static void
1363 switch_to_pointer_grab (GdkDisplay        *display,
1364                         GdkDevice         *device,
1365                         GdkDeviceGrabInfo *grab,
1366                         GdkDeviceGrabInfo *last_grab,
1367                         guint32            time,
1368                         gulong             serial)
1369 {
1370   GdkWindow *src_window, *pointer_window, *new_toplevel;
1371   GdkPointerWindowInfo *info;
1372   GList *old_grabs;
1373   GdkModifierType state;
1374   int x, y;
1375
1376   /* Temporarily unset pointer to make sure we send the crossing events below */
1377   old_grabs = g_hash_table_lookup (display->device_grabs, device);
1378   g_hash_table_steal (display->device_grabs, device);
1379   info = _gdk_display_get_pointer_info (display, device);
1380
1381   if (grab)
1382     {
1383       /* New grab is in effect */
1384
1385       /* We need to generate crossing events for the grab.
1386        * However, there are never any crossing events for implicit grabs
1387        * TODO: ... Actually, this could happen if the pointer window
1388        *           doesn't have button mask so a parent gets the event...
1389        */
1390       if (!grab->implicit)
1391         {
1392           /* We send GRAB crossing events from the window under the pointer to the
1393              grab window. Except if there is an old grab then we start from that */
1394           if (last_grab)
1395             src_window = last_grab->window;
1396           else
1397             src_window = info->window_under_pointer;
1398
1399           if (src_window != grab->window)
1400             synthesize_crossing_events (display, device,
1401                                         src_window, grab->window,
1402                                         GDK_CROSSING_GRAB, time, serial);
1403
1404           /* !owner_event Grabbing a window that we're not inside, current status is
1405              now NULL (i.e. outside grabbed window) */
1406           if (!grab->owner_events && info->window_under_pointer != grab->window)
1407             _gdk_display_set_window_under_pointer (display, device, NULL);
1408         }
1409
1410       grab->activated = TRUE;
1411     }
1412
1413   if (last_grab)
1414     {
1415       new_toplevel = NULL;
1416
1417       if (grab == NULL /* ungrab */ ||
1418           (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
1419         {
1420           /* We force check what window we're in, and update the toplevel_under_pointer info,
1421            * as that won't get told of this change with toplevel enter events.
1422            */
1423           if (info->toplevel_under_pointer)
1424             g_object_unref (info->toplevel_under_pointer);
1425           info->toplevel_under_pointer = NULL;
1426
1427           new_toplevel = get_current_toplevel (display, device, &x, &y, &state);
1428           if (new_toplevel)
1429             {
1430               /* w is now toplevel and x,y in toplevel coords */
1431               info->toplevel_under_pointer = g_object_ref (new_toplevel);
1432               info->toplevel_x = x;
1433               info->toplevel_y = y;
1434               info->state = state;
1435             }
1436         }
1437
1438       if (grab == NULL) /* Ungrabbed, send events */
1439         {
1440           pointer_window = NULL;
1441           if (new_toplevel)
1442             {
1443               /* Find (possibly virtual) child window */
1444               pointer_window =
1445                 _gdk_window_find_descendant_at (new_toplevel,
1446                                                 x, y,
1447                                                 NULL, NULL);
1448             }
1449
1450           if (pointer_window != last_grab->window)
1451             synthesize_crossing_events (display, device,
1452                                         last_grab->window, pointer_window,
1453                                         GDK_CROSSING_UNGRAB, time, serial);
1454
1455           /* We're now ungrabbed, update the window_under_pointer */
1456           _gdk_display_set_window_under_pointer (display, device, pointer_window);
1457         }
1458     }
1459
1460   g_hash_table_insert (display->device_grabs, device, old_grabs);
1461 }
1462
1463 void
1464 _gdk_display_device_grab_update (GdkDisplay *display,
1465                                  GdkDevice  *device,
1466                                  gulong      current_serial)
1467 {
1468   GdkDeviceGrabInfo *current_grab, *next_grab;
1469   GList *grabs;
1470   guint32 time;
1471
1472   time = display->last_event_time;
1473   grabs = g_hash_table_lookup (display->device_grabs, device);
1474
1475   while (grabs != NULL)
1476     {
1477       current_grab = grabs->data;
1478
1479       if (current_grab->serial_start > current_serial)
1480         return; /* Hasn't started yet */
1481
1482       if (current_grab->serial_end > current_serial)
1483         {
1484           /* This one hasn't ended yet.
1485              its the currently active one or scheduled to be active */
1486
1487           if (!current_grab->activated)
1488             {
1489               if (device->source != GDK_SOURCE_KEYBOARD)
1490                 switch_to_pointer_grab (display, device, current_grab, NULL, time, current_serial);
1491             }
1492
1493           break;
1494         }
1495
1496       next_grab = NULL;
1497       if (grabs->next)
1498         {
1499           /* This is the next active grab */
1500           next_grab = grabs->next->data;
1501
1502           if (next_grab->serial_start > current_serial)
1503             next_grab = NULL; /* Actually its not yet active */
1504         }
1505
1506       if ((next_grab == NULL && current_grab->implicit_ungrab) ||
1507           (next_grab != NULL && current_grab->window != next_grab->window))
1508         generate_grab_broken_event (GDK_WINDOW (current_grab->window),
1509                                     device,
1510                                     current_grab->implicit,
1511                                     next_grab? next_grab->window : NULL);
1512
1513       /* Remove old grab */
1514       grabs = g_list_delete_link (grabs, grabs);
1515       g_hash_table_insert (display->device_grabs, device, grabs);
1516
1517       if (device->source != GDK_SOURCE_KEYBOARD)
1518         switch_to_pointer_grab (display, device,
1519                                 next_grab, current_grab,
1520                                 time, current_serial);
1521
1522       free_device_grab (current_grab);
1523     }
1524 }
1525
1526 static GList *
1527 grab_list_find (GList  *grabs,
1528                 gulong  serial)
1529 {
1530   GdkDeviceGrabInfo *grab;
1531
1532   while (grabs)
1533     {
1534       grab = grabs->data;
1535
1536       if (serial >= grab->serial_start && serial < grab->serial_end)
1537         return grabs;
1538
1539       grabs = grabs->next;
1540     }
1541
1542   return NULL;
1543 }
1544
1545 static GList *
1546 find_device_grab (GdkDisplay *display,
1547                    GdkDevice  *device,
1548                    gulong      serial)
1549 {
1550   GList *l;
1551
1552   l = g_hash_table_lookup (display->device_grabs, device);
1553   return grab_list_find (l, serial);
1554 }
1555
1556 GdkDeviceGrabInfo *
1557 _gdk_display_has_device_grab (GdkDisplay *display,
1558                               GdkDevice  *device,
1559                               gulong      serial)
1560 {
1561   GList *l;
1562
1563   l = find_device_grab (display, device, serial);
1564   if (l)
1565     return l->data;
1566
1567   return NULL;
1568 }
1569
1570 /* Returns true if last grab was ended
1571  * If if_child is non-NULL, end the grab only if the grabbed
1572  * window is the same as if_child or a descendant of it */
1573 gboolean
1574 _gdk_display_end_device_grab (GdkDisplay *display,
1575                               GdkDevice  *device,
1576                               gulong      serial,
1577                               GdkWindow  *if_child,
1578                               gboolean    implicit)
1579 {
1580   GdkDeviceGrabInfo *grab;
1581   GList *l;
1582
1583   l = find_device_grab (display, device, serial);
1584
1585   if (l == NULL)
1586     return FALSE;
1587
1588   grab = l->data;
1589   if (grab &&
1590       (if_child == NULL ||
1591        _gdk_window_event_parent_of (if_child, grab->window)))
1592     {
1593       grab->serial_end = serial;
1594       grab->implicit_ungrab = implicit;
1595       return l->next == NULL;
1596     }
1597   
1598   return FALSE;
1599 }
1600
1601 /* Returns TRUE if device events are not blocked by any grab */
1602 gboolean
1603 _gdk_display_check_grab_ownership (GdkDisplay *display,
1604                                    GdkDevice  *device,
1605                                    gulong      serial)
1606 {
1607   GHashTableIter iter;
1608   gpointer key, value;
1609   GdkGrabOwnership higher_ownership, device_ownership;
1610   gboolean device_is_keyboard;
1611
1612   g_hash_table_iter_init (&iter, display->device_grabs);
1613   higher_ownership = device_ownership = GDK_OWNERSHIP_NONE;
1614   device_is_keyboard = (device->source == GDK_SOURCE_KEYBOARD);
1615
1616   while (g_hash_table_iter_next (&iter, &key, &value))
1617     {
1618       GdkDeviceGrabInfo *grab;
1619       GdkDevice *dev;
1620       GList *grabs;
1621
1622       dev = key;
1623       grabs = value;
1624       grabs = grab_list_find (grabs, serial);
1625
1626       if (!grabs)
1627         continue;
1628
1629       /* Discard device if it's not of the same type */
1630       if ((device_is_keyboard && dev->source != GDK_SOURCE_KEYBOARD) ||
1631           (!device_is_keyboard && dev->source == GDK_SOURCE_KEYBOARD))
1632         continue;
1633
1634       grab = grabs->data;
1635
1636       if (dev == device)
1637         device_ownership = grab->ownership;
1638       else
1639         {
1640           if (grab->ownership > higher_ownership)
1641             higher_ownership = grab->ownership;
1642         }
1643     }
1644
1645   if (higher_ownership > device_ownership)
1646     {
1647       /* There's a higher priority ownership
1648        * going on for other device(s)
1649        */
1650       return FALSE;
1651     }
1652
1653   return TRUE;
1654 }
1655
1656 GdkPointerWindowInfo *
1657 _gdk_display_get_pointer_info (GdkDisplay *display,
1658                                GdkDevice  *device)
1659 {
1660   GdkPointerWindowInfo *info;
1661
1662   if (G_UNLIKELY (!device))
1663     return NULL;
1664
1665   info = g_hash_table_lookup (display->pointers_info, device);
1666
1667   if (G_UNLIKELY (!info))
1668     {
1669       info = g_slice_new0 (GdkPointerWindowInfo);
1670       g_hash_table_insert (display->pointers_info, device, info);
1671     }
1672
1673   return info;
1674 }
1675
1676 void
1677 _gdk_display_pointer_info_foreach (GdkDisplay                   *display,
1678                                    GdkDisplayPointerInfoForeach  func,
1679                                    gpointer                      user_data)
1680 {
1681   GHashTableIter iter;
1682   gpointer key, value;
1683
1684   g_hash_table_iter_init (&iter, display->pointers_info);
1685
1686   while (g_hash_table_iter_next (&iter, &key, &value))
1687     {
1688       GdkPointerWindowInfo *info = value;
1689       GdkDevice *device = key;
1690
1691       (func) (display, device, info, user_data);
1692     }
1693 }
1694
1695 /**
1696  * gdk_device_grab_info_libgtk_only:
1697  * @display: the display for which to get the grab information
1698  * @device: device to get the grab information from
1699  * @grab_window: location to store current grab window
1700  * @owner_events: location to store boolean indicating whether
1701  *   the @owner_events flag to gdk_keyboard_grab() or
1702  *   gdk_pointer_grab() was %TRUE.
1703  *
1704  * Determines information about the current keyboard grab.
1705  * This is not public API and must not be used by applications.
1706  *
1707  * Return value: %TRUE if this application currently has the
1708  *  keyboard grabbed.
1709  **/
1710 gboolean
1711 gdk_device_grab_info_libgtk_only (GdkDisplay  *display,
1712                                   GdkDevice   *device,
1713                                   GdkWindow  **grab_window,
1714                                   gboolean    *owner_events)
1715 {
1716   GdkDeviceGrabInfo *info;
1717
1718   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
1719   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
1720
1721   info = _gdk_display_get_last_device_grab (display, device);
1722
1723   if (info)
1724     {
1725       if (grab_window)
1726         *grab_window = info->window;
1727       if (owner_events)
1728         *owner_events = info->owner_events;
1729
1730       return TRUE;
1731     }
1732   else
1733     return FALSE;
1734 }
1735
1736 /**
1737  * gdk_display_pointer_is_grabbed:
1738  * @display: a #GdkDisplay
1739  *
1740  * Test if the pointer is grabbed.
1741  *
1742  * Returns: %TRUE if an active X pointer grab is in effect
1743  *
1744  * Since: 2.2
1745  *
1746  * Deprecated: 3.0: Use gdk_display_device_is_grabbed() instead.
1747  */
1748 gboolean
1749 gdk_display_pointer_is_grabbed (GdkDisplay *display)
1750 {
1751   GdkDeviceManager *device_manager;
1752   GList *devices, *dev;
1753   GdkDevice *device;
1754
1755   g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
1756
1757   device_manager = gdk_display_get_device_manager (display);
1758   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
1759
1760   for (dev = devices; dev; dev = dev->next)
1761     {
1762       device = dev->data;
1763
1764       if (device->source == GDK_SOURCE_MOUSE &&
1765           gdk_display_device_is_grabbed (display, device))
1766         return TRUE;
1767     }
1768
1769   return FALSE;
1770 }
1771
1772 /**
1773  * gdk_display_device_is_grabbed:
1774  * @display: a #GdkDisplay
1775  * @device: a #GdkDevice
1776  *
1777  * Returns %TRUE if there is an ongoing grab on @device for @display.
1778  *
1779  * Returns: %TRUE if there is a grab in effect for @device.
1780  **/
1781 gboolean
1782 gdk_display_device_is_grabbed (GdkDisplay *display,
1783                                GdkDevice  *device)
1784 {
1785   GdkDeviceGrabInfo *info;
1786
1787   g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
1788   g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
1789
1790   /* What we're interested in is the steady state (ie last grab),
1791      because we're interested e.g. if we grabbed so that we
1792      can ungrab, even if our grab is not active just yet. */
1793   info = _gdk_display_get_last_device_grab (display, device);
1794
1795   return (info && !info->implicit);
1796 }
1797
1798 /**
1799  * gdk_display_get_device_manager:
1800  * @display: a #GdkDisplay.
1801  *
1802  * Returns the #GdkDeviceManager associated to @display.
1803  *
1804  * Returns: A #GdkDeviceManager, or %NULL. This memory is
1805  *          owned by GDK and must not be freed or unreferenced.
1806  *
1807  * Since: 3.0
1808  **/
1809 GdkDeviceManager *
1810 gdk_display_get_device_manager (GdkDisplay *display)
1811 {
1812   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1813
1814   return display->device_manager;
1815 }