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