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