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