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