]> Pileus Git - ~andy/gtk/blob - gdk/gdkdisplay.c
Strengthen checks in functions taking a GdkDevice
[~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 (gdk_device_get_source (device) != 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 (gdk_device_get_source (device) != 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_set_sm_client_id:
654  * @sm_client_id: the client id assigned by the session manager when the
655  *    connection was opened, or %NULL to remove the property.
656  * 
657  * Sets the <literal>SM_CLIENT_ID</literal> property on the application's leader window so that
658  * the window manager can save the application's state using the X11R6 ICCCM
659  * session management protocol.
660  *
661  * See the X Session Management Library documentation for more information on
662  * session management and the Inter-Client Communication Conventions Manual
663  * (ICCCM) for information on the <literal>WM_CLIENT_LEADER</literal> property. 
664  * (Both documents are part of the X Window System distribution.)
665  **/
666 void
667 gdk_set_sm_client_id (const gchar* sm_client_id)
668 {
669   GSList *displays, *tmp_list;
670   
671   g_free (gdk_sm_client_id);
672   gdk_sm_client_id = g_strdup (sm_client_id);
673
674   displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
675   for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
676     _gdk_windowing_display_set_sm_client_id (tmp_list->data, sm_client_id);
677
678   g_slist_free (displays);
679 }
680
681 /**
682  * _gdk_get_sm_client_id:
683  * 
684  * Gets the client ID set with gdk_set_sm_client_id(), if any.
685  * 
686  * Return value: Session ID, or %NULL if gdk_set_sm_client_id()
687  *               has never been called.
688  **/
689 const char *
690 _gdk_get_sm_client_id (void)
691 {
692   return gdk_sm_client_id;
693 }
694
695 void
696 _gdk_display_enable_motion_hints (GdkDisplay *display,
697                                   GdkDevice  *device)
698 {
699   gulong *device_serial, serial;
700
701   device_serial = g_hash_table_lookup (display->motion_hint_info, device);
702
703   if (!device_serial)
704     {
705       device_serial = g_new0 (gulong, 1);
706       *device_serial = G_MAXULONG;
707       g_hash_table_insert (display->motion_hint_info, device, device_serial);
708     }
709
710   if (*device_serial != 0)
711     {
712       serial = _gdk_windowing_window_get_next_serial (display);
713       /* We might not actually generate the next request, so
714          make sure this triggers always, this may cause it to
715          trigger slightly too early, but this is just a hint
716          anyway. */
717       if (serial > 0)
718         serial--;
719       if (serial < *device_serial)
720         *device_serial = serial;
721     }
722 }
723
724 /**
725  * gdk_display_get_device_state:
726  * @display: a #GdkDisplay.
727  * @device: pointer device to query status about.
728  * @screen: (out) (transfer none) (allow-none): location to store the #GdkScreen
729  *          the @device is on, or %NULL.
730  * @x: (out) (allow-none): location to store root window X coordinate of @device, or %NULL.
731  * @y: (out) (allow-none): location to store root window Y coordinate of @device, or %NULL.
732  * @mask: (out) (allow-none): location to store current modifier mask for @device, or %NULL.
733  *
734  * Gets the current location and state of @device for a given display.
735  *
736  * Since: 3.0
737  **/
738 void
739 gdk_display_get_device_state (GdkDisplay       *display,
740                               GdkDevice        *device,
741                               GdkScreen       **screen,
742                               gint             *x,
743                               gint             *y,
744                               GdkModifierType  *mask)
745 {
746   GdkScreen *tmp_screen;
747   gint tmp_x, tmp_y;
748   GdkModifierType tmp_mask;
749
750   g_return_if_fail (GDK_IS_DISPLAY (display));
751   g_return_if_fail (GDK_IS_DEVICE (device));
752   g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
753
754   display->device_hooks->get_device_state (display, device, &tmp_screen, &tmp_x, &tmp_y, &tmp_mask);
755
756   if (screen)
757     *screen = tmp_screen;
758   if (x)
759     *x = tmp_x;
760   if (y)
761     *y = tmp_y;
762   if (mask)
763     *mask = tmp_mask;
764 }
765
766 /**
767  * gdk_display_get_window_at_device_position:
768  * @display: a #GdkDisplay.
769  * @device: pointer #GdkDevice to query info to.
770  * @win_x: (out) (allow-none): return location for the X coordinate of the device location,
771  *         relative to the window origin, or %NULL.
772  * @win_y: (out) (allow-none): return location for the Y coordinate of the device location,
773  *         relative to the window origin, or %NULL.
774  *
775  * Obtains the window underneath @device, returning the location of the device in @win_x and @win_y. Returns
776  * %NULL if the window tree under @device is not known to GDK (for example, belongs to another application).
777  *
778  * Returns: (transfer none): the #GdkWindow under the device position, or %NULL.
779  *
780  * Since: 3.0
781  **/
782 GdkWindow *
783 gdk_display_get_window_at_device_position (GdkDisplay *display,
784                                            GdkDevice  *device,
785                                            gint       *win_x,
786                                            gint       *win_y)
787 {
788   gint tmp_x, tmp_y;
789   GdkWindow *window;
790
791   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
792   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
793   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
794
795   window = display->device_hooks->window_at_device_position (display, device, &tmp_x, &tmp_y);
796
797   if (win_x)
798     *win_x = tmp_x;
799   if (win_y)
800     *win_y = tmp_y;
801
802   return window;
803 }
804
805 /**
806  * gdk_display_set_device_hooks:
807  * @display: a #GdkDisplay.
808  * @new_hooks: (allow-none): a table of pointers to functions for getting quantities related
809  *             to all devices position, or %NULL to restore the default table.
810  *
811  * This function allows for hooking into the operation of getting the current location of any
812  * #GdkDevice on a particular #GdkDisplay. This is only useful for such low-level tools as
813  * an event recorder. Applications should never have any reason to use this facility.
814  *
815  * Returns: (transfer none): The previous device hook table.
816  *
817  * Since: 3.0
818  **/
819 GdkDisplayDeviceHooks *
820 gdk_display_set_device_hooks (GdkDisplay                  *display,
821                               const GdkDisplayDeviceHooks *new_hooks)
822 {
823   const GdkDisplayDeviceHooks *result;
824
825   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
826   result = display->device_hooks;
827
828   if (new_hooks)
829     display->device_hooks = new_hooks;
830   else
831     display->device_hooks = &default_device_hooks;
832
833   return (GdkDisplayDeviceHooks *) result;
834 }
835
836 /**
837  * gdk_display_get_pointer:
838  * @display: a #GdkDisplay
839  * @screen: (allow-none): location to store the screen that the
840  *          cursor is on, or %NULL.
841  * @x: (out) (allow-none): location to store root window X coordinate of pointer, or %NULL.
842  * @y: (out) (allow-none): location to store root window Y coordinate of pointer, or %NULL.
843  * @mask: (out) (allow-none): location to store current modifier mask, or %NULL
844  *
845  * Gets the current location of the pointer and the current modifier
846  * mask for a given display.
847  *
848  * Since: 2.2
849  *
850  * Deprecated: 3.0: Use gdk_display_get_device_state() instead.
851  **/
852 void
853 gdk_display_get_pointer (GdkDisplay      *display,
854                          GdkScreen      **screen,
855                          gint            *x,
856                          gint            *y,
857                          GdkModifierType *mask)
858 {
859   g_return_if_fail (GDK_IS_DISPLAY (display));
860
861   gdk_display_get_device_state (display, display->core_pointer, screen, x, y, mask);
862 }
863
864 static GdkWindow *
865 gdk_display_real_get_window_at_device_position (GdkDisplay *display,
866                                                 GdkDevice  *device,
867                                                 gint       *win_x,
868                                                 gint       *win_y)
869 {
870   GdkWindow *window;
871   gint x, y;
872
873   window = _gdk_windowing_window_at_device_position (display, device, &x, &y, NULL, FALSE);
874
875   /* This might need corrections, as the native window returned
876      may contain client side children */
877   if (window)
878     {
879       double xx, yy;
880
881       window = _gdk_window_find_descendant_at (window,
882                                                x, y,
883                                                &xx, &yy);
884       x = floor (xx + 0.5);
885       y = floor (yy + 0.5);
886     }
887
888   *win_x = x;
889   *win_y = y;
890
891   return window;
892 }
893
894 static GdkWindow *
895 gdk_window_real_window_get_device_position (GdkDisplay       *display,
896                                             GdkDevice        *device,
897                                             GdkWindow        *window,
898                                             gint             *x,
899                                             gint             *y,
900                                             GdkModifierType  *mask)
901 {
902   gint tmpx, tmpy;
903   GdkModifierType tmp_mask;
904   gboolean normal_child;
905
906   normal_child = GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_device_state (window,
907                                                                               device,
908                                                                               &tmpx, &tmpy,
909                                                                               &tmp_mask);
910   /* We got the coords on the impl, convert to the window */
911   tmpx -= window->abs_x;
912   tmpy -= window->abs_y;
913
914   if (x)
915     *x = tmpx;
916   if (y)
917     *y = tmpy;
918   if (mask)
919     *mask = tmp_mask;
920
921   if (normal_child)
922     return _gdk_window_find_child_at (window, tmpx, tmpy);
923   return NULL;
924 }
925
926 /**
927  * gdk_display_get_window_at_pointer:
928  * @display: a #GdkDisplay
929  * @win_x: (out) (allow-none): return location for x coordinate of the pointer location relative
930  *    to the window origin, or %NULL
931  * @win_y: (out) (allow-none): return location for y coordinate of the pointer location relative
932  &    to the window origin, or %NULL
933  *
934  * Obtains the window underneath the mouse pointer, returning the location
935  * of the pointer in that window in @win_x, @win_y for @screen. Returns %NULL
936  * if the window under the mouse pointer is not known to GDK (for example, 
937  * belongs to another application).
938  *
939  * Returns: (transfer none): the window under the mouse pointer, or %NULL
940  *
941  * Since: 2.2
942  *
943  * Deprecated: 3.0: Use gdk_display_get_window_at_device_position() instead.
944  **/
945 GdkWindow *
946 gdk_display_get_window_at_pointer (GdkDisplay *display,
947                                    gint       *win_x,
948                                    gint       *win_y)
949 {
950   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
951
952   return gdk_display_get_window_at_device_position (display, display->core_pointer, win_x, win_y);
953 }
954
955 static void
956 multihead_get_device_state (GdkDisplay       *display,
957                             GdkDevice        *device,
958                             GdkScreen       **screen,
959                             gint             *x,
960                             gint             *y,
961                             GdkModifierType  *mask)
962 {
963   multihead_current_pointer_hooks->get_pointer (display, screen, x, y, mask);
964 }
965
966 static GdkWindow *
967 multihead_window_get_device_position (GdkDisplay      *display,
968                                       GdkDevice       *device,
969                                       GdkWindow       *window,
970                                       gint            *x,
971                                       gint            *y,
972                                       GdkModifierType *mask)
973 {
974   return multihead_current_pointer_hooks->window_get_pointer (display, window, x, y, mask);
975 }
976
977 static GdkWindow *
978 multihead_window_at_device_position (GdkDisplay *display,
979                                      GdkDevice  *device,
980                                      gint       *win_x,
981                                      gint       *win_y)
982 {
983   return multihead_current_pointer_hooks->window_at_pointer (display, win_x, win_y);
984 }
985
986 static void
987 multihead_default_get_pointer (GdkDisplay       *display,
988                                GdkScreen       **screen,
989                                gint             *x,
990                                gint             *y,
991                                GdkModifierType  *mask)
992 {
993   return _gdk_windowing_get_device_state (display,
994                                           display->core_pointer,
995                                           screen, x, y, mask);
996 }
997
998 static GdkWindow *
999 multihead_default_window_get_pointer (GdkDisplay      *display,
1000                                       GdkWindow       *window,
1001                                       gint            *x,
1002                                       gint            *y,
1003                                       GdkModifierType *mask)
1004 {
1005   return gdk_window_real_window_get_device_position (display,
1006                                                      display->core_pointer,
1007                                                      window, x, y, mask);
1008 }
1009
1010 static GdkWindow *
1011 multihead_default_window_at_pointer (GdkDisplay *display,
1012                                      gint       *win_x,
1013                                      gint       *win_y)
1014 {
1015   return gdk_display_real_get_window_at_device_position (display,
1016                                                          display->core_pointer,
1017                                                          win_x, win_y);
1018 }
1019
1020 /**
1021  * gdk_display_set_pointer_hooks:
1022  * @display: a #GdkDisplay
1023  * @new_hooks: (allow-none): a table of pointers to functions for getting
1024  *   quantities related to the current pointer position,
1025  *   or %NULL to restore the default table.
1026  * 
1027  * This function allows for hooking into the operation
1028  * of getting the current location of the pointer on a particular
1029  * display. This is only useful for such low-level tools as an
1030  * event recorder. Applications should never have any
1031  * reason to use this facility.
1032  *
1033  * Return value: (transfer none): the previous pointer hook table
1034  *
1035  * Since: 2.2
1036  *
1037  * Deprecated: 3.0: Use gdk_display_set_device_hooks() instead.
1038  **/
1039 GdkDisplayPointerHooks *
1040 gdk_display_set_pointer_hooks (GdkDisplay                   *display,
1041                                const GdkDisplayPointerHooks *new_hooks)
1042 {
1043   const GdkDisplayPointerHooks *result = multihead_current_pointer_hooks;
1044
1045   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1046
1047   if (new_hooks)
1048     multihead_current_pointer_hooks = new_hooks;
1049   else
1050     multihead_current_pointer_hooks = &multihead_default_pointer_hooks;
1051
1052   gdk_display_set_device_hooks (display, &multihead_pointer_hooks);
1053
1054   return (GdkDisplayPointerHooks *)result;
1055 }
1056
1057 static void
1058 singlehead_get_pointer (GdkDisplay       *display,
1059                         GdkScreen       **screen,
1060                         gint             *x,
1061                         gint             *y,
1062                         GdkModifierType  *mask)
1063 {
1064   GdkScreen *default_screen = gdk_display_get_default_screen (display);
1065   GdkWindow *root_window = gdk_screen_get_root_window (default_screen);
1066
1067   *screen = default_screen;
1068
1069   singlehead_current_pointer_hooks->get_pointer (root_window, x, y, mask);
1070 }
1071
1072 static GdkWindow*
1073 singlehead_window_get_pointer (GdkDisplay       *display,
1074                                GdkWindow        *window,
1075                                gint             *x,
1076                                gint             *y,
1077                                GdkModifierType  *mask)
1078 {
1079   return singlehead_current_pointer_hooks->get_pointer (window, x, y, mask);
1080 }
1081
1082 static GdkWindow*
1083 singlehead_window_at_pointer   (GdkDisplay *display,
1084                                 gint       *win_x,
1085                                 gint       *win_y)
1086 {
1087   GdkScreen *default_screen = gdk_display_get_default_screen (display);
1088
1089   return singlehead_current_pointer_hooks->window_at_pointer (default_screen,
1090                                                               win_x, win_y);
1091 }
1092
1093 static GdkWindow*
1094 singlehead_default_window_get_pointer (GdkWindow       *window,
1095                                        gint            *x,
1096                                        gint            *y,
1097                                        GdkModifierType *mask)
1098 {
1099   GdkDisplay *display;
1100
1101   display = gdk_window_get_display (window);
1102
1103   return gdk_window_real_window_get_device_position (display,
1104                                                      display->core_pointer,
1105                                                      window, x, y, mask);
1106 }
1107
1108 static GdkWindow*
1109 singlehead_default_window_at_pointer  (GdkScreen       *screen,
1110                                        gint            *win_x,
1111                                        gint            *win_y)
1112 {
1113   GdkDisplay *display;
1114
1115   display = gdk_screen_get_display (screen);
1116
1117   return gdk_display_real_get_window_at_device_position (display,
1118                                                          display->core_pointer,
1119                                                          win_x, win_y);
1120 }
1121
1122 /**
1123  * gdk_set_pointer_hooks:
1124  * @new_hooks: (allow-none): a table of pointers to functions for getting
1125  *   quantities related to the current pointer position,
1126  *   or %NULL to restore the default table.
1127  * 
1128  * This function allows for hooking into the operation
1129  * of getting the current location of the pointer. This
1130  * is only useful for such low-level tools as an
1131  * event recorder. Applications should never have any
1132  * reason to use this facility.
1133  *
1134  * This function is not multihead safe. For multihead operation,
1135  * see gdk_display_set_pointer_hooks().
1136  * 
1137  * Return value: the previous pointer hook table
1138  *
1139  * Deprecated: 3.0: Use gdk_display_set_device_hooks() instead.
1140  **/
1141 GdkPointerHooks *
1142 gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
1143 {
1144   const GdkPointerHooks *result = singlehead_current_pointer_hooks;
1145
1146   if (new_hooks)
1147     singlehead_current_pointer_hooks = new_hooks;
1148   else
1149     singlehead_current_pointer_hooks = &singlehead_default_pointer_hooks;
1150
1151   gdk_display_set_pointer_hooks (gdk_display_get_default (),
1152                                  &singlehead_pointer_hooks);
1153   
1154   return (GdkPointerHooks *)result;
1155 }
1156
1157 static void
1158 generate_grab_broken_event (GdkWindow *window,
1159                             GdkDevice *device,
1160                             gboolean   implicit,
1161                             GdkWindow *grab_window)
1162 {
1163   g_return_if_fail (window != NULL);
1164
1165   if (!GDK_WINDOW_DESTROYED (window))
1166     {
1167       GdkEvent *event;
1168
1169       event = gdk_event_new (GDK_GRAB_BROKEN);
1170       event->grab_broken.window = g_object_ref (window);
1171       event->grab_broken.send_event = FALSE;
1172       event->grab_broken.implicit = implicit;
1173       event->grab_broken.grab_window = grab_window;
1174       gdk_event_set_device (event, device);
1175       event->grab_broken.keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) ? TRUE : FALSE;
1176
1177       gdk_event_put (event);
1178       gdk_event_free (event);
1179     }
1180 }
1181
1182 GdkDeviceGrabInfo *
1183 _gdk_display_get_last_device_grab (GdkDisplay *display,
1184                                    GdkDevice  *device)
1185 {
1186   GList *l;
1187
1188   l = g_hash_table_lookup (display->device_grabs, device);
1189
1190   if (l)
1191     {
1192       l = g_list_last (l);
1193       return l->data;
1194     }
1195
1196   return NULL;
1197 }
1198
1199 GdkDeviceGrabInfo *
1200 _gdk_display_add_device_grab (GdkDisplay       *display,
1201                               GdkDevice        *device,
1202                               GdkWindow        *window,
1203                               GdkWindow        *native_window,
1204                               GdkGrabOwnership  grab_ownership,
1205                               gboolean          owner_events,
1206                               GdkEventMask      event_mask,
1207                               unsigned long     serial_start,
1208                               guint32           time,
1209                               gboolean          implicit)
1210 {
1211   GdkDeviceGrabInfo *info, *other_info;
1212   GList *grabs, *l;
1213
1214   info = g_new0 (GdkDeviceGrabInfo, 1);
1215
1216   info->window = g_object_ref (window);
1217   info->native_window = g_object_ref (native_window);
1218   info->serial_start = serial_start;
1219   info->serial_end = G_MAXULONG;
1220   info->owner_events = owner_events;
1221   info->event_mask = event_mask;
1222   info->time = time;
1223   info->implicit = implicit;
1224   info->ownership = grab_ownership;
1225
1226   grabs = g_hash_table_lookup (display->device_grabs, device);
1227
1228   /* Find the first grab that has a larger start time (if any) and insert
1229    * before that. I.E we insert after already existing grabs with same
1230    * start time */
1231   for (l = grabs; l != NULL; l = l->next)
1232     {
1233       other_info = l->data;
1234
1235       if (info->serial_start < other_info->serial_start)
1236         break;
1237     }
1238
1239   grabs = g_list_insert_before (grabs, l, info);
1240
1241   /* Make sure the new grab end before next grab */
1242   if (l)
1243     {
1244       other_info = l->data;
1245       info->serial_end = other_info->serial_start;
1246     }
1247
1248   /* Find any previous grab and update its end time */
1249   l = g_list_find (grabs, info);
1250   l = l->prev;
1251   if (l)
1252     {
1253       other_info = l->data;
1254       other_info->serial_end = serial_start;
1255     }
1256
1257   g_hash_table_insert (display->device_grabs, device, grabs);
1258
1259   return info;
1260 }
1261
1262 /* _gdk_synthesize_crossing_events only works inside one toplevel.
1263    This function splits things into two calls if needed, converting the
1264    coordinates to the right toplevel */
1265 static void
1266 synthesize_crossing_events (GdkDisplay      *display,
1267                             GdkDevice       *device,
1268                             GdkDevice       *source_device,
1269                             GdkWindow       *src_window,
1270                             GdkWindow       *dest_window,
1271                             GdkCrossingMode  crossing_mode,
1272                             guint32          time,
1273                             gulong           serial)
1274 {
1275   GdkWindow *src_toplevel, *dest_toplevel;
1276   GdkModifierType state;
1277   int x, y;
1278
1279   /* We use the native crossing events if all native */
1280   if (_gdk_native_windows)
1281     return;
1282   
1283   if (src_window)
1284     src_toplevel = gdk_window_get_toplevel (src_window);
1285   else
1286     src_toplevel = NULL;
1287   if (dest_window)
1288     dest_toplevel = gdk_window_get_toplevel (dest_window);
1289   else
1290     dest_toplevel = NULL;
1291
1292   if (src_toplevel == NULL && dest_toplevel == NULL)
1293     return;
1294   
1295   if (src_toplevel == NULL ||
1296       src_toplevel == dest_toplevel)
1297     {
1298       /* Same toplevels */
1299       gdk_window_get_pointer (dest_toplevel,
1300                               &x, &y, &state);
1301       _gdk_synthesize_crossing_events (display,
1302                                        src_window,
1303                                        dest_window,
1304                                        device, source_device,
1305                                        crossing_mode,
1306                                        x, y, state,
1307                                        time,
1308                                        NULL,
1309                                        serial, FALSE);
1310     }
1311   else if (dest_toplevel == NULL)
1312     {
1313       gdk_window_get_pointer (src_toplevel,
1314                               &x, &y, &state);
1315       _gdk_synthesize_crossing_events (display,
1316                                        src_window,
1317                                        NULL,
1318                                        device, source_device,
1319                                        crossing_mode,
1320                                        x, y, state,
1321                                        time,
1322                                        NULL,
1323                                        serial, FALSE);
1324     }
1325   else
1326     {
1327       /* Different toplevels */
1328       gdk_window_get_pointer (src_toplevel,
1329                               &x, &y, &state);
1330       _gdk_synthesize_crossing_events (display,
1331                                        src_window,
1332                                        NULL,
1333                                        device, source_device,
1334                                        crossing_mode,
1335                                        x, y, state,
1336                                        time,
1337                                        NULL,
1338                                        serial, FALSE);
1339       gdk_window_get_pointer (dest_toplevel,
1340                               &x, &y, &state);
1341       _gdk_synthesize_crossing_events (display,
1342                                        NULL,
1343                                        dest_window,
1344                                        device, source_device,
1345                                        crossing_mode,
1346                                        x, y, state,
1347                                        time,
1348                                        NULL,
1349                                        serial, FALSE);
1350     }
1351 }
1352
1353 static GdkWindow *
1354 get_current_toplevel (GdkDisplay      *display,
1355                       GdkDevice       *device,
1356                       int             *x_out,
1357                       int             *y_out,
1358                       GdkModifierType *state_out)
1359 {
1360   GdkWindow *pointer_window;
1361   int x, y;
1362   GdkModifierType state;
1363
1364   pointer_window = _gdk_windowing_window_at_device_position (display, device, &x, &y, &state, TRUE);
1365
1366   if (pointer_window != NULL &&
1367       (GDK_WINDOW_DESTROYED (pointer_window) ||
1368        GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
1369        GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
1370     pointer_window = NULL;
1371
1372   *x_out = x;
1373   *y_out = y;
1374   *state_out = state;
1375   return pointer_window;
1376 }
1377
1378 static void
1379 switch_to_pointer_grab (GdkDisplay        *display,
1380                         GdkDevice         *device,
1381                         GdkDevice         *source_device,
1382                         GdkDeviceGrabInfo *grab,
1383                         GdkDeviceGrabInfo *last_grab,
1384                         guint32            time,
1385                         gulong             serial)
1386 {
1387   GdkWindow *src_window, *pointer_window, *new_toplevel;
1388   GdkPointerWindowInfo *info;
1389   GList *old_grabs;
1390   GdkModifierType state;
1391   int x, y;
1392
1393   /* Temporarily unset pointer to make sure we send the crossing events below */
1394   old_grabs = g_hash_table_lookup (display->device_grabs, device);
1395   g_hash_table_steal (display->device_grabs, device);
1396   info = _gdk_display_get_pointer_info (display, device);
1397
1398   if (grab)
1399     {
1400       /* New grab is in effect */
1401
1402       /* We need to generate crossing events for the grab.
1403        * However, there are never any crossing events for implicit grabs
1404        * TODO: ... Actually, this could happen if the pointer window
1405        *           doesn't have button mask so a parent gets the event...
1406        */
1407       if (!grab->implicit)
1408         {
1409           /* We send GRAB crossing events from the window under the pointer to the
1410              grab window. Except if there is an old grab then we start from that */
1411           if (last_grab)
1412             src_window = last_grab->window;
1413           else
1414             src_window = info->window_under_pointer;
1415
1416           if (src_window != grab->window)
1417             synthesize_crossing_events (display, device, source_device,
1418                                         src_window, grab->window,
1419                                         GDK_CROSSING_GRAB, time, serial);
1420
1421           /* !owner_event Grabbing a window that we're not inside, current status is
1422              now NULL (i.e. outside grabbed window) */
1423           if (!grab->owner_events && info->window_under_pointer != grab->window)
1424             _gdk_display_set_window_under_pointer (display, device, NULL);
1425         }
1426
1427       grab->activated = TRUE;
1428     }
1429
1430   if (last_grab)
1431     {
1432       new_toplevel = NULL;
1433
1434       if (grab == NULL /* ungrab */ ||
1435           (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
1436         {
1437           /* We force check what window we're in, and update the toplevel_under_pointer info,
1438            * as that won't get told of this change with toplevel enter events.
1439            */
1440           if (info->toplevel_under_pointer)
1441             g_object_unref (info->toplevel_under_pointer);
1442           info->toplevel_under_pointer = NULL;
1443
1444           new_toplevel = get_current_toplevel (display, device, &x, &y, &state);
1445           if (new_toplevel)
1446             {
1447               /* w is now toplevel and x,y in toplevel coords */
1448               info->toplevel_under_pointer = g_object_ref (new_toplevel);
1449               info->toplevel_x = x;
1450               info->toplevel_y = y;
1451               info->state = state;
1452             }
1453         }
1454
1455       if (grab == NULL) /* Ungrabbed, send events */
1456         {
1457           pointer_window = NULL;
1458           if (new_toplevel)
1459             {
1460               /* Find (possibly virtual) child window */
1461               pointer_window =
1462                 _gdk_window_find_descendant_at (new_toplevel,
1463                                                 x, y,
1464                                                 NULL, NULL);
1465             }
1466
1467           if (pointer_window != last_grab->window)
1468             synthesize_crossing_events (display, device, source_device,
1469                                         last_grab->window, pointer_window,
1470                                         GDK_CROSSING_UNGRAB, time, serial);
1471
1472           /* We're now ungrabbed, update the window_under_pointer */
1473           _gdk_display_set_window_under_pointer (display, device, pointer_window);
1474         }
1475     }
1476
1477   g_hash_table_insert (display->device_grabs, device, old_grabs);
1478 }
1479
1480 void
1481 _gdk_display_device_grab_update (GdkDisplay *display,
1482                                  GdkDevice  *device,
1483                                  GdkDevice  *source_device,
1484                                  gulong      current_serial)
1485 {
1486   GdkDeviceGrabInfo *current_grab, *next_grab;
1487   GList *grabs;
1488   guint32 time;
1489
1490   time = display->last_event_time;
1491   grabs = g_hash_table_lookup (display->device_grabs, device);
1492
1493   while (grabs != NULL)
1494     {
1495       current_grab = grabs->data;
1496
1497       if (current_grab->serial_start > current_serial)
1498         return; /* Hasn't started yet */
1499
1500       if (current_grab->serial_end > current_serial)
1501         {
1502           /* This one hasn't ended yet.
1503              its the currently active one or scheduled to be active */
1504
1505           if (!current_grab->activated)
1506             {
1507               if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
1508                 switch_to_pointer_grab (display, device, source_device, current_grab, NULL, time, current_serial);
1509             }
1510
1511           break;
1512         }
1513
1514       next_grab = NULL;
1515       if (grabs->next)
1516         {
1517           /* This is the next active grab */
1518           next_grab = grabs->next->data;
1519
1520           if (next_grab->serial_start > current_serial)
1521             next_grab = NULL; /* Actually its not yet active */
1522         }
1523
1524       if ((next_grab == NULL && current_grab->implicit_ungrab) ||
1525           (next_grab != NULL && current_grab->window != next_grab->window))
1526         generate_grab_broken_event (GDK_WINDOW (current_grab->window),
1527                                     device,
1528                                     current_grab->implicit,
1529                                     next_grab? next_grab->window : NULL);
1530
1531       /* Remove old grab */
1532       grabs = g_list_delete_link (grabs, grabs);
1533       g_hash_table_insert (display->device_grabs, device, grabs);
1534
1535       if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
1536         switch_to_pointer_grab (display, device, source_device,
1537                                 next_grab, current_grab,
1538                                 time, current_serial);
1539
1540       free_device_grab (current_grab);
1541     }
1542 }
1543
1544 static GList *
1545 grab_list_find (GList  *grabs,
1546                 gulong  serial)
1547 {
1548   GdkDeviceGrabInfo *grab;
1549
1550   while (grabs)
1551     {
1552       grab = grabs->data;
1553
1554       if (serial >= grab->serial_start && serial < grab->serial_end)
1555         return grabs;
1556
1557       grabs = grabs->next;
1558     }
1559
1560   return NULL;
1561 }
1562
1563 static GList *
1564 find_device_grab (GdkDisplay *display,
1565                    GdkDevice  *device,
1566                    gulong      serial)
1567 {
1568   GList *l;
1569
1570   l = g_hash_table_lookup (display->device_grabs, device);
1571   return grab_list_find (l, serial);
1572 }
1573
1574 GdkDeviceGrabInfo *
1575 _gdk_display_has_device_grab (GdkDisplay *display,
1576                               GdkDevice  *device,
1577                               gulong      serial)
1578 {
1579   GList *l;
1580
1581   l = find_device_grab (display, device, serial);
1582   if (l)
1583     return l->data;
1584
1585   return NULL;
1586 }
1587
1588 /* Returns true if last grab was ended
1589  * If if_child is non-NULL, end the grab only if the grabbed
1590  * window is the same as if_child or a descendant of it */
1591 gboolean
1592 _gdk_display_end_device_grab (GdkDisplay *display,
1593                               GdkDevice  *device,
1594                               gulong      serial,
1595                               GdkWindow  *if_child,
1596                               gboolean    implicit)
1597 {
1598   GdkDeviceGrabInfo *grab;
1599   GList *l;
1600
1601   l = find_device_grab (display, device, serial);
1602
1603   if (l == NULL)
1604     return FALSE;
1605
1606   grab = l->data;
1607   if (grab &&
1608       (if_child == NULL ||
1609        _gdk_window_event_parent_of (if_child, grab->window)))
1610     {
1611       grab->serial_end = serial;
1612       grab->implicit_ungrab = implicit;
1613       return l->next == NULL;
1614     }
1615   
1616   return FALSE;
1617 }
1618
1619 /* Returns TRUE if device events are not blocked by any grab */
1620 gboolean
1621 _gdk_display_check_grab_ownership (GdkDisplay *display,
1622                                    GdkDevice  *device,
1623                                    gulong      serial)
1624 {
1625   GHashTableIter iter;
1626   gpointer key, value;
1627   GdkGrabOwnership higher_ownership, device_ownership;
1628   gboolean device_is_keyboard;
1629
1630   g_hash_table_iter_init (&iter, display->device_grabs);
1631   higher_ownership = device_ownership = GDK_OWNERSHIP_NONE;
1632   device_is_keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD);
1633
1634   while (g_hash_table_iter_next (&iter, &key, &value))
1635     {
1636       GdkDeviceGrabInfo *grab;
1637       GdkDevice *dev;
1638       GList *grabs;
1639
1640       dev = key;
1641       grabs = value;
1642       grabs = grab_list_find (grabs, serial);
1643
1644       if (!grabs)
1645         continue;
1646
1647       /* Discard device if it's not of the same type */
1648       if ((device_is_keyboard && gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD) ||
1649           (!device_is_keyboard && gdk_device_get_source (dev) == GDK_SOURCE_KEYBOARD))
1650         continue;
1651
1652       grab = grabs->data;
1653
1654       if (dev == device)
1655         device_ownership = grab->ownership;
1656       else
1657         {
1658           if (grab->ownership > higher_ownership)
1659             higher_ownership = grab->ownership;
1660         }
1661     }
1662
1663   if (higher_ownership > device_ownership)
1664     {
1665       /* There's a higher priority ownership
1666        * going on for other device(s)
1667        */
1668       return FALSE;
1669     }
1670
1671   return TRUE;
1672 }
1673
1674 GdkPointerWindowInfo *
1675 _gdk_display_get_pointer_info (GdkDisplay *display,
1676                                GdkDevice  *device)
1677 {
1678   GdkPointerWindowInfo *info;
1679
1680   if (G_UNLIKELY (!device))
1681     return NULL;
1682
1683   info = g_hash_table_lookup (display->pointers_info, device);
1684
1685   if (G_UNLIKELY (!info))
1686     {
1687       info = g_slice_new0 (GdkPointerWindowInfo);
1688       g_hash_table_insert (display->pointers_info, device, info);
1689     }
1690
1691   return info;
1692 }
1693
1694 void
1695 _gdk_display_pointer_info_foreach (GdkDisplay                   *display,
1696                                    GdkDisplayPointerInfoForeach  func,
1697                                    gpointer                      user_data)
1698 {
1699   GHashTableIter iter;
1700   gpointer key, value;
1701
1702   g_hash_table_iter_init (&iter, display->pointers_info);
1703
1704   while (g_hash_table_iter_next (&iter, &key, &value))
1705     {
1706       GdkPointerWindowInfo *info = value;
1707       GdkDevice *device = key;
1708
1709       (func) (display, device, info, user_data);
1710     }
1711 }
1712
1713 /**
1714  * gdk_device_grab_info_libgtk_only:
1715  * @display: the display for which to get the grab information
1716  * @device: device to get the grab information from
1717  * @grab_window: (out) (transfer none): location to store current grab window
1718  * @owner_events: (out): location to store boolean indicating whether
1719  *   the @owner_events flag to gdk_keyboard_grab() or
1720  *   gdk_pointer_grab() was %TRUE.
1721  *
1722  * Determines information about the current keyboard grab.
1723  * This is not public API and must not be used by applications.
1724  *
1725  * Return value: %TRUE if this application currently has the
1726  *  keyboard grabbed.
1727  **/
1728 gboolean
1729 gdk_device_grab_info_libgtk_only (GdkDisplay  *display,
1730                                   GdkDevice   *device,
1731                                   GdkWindow  **grab_window,
1732                                   gboolean    *owner_events)
1733 {
1734   GdkDeviceGrabInfo *info;
1735
1736   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
1737   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
1738
1739   info = _gdk_display_get_last_device_grab (display, device);
1740
1741   if (info)
1742     {
1743       if (grab_window)
1744         *grab_window = info->window;
1745       if (owner_events)
1746         *owner_events = info->owner_events;
1747
1748       return TRUE;
1749     }
1750   else
1751     return FALSE;
1752 }
1753
1754 /**
1755  * gdk_display_pointer_is_grabbed:
1756  * @display: a #GdkDisplay
1757  *
1758  * Test if the pointer is grabbed.
1759  *
1760  * Returns: %TRUE if an active X pointer grab is in effect
1761  *
1762  * Since: 2.2
1763  *
1764  * Deprecated: 3.0: Use gdk_display_device_is_grabbed() instead.
1765  */
1766 gboolean
1767 gdk_display_pointer_is_grabbed (GdkDisplay *display)
1768 {
1769   GdkDeviceManager *device_manager;
1770   GList *devices, *dev;
1771   GdkDevice *device;
1772
1773   g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
1774
1775   device_manager = gdk_display_get_device_manager (display);
1776   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
1777
1778   for (dev = devices; dev; dev = dev->next)
1779     {
1780       device = dev->data;
1781
1782       if (gdk_device_get_source (device) == GDK_SOURCE_MOUSE &&
1783           gdk_display_device_is_grabbed (display, device))
1784         return TRUE;
1785     }
1786
1787   return FALSE;
1788 }
1789
1790 /**
1791  * gdk_display_device_is_grabbed:
1792  * @display: a #GdkDisplay
1793  * @device: a #GdkDevice
1794  *
1795  * Returns %TRUE if there is an ongoing grab on @device for @display.
1796  *
1797  * Returns: %TRUE if there is a grab in effect for @device.
1798  **/
1799 gboolean
1800 gdk_display_device_is_grabbed (GdkDisplay *display,
1801                                GdkDevice  *device)
1802 {
1803   GdkDeviceGrabInfo *info;
1804
1805   g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
1806   g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
1807
1808   /* What we're interested in is the steady state (ie last grab),
1809      because we're interested e.g. if we grabbed so that we
1810      can ungrab, even if our grab is not active just yet. */
1811   info = _gdk_display_get_last_device_grab (display, device);
1812
1813   return (info && !info->implicit);
1814 }
1815
1816 /**
1817  * gdk_display_get_device_manager:
1818  * @display: a #GdkDisplay.
1819  *
1820  * Returns the #GdkDeviceManager associated to @display.
1821  *
1822  * Returns: (transfer none): A #GdkDeviceManager, or %NULL. This memory is
1823  *          owned by GDK and must not be freed or unreferenced.
1824  *
1825  * Since: 3.0
1826  **/
1827 GdkDeviceManager *
1828 gdk_display_get_device_manager (GdkDisplay *display)
1829 {
1830   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1831
1832   return display->device_manager;
1833 }