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