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