]> Pileus Git - ~andy/gtk/blob - gdk/gdkdisplay.c
Merge in Gdk-custom.c introspection annotations
[~andy/gtk] / gdk / gdkdisplay.c
1 /* GDK - The GIMP Drawing Kit
2  * gdkdisplay.c
3  * 
4  * Copyright 2001 Sun Microsystems Inc. 
5  *
6  * Erwann Chenede <erwann.chenede@sun.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "config.h"
25 #include <math.h>
26 #include <glib.h>
27 #include "gdk.h"                /* gdk_event_send_client_message() */
28 #include "gdkdisplay.h"
29 #include "gdkwindowimpl.h"
30 #include "gdkinternals.h"
31 #include "gdkmarshalers.h"
32 #include "gdkscreen.h"
33 #include "gdkalias.h"
34
35 enum {
36   CLOSED,
37   LAST_SIGNAL
38 };
39
40 static void gdk_display_dispose    (GObject         *object);
41 static void gdk_display_finalize   (GObject         *object);
42
43
44 static void       singlehead_get_pointer (GdkDisplay       *display,
45                                           GdkScreen       **screen,
46                                           gint             *x,
47                                           gint             *y,
48                                           GdkModifierType  *mask);
49 static GdkWindow* singlehead_window_get_pointer (GdkDisplay       *display,
50                                                  GdkWindow        *window,
51                                                  gint             *x,
52                                                  gint             *y,
53                                                  GdkModifierType  *mask);
54 static GdkWindow* singlehead_window_at_pointer  (GdkDisplay       *display,
55                                                  gint             *win_x,
56                                                  gint             *win_y);
57
58 static GdkWindow* singlehead_default_window_get_pointer (GdkWindow       *window,
59                                                          gint            *x,
60                                                          gint            *y,
61                                                          GdkModifierType *mask);
62 static GdkWindow* singlehead_default_window_at_pointer  (GdkScreen       *screen,
63                                                          gint            *win_x,
64                                                          gint            *win_y);
65 static GdkWindow *gdk_window_real_window_get_pointer     (GdkDisplay       *display,
66                                                           GdkWindow        *window,
67                                                           gint             *x,
68                                                           gint             *y,
69                                                           GdkModifierType  *mask);
70 static GdkWindow *gdk_display_real_get_window_at_pointer (GdkDisplay       *display,
71                                                           gint             *win_x,
72                                                           gint             *win_y);
73
74 static guint signals[LAST_SIGNAL] = { 0 };
75
76 static char *gdk_sm_client_id;
77
78 static const GdkDisplayPointerHooks default_pointer_hooks = {
79   _gdk_windowing_get_pointer,
80   gdk_window_real_window_get_pointer,
81   gdk_display_real_get_window_at_pointer
82 };
83
84 static const GdkDisplayPointerHooks singlehead_pointer_hooks = {
85   singlehead_get_pointer,
86   singlehead_window_get_pointer,
87   singlehead_window_at_pointer
88 };
89
90 static const GdkPointerHooks singlehead_default_pointer_hooks = {
91   singlehead_default_window_get_pointer,
92   singlehead_default_window_at_pointer
93 };
94
95 static const GdkPointerHooks *singlehead_current_pointer_hooks = &singlehead_default_pointer_hooks;
96
97 G_DEFINE_TYPE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
98
99 static void
100 gdk_display_class_init (GdkDisplayClass *class)
101 {
102   GObjectClass *object_class = G_OBJECT_CLASS (class);
103   
104   object_class->finalize = gdk_display_finalize;
105   object_class->dispose = gdk_display_dispose;
106
107   /**
108    * GdkDisplay::closed:
109    * @display: the object on which the signal is emitted
110    * @is_error: %TRUE if the display was closed due to an error
111    *
112    * The ::closed signal is emitted when the connection to the windowing
113    * system for @display is closed.
114    *
115    * Since: 2.2
116    */   
117   signals[CLOSED] =
118     g_signal_new (g_intern_static_string ("closed"),
119                   G_OBJECT_CLASS_TYPE (object_class),
120                   G_SIGNAL_RUN_LAST,
121                   G_STRUCT_OFFSET (GdkDisplayClass, closed),
122                   NULL, NULL,
123                   _gdk_marshal_VOID__BOOLEAN,
124                   G_TYPE_NONE,
125                   1,
126                   G_TYPE_BOOLEAN);
127 }
128
129 static void
130 gdk_display_init (GdkDisplay *display)
131 {
132   _gdk_displays = g_slist_prepend (_gdk_displays, display);
133
134   display->button_click_time[0] = display->button_click_time[1] = 0;
135   display->button_window[0] = display->button_window[1] = NULL;
136   display->button_number[0] = display->button_number[1] = -1;
137   display->button_x[0] = display->button_x[1] = 0;
138   display->button_y[0] = display->button_y[1] = 0;
139
140   display->double_click_time = 250;
141   display->double_click_distance = 5;
142
143   display->pointer_hooks = &default_pointer_hooks;
144 }
145
146 static void
147 gdk_display_dispose (GObject *object)
148 {
149   GdkDisplay *display = GDK_DISPLAY_OBJECT (object);
150
151   g_list_foreach (display->queued_events, (GFunc)gdk_event_free, NULL);
152   g_list_free (display->queued_events);
153   display->queued_events = NULL;
154   display->queued_tail = NULL;
155
156   _gdk_displays = g_slist_remove (_gdk_displays, object);
157
158   if (gdk_display_get_default() == display)
159     {
160       if (_gdk_displays)
161         gdk_display_manager_set_default_display (gdk_display_manager_get(),
162                                                  _gdk_displays->data);
163       else
164         gdk_display_manager_set_default_display (gdk_display_manager_get(),
165                                                  NULL);
166     }
167
168   G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
169 }
170
171 static void
172 gdk_display_finalize (GObject *object)
173 {
174   G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
175 }
176
177 /**
178  * gdk_display_close:
179  * @display: a #GdkDisplay
180  *
181  * Closes the connection to the windowing system for the given display,
182  * and cleans up associated resources.
183  *
184  * Since: 2.2
185  */
186 void
187 gdk_display_close (GdkDisplay *display)
188 {
189   g_return_if_fail (GDK_IS_DISPLAY (display));
190
191   if (!display->closed)
192     {
193       display->closed = TRUE;
194       
195       g_signal_emit (display, signals[CLOSED], 0, FALSE);
196       g_object_run_dispose (G_OBJECT (display));
197       
198       g_object_unref (display);
199     }
200 }
201
202 /**
203  * gdk_display_get_event:
204  * @display: a #GdkDisplay
205  * 
206  * Gets the next #GdkEvent to be processed for @display, fetching events from the
207  * windowing system if necessary.
208  * 
209  * Return value: the next #GdkEvent to be processed, or %NULL if no events
210  * are pending. The returned #GdkEvent should be freed with gdk_event_free().
211  *
212  * Since: 2.2
213  **/
214 GdkEvent*
215 gdk_display_get_event (GdkDisplay *display)
216 {
217   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
218   
219   _gdk_events_queue (display);
220   return _gdk_event_unqueue (display);
221 }
222
223 /**
224  * gdk_display_peek_event:
225  * @display: a #GdkDisplay 
226  * 
227  * Gets a copy of the first #GdkEvent in the @display's event queue, without
228  * removing the event from the queue.  (Note that this function will
229  * not get more events from the windowing system.  It only checks the events
230  * that have already been moved to the GDK event queue.)
231  * 
232  * Return value: a copy of the first #GdkEvent on the event queue, or %NULL 
233  * if no events are in the queue. The returned #GdkEvent should be freed with
234  * gdk_event_free().
235  *
236  * Since: 2.2
237  **/
238 GdkEvent*
239 gdk_display_peek_event (GdkDisplay *display)
240 {
241   GList *tmp_list;
242
243   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
244
245   tmp_list = _gdk_event_queue_find_first (display);
246   
247   if (tmp_list)
248     return gdk_event_copy (tmp_list->data);
249   else
250     return NULL;
251 }
252
253 /**
254  * gdk_display_put_event:
255  * @display: a #GdkDisplay
256  * @event: a #GdkEvent.
257  *
258  * Appends a copy of the given event onto the front of the event
259  * queue for @display.
260  *
261  * Since: 2.2
262  **/
263 void
264 gdk_display_put_event (GdkDisplay     *display,
265                        const GdkEvent *event)
266 {
267   g_return_if_fail (GDK_IS_DISPLAY (display));
268   g_return_if_fail (event != NULL);
269
270   _gdk_event_queue_append (display, gdk_event_copy (event));
271   /* If the main loop is blocking in a different thread, wake it up */
272   g_main_context_wakeup (NULL); 
273 }
274
275 /**
276  * gdk_pointer_ungrab:
277  * @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no 
278  *  timestamp is available.
279  *
280  * Ungrabs the pointer on the default display, if it is grabbed by this 
281  * application.
282  **/
283 void
284 gdk_pointer_ungrab (guint32 time)
285 {
286   gdk_display_pointer_ungrab (gdk_display_get_default (), time);
287 }
288
289 /**
290  * gdk_pointer_is_grabbed:
291  * 
292  * Returns %TRUE if the pointer on the default display is currently 
293  * grabbed by this application.
294  *
295  * Note that this does not take the inmplicit pointer grab on button
296  * presses into account.
297
298  * Return value: %TRUE if the pointer is currently grabbed by this application.* 
299  **/
300 gboolean
301 gdk_pointer_is_grabbed (void)
302 {
303   return gdk_display_pointer_is_grabbed (gdk_display_get_default ());
304 }
305
306 /**
307  * gdk_keyboard_ungrab:
308  * @time_: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no
309  *        timestamp is available.
310  * 
311  * Ungrabs the keyboard on the default display, if it is grabbed by this 
312  * application.
313  **/
314 void
315 gdk_keyboard_ungrab (guint32 time)
316 {
317   gdk_display_keyboard_ungrab (gdk_display_get_default (), time);
318 }
319
320 /**
321  * gdk_beep:
322  * 
323  * Emits a short beep on the default display.
324  **/
325 void
326 gdk_beep (void)
327 {
328   gdk_display_beep (gdk_display_get_default ());
329 }
330
331 /**
332  * gdk_event_send_client_message:
333  * @event: the #GdkEvent to send, which should be a #GdkEventClient.
334  * @winid:  the window to send the X ClientMessage event to.
335  * 
336  * Sends an X ClientMessage event to a given window (which must be
337  * on the default #GdkDisplay.)
338  * This could be used for communicating between different applications,
339  * though the amount of data is limited to 20 bytes.
340  * 
341  * Return value: non-zero on success.
342  **/
343 gboolean
344 gdk_event_send_client_message (GdkEvent        *event,
345                                GdkNativeWindow  winid)
346 {
347   g_return_val_if_fail (event != NULL, FALSE);
348
349   return gdk_event_send_client_message_for_display (gdk_display_get_default (),
350                                                     event, winid);
351 }
352
353 /**
354  * gdk_event_send_clientmessage_toall:
355  * @event: the #GdkEvent to send, which should be a #GdkEventClient.
356  *
357  * Sends an X ClientMessage event to all toplevel windows on the default
358  * #GdkScreen.
359  *
360  * Toplevel windows are determined by checking for the WM_STATE property, as
361  * described in the Inter-Client Communication Conventions Manual (ICCCM).
362  * If no windows are found with the WM_STATE property set, the message is sent
363  * to all children of the root window.
364  **/
365 void
366 gdk_event_send_clientmessage_toall (GdkEvent *event)
367 {
368   g_return_if_fail (event != NULL);
369
370   gdk_screen_broadcast_client_message (gdk_screen_get_default (), event);
371 }
372
373 /**
374  * gdk_device_get_core_pointer:
375  * 
376  * Returns the core pointer device for the default display.
377  * 
378  * Return value: the core pointer device; this is owned by the
379  *   display and should not be freed.
380  **/
381 GdkDevice *
382 gdk_device_get_core_pointer (void)
383 {
384   return gdk_display_get_core_pointer (gdk_display_get_default ());
385 }
386
387 /**
388  * gdk_display_get_core_pointer:
389  * @display: a #GdkDisplay
390  * 
391  * Returns the core pointer device for the given display
392  * 
393  * Return value: the core pointer device; this is owned by the
394  *   display and should not be freed.
395  *
396  * Since: 2.2
397  **/
398 GdkDevice *
399 gdk_display_get_core_pointer (GdkDisplay *display)
400 {
401   return display->core_pointer;
402 }
403
404 /**
405  * gdk_set_sm_client_id:
406  * @sm_client_id: the client id assigned by the session manager when the
407  *    connection was opened, or %NULL to remove the property.
408  * 
409  * Sets the <literal>SM_CLIENT_ID</literal> property on the application's leader window so that
410  * the window manager can save the application's state using the X11R6 ICCCM
411  * session management protocol.
412  *
413  * See the X Session Management Library documentation for more information on
414  * session management and the Inter-Client Communication Conventions Manual
415  * (ICCCM) for information on the <literal>WM_CLIENT_LEADER</literal> property. 
416  * (Both documents are part of the X Window System distribution.)
417  **/
418 void
419 gdk_set_sm_client_id (const gchar* sm_client_id)
420 {
421   GSList *displays, *tmp_list;
422   
423   g_free (gdk_sm_client_id);
424   gdk_sm_client_id = g_strdup (sm_client_id);
425
426   displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
427   for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
428     _gdk_windowing_display_set_sm_client_id (tmp_list->data, sm_client_id);
429
430   g_slist_free (displays);
431 }
432
433 /**
434  * _gdk_get_sm_client_id:
435  * 
436  * Gets the client ID set with gdk_set_sm_client_id(), if any.
437  * 
438  * Return value: Session ID, or %NULL if gdk_set_sm_client_id()
439  *               has never been called.
440  **/
441 const char *
442 _gdk_get_sm_client_id (void)
443 {
444   return gdk_sm_client_id;
445 }
446
447 void
448 _gdk_display_enable_motion_hints (GdkDisplay *display)
449 {
450   gulong serial;
451   
452   if (display->pointer_info.motion_hint_serial != 0)
453     {
454       serial = _gdk_windowing_window_get_next_serial (display);
455       /* We might not actually generate the next request, so
456          make sure this triggers always, this may cause it to
457          trigger slightly too early, but this is just a hint
458          anyway. */
459       if (serial > 0)
460         serial--;
461       if (serial < display->pointer_info.motion_hint_serial)
462         display->pointer_info.motion_hint_serial = serial;
463     }
464 }
465
466 /**
467  * gdk_display_get_pointer:
468  * @display: a #GdkDisplay
469  * @screen: (allow-none): location to store the screen that the
470  *          cursor is on, or %NULL.
471  * @x: (out): location to store root window X coordinate of pointer, or %NULL.
472  * @y: (out): location to store root window Y coordinate of pointer, or %NULL.
473  * @mask: (out): location to store current modifier mask, or %NULL
474  *
475  * Gets the current location of the pointer and the current modifier
476  * mask for a given display.
477  *
478  * Since: 2.2
479  **/
480 void
481 gdk_display_get_pointer (GdkDisplay      *display,
482                          GdkScreen      **screen,
483                          gint            *x,
484                          gint            *y,
485                          GdkModifierType *mask)
486 {
487   GdkScreen *tmp_screen;
488   gint tmp_x, tmp_y;
489   GdkModifierType tmp_mask;
490   
491   g_return_if_fail (GDK_IS_DISPLAY (display));
492
493   display->pointer_hooks->get_pointer (display, &tmp_screen, &tmp_x, &tmp_y, &tmp_mask);
494
495   if (screen)
496     *screen = tmp_screen;
497   if (x)
498     *x = tmp_x;
499   if (y)
500     *y = tmp_y;
501   if (mask)
502     *mask = tmp_mask;
503 }
504
505 static GdkWindow *
506 gdk_display_real_get_window_at_pointer (GdkDisplay *display,
507                                         gint       *win_x,
508                                         gint       *win_y)
509 {
510   GdkWindow *window;
511   gint x, y;
512
513   window = _gdk_windowing_window_at_pointer (display, &x, &y, NULL, FALSE);
514
515   /* This might need corrections, as the native window returned
516      may contain client side children */
517   if (window)
518     {
519       double xx, yy;
520
521       window = _gdk_window_find_descendant_at (window,
522                                                x, y,
523                                                &xx, &yy);
524       x = floor (xx + 0.5);
525       y = floor (yy + 0.5);
526     }
527
528   *win_x = x;
529   *win_y = y;
530
531   return window;
532 }
533
534 static GdkWindow *
535 gdk_window_real_window_get_pointer (GdkDisplay       *display,
536                                     GdkWindow        *window,
537                                     gint             *x,
538                                     gint             *y,
539                                     GdkModifierType  *mask)
540 {
541   GdkWindowObject *private;
542   gint tmpx, tmpy;
543   GdkModifierType tmp_mask;
544   gboolean normal_child;
545
546   private = (GdkWindowObject *) window;
547
548   normal_child = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_pointer (window,
549                                                                          &tmpx, &tmpy,
550                                                                          &tmp_mask);
551   /* We got the coords on the impl, convert to the window */
552   tmpx -= private->abs_x;
553   tmpy -= private->abs_y;
554
555   if (x)
556     *x = tmpx;
557   if (y)
558     *y = tmpy;
559   if (mask)
560     *mask = tmp_mask;
561
562   if (normal_child)
563     return _gdk_window_find_child_at (window, tmpx, tmpy);
564   return NULL;
565 }
566
567 /**
568  * gdk_display_get_window_at_pointer:
569  * @display: a #GdkDisplay
570  * @win_x: (out) (allow-none): return location for x coordinate of the pointer location relative
571  *    to the window origin, or %NULL
572  * @win_y: (out) (allow-none): return location for y coordinate of the pointer location relative
573  &    to the window origin, or %NULL
574  *
575  * Obtains the window underneath the mouse pointer, returning the location
576  * of the pointer in that window in @win_x, @win_y for @screen. Returns %NULL
577  * if the window under the mouse pointer is not known to GDK (for example, 
578  * belongs to another application).
579  *
580  * Returns: (transfer none): the window under the mouse pointer, or %NULL
581  *
582  * Since: 2.2
583  **/
584 GdkWindow *
585 gdk_display_get_window_at_pointer (GdkDisplay *display,
586                                    gint       *win_x,
587                                    gint       *win_y)
588 {
589   gint tmp_x, tmp_y;
590   GdkWindow *window;
591
592   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
593
594   window = display->pointer_hooks->window_at_pointer (display, &tmp_x, &tmp_y);
595
596   if (win_x)
597     *win_x = tmp_x;
598   if (win_y)
599     *win_y = tmp_y;
600
601   return window;
602 }
603
604 /**
605  * gdk_display_set_pointer_hooks:
606  * @display: a #GdkDisplay
607  * @new_hooks: a table of pointers to functions for getting
608  *   quantities related to the current pointer position,
609  *   or %NULL to restore the default table.
610  * 
611  * This function allows for hooking into the operation
612  * of getting the current location of the pointer on a particular
613  * display. This is only useful for such low-level tools as an
614  * event recorder. Applications should never have any
615  * reason to use this facility.
616  *
617  * Return value: the previous pointer hook table
618  *
619  * Since: 2.2
620  **/
621 GdkDisplayPointerHooks *
622 gdk_display_set_pointer_hooks (GdkDisplay                   *display,
623                                const GdkDisplayPointerHooks *new_hooks)
624 {
625   const GdkDisplayPointerHooks *result;
626
627   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
628   result = display->pointer_hooks;
629
630   if (new_hooks)
631     display->pointer_hooks = new_hooks;
632   else
633     display->pointer_hooks = &default_pointer_hooks;
634
635   return (GdkDisplayPointerHooks *)result;
636 }
637
638 static void
639 singlehead_get_pointer (GdkDisplay       *display,
640                         GdkScreen       **screen,
641                         gint             *x,
642                         gint             *y,
643                         GdkModifierType  *mask)
644 {
645   GdkScreen *default_screen = gdk_display_get_default_screen (display);
646   GdkWindow *root_window = gdk_screen_get_root_window (default_screen);
647
648   *screen = default_screen;
649
650   singlehead_current_pointer_hooks->get_pointer (root_window, x, y, mask);
651 }
652
653 static GdkWindow*
654 singlehead_window_get_pointer (GdkDisplay       *display,
655                                GdkWindow        *window,
656                                gint             *x,
657                                gint             *y,
658                                GdkModifierType  *mask)
659 {
660   return singlehead_current_pointer_hooks->get_pointer (window, x, y, mask);
661 }
662
663 static GdkWindow*
664 singlehead_window_at_pointer   (GdkDisplay *display,
665                                 gint       *win_x,
666                                 gint       *win_y)
667 {
668   GdkScreen *default_screen = gdk_display_get_default_screen (display);
669
670   return singlehead_current_pointer_hooks->window_at_pointer (default_screen,
671                                                               win_x, win_y);
672 }
673
674 static GdkWindow*
675 singlehead_default_window_get_pointer (GdkWindow       *window,
676                                        gint            *x,
677                                        gint            *y,
678                                        GdkModifierType *mask)
679 {
680   return gdk_window_real_window_get_pointer (gdk_drawable_get_display (window),
681                                              window, x, y, mask);
682 }
683
684 static GdkWindow*
685 singlehead_default_window_at_pointer  (GdkScreen       *screen,
686                                        gint            *win_x,
687                                        gint            *win_y)
688 {
689   return gdk_display_real_get_window_at_pointer (gdk_screen_get_display (screen),
690                                                  win_x, win_y);
691 }
692
693 /**
694  * gdk_set_pointer_hooks:
695  * @new_hooks: a table of pointers to functions for getting
696  *   quantities related to the current pointer position,
697  *   or %NULL to restore the default table.
698  * 
699  * This function allows for hooking into the operation
700  * of getting the current location of the pointer. This
701  * is only useful for such low-level tools as an
702  * event recorder. Applications should never have any
703  * reason to use this facility.
704  *
705  * This function is not multihead safe. For multihead operation,
706  * see gdk_display_set_pointer_hooks().
707  * 
708  * Return value: the previous pointer hook table
709  **/
710 GdkPointerHooks *
711 gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks)
712 {
713   const GdkPointerHooks *result = singlehead_current_pointer_hooks;
714
715   if (new_hooks)
716     singlehead_current_pointer_hooks = new_hooks;
717   else
718     singlehead_current_pointer_hooks = &singlehead_default_pointer_hooks;
719
720   gdk_display_set_pointer_hooks (gdk_display_get_default (),
721                                  &singlehead_pointer_hooks);
722   
723   return (GdkPointerHooks *)result;
724 }
725
726 static void
727 generate_grab_broken_event (GdkWindow *window,
728                             gboolean   keyboard,
729                             gboolean   implicit,
730                             GdkWindow *grab_window)
731 {
732   g_return_if_fail (window != NULL);
733
734   if (!GDK_WINDOW_DESTROYED (window))
735     {
736       GdkEvent event;
737       event.type = GDK_GRAB_BROKEN;
738       event.grab_broken.window = window;
739       event.grab_broken.send_event = 0;
740       event.grab_broken.keyboard = keyboard;
741       event.grab_broken.implicit = implicit;
742       event.grab_broken.grab_window = grab_window;
743       gdk_event_put (&event);
744     }
745 }
746
747 GdkPointerGrabInfo *
748 _gdk_display_get_last_pointer_grab (GdkDisplay *display)
749 {
750   GList *l;
751
752   l = g_list_last (display->pointer_grabs);
753
754   if (l == NULL)
755     return NULL;
756   else
757     return (GdkPointerGrabInfo *)l->data;
758 }
759
760
761 GdkPointerGrabInfo *
762 _gdk_display_add_pointer_grab (GdkDisplay *display,
763                                GdkWindow *window,
764                                GdkWindow *native_window,
765                                gboolean owner_events,
766                                GdkEventMask event_mask,
767                                unsigned long serial_start,
768                                guint32 time,
769                                gboolean implicit)
770 {
771   GdkPointerGrabInfo *info, *other_info;
772   GList *l;
773
774   info = g_new0 (GdkPointerGrabInfo, 1);
775
776   info->window = g_object_ref (window);
777   info->native_window = g_object_ref (native_window);
778   info->serial_start = serial_start;
779   info->serial_end = G_MAXULONG;
780   info->owner_events = owner_events;
781   info->event_mask = event_mask;
782   info->time = time;
783   info->implicit = implicit;
784
785   /* Find the first grab that has a larger start time (if any) and insert
786    * before that. I.E we insert after already existing grabs with same
787    * start time */
788   for (l = display->pointer_grabs; l != NULL; l = l->next)
789     {
790       other_info = l->data;
791       
792       if (info->serial_start < other_info->serial_start)
793         break;
794     }
795   display->pointer_grabs =
796     g_list_insert_before (display->pointer_grabs, l, info);
797
798   /* Make sure the new grab end before next grab */
799   if (l)
800     {
801       other_info = l->data;
802       info->serial_end = other_info->serial_start;
803     }
804   
805   /* Find any previous grab and update its end time */
806   l = g_list_find  (display->pointer_grabs, info);
807   l = l->prev;
808   if (l)
809     {
810       other_info = l->data;
811       other_info->serial_end = serial_start;
812     }
813
814   return info;
815 }
816
817 static void
818 free_pointer_grab (GdkPointerGrabInfo *info)
819 {
820   g_object_unref (info->window);
821   g_object_unref (info->native_window);
822   g_free (info);
823 }
824
825 /* _gdk_synthesize_crossing_events only works inside one toplevel.
826    This function splits things into two calls if needed, converting the
827    coordinates to the right toplevel */
828 static void
829 synthesize_crossing_events (GdkDisplay *display,
830                             GdkWindow *src_window,
831                             GdkWindow *dest_window,
832                             GdkCrossingMode crossing_mode,
833                             guint32 time,
834                             gulong serial)
835 {
836   GdkWindow *src_toplevel, *dest_toplevel;
837   GdkModifierType state;
838   int x, y;
839
840   /* We use the native crossing events if all native */
841   if (_gdk_native_windows)
842     return;
843   
844   if (src_window)
845     src_toplevel = gdk_window_get_toplevel (src_window);
846   else
847     src_toplevel = NULL;
848   if (dest_window)
849     dest_toplevel = gdk_window_get_toplevel (dest_window);
850   else
851     dest_toplevel = NULL;
852
853   if (src_toplevel == NULL && dest_toplevel == NULL)
854     return;
855   
856   if (src_toplevel == NULL ||
857       src_toplevel == dest_toplevel)
858     {
859       /* Same toplevels */
860       gdk_window_get_pointer (dest_toplevel,
861                               &x, &y, &state);
862       _gdk_synthesize_crossing_events (display,
863                                        src_window,
864                                        dest_window,
865                                        crossing_mode,
866                                        x, y, state,
867                                        time,
868                                        NULL,
869                                        serial, FALSE);
870     }
871   else if (dest_toplevel == NULL)
872     {
873       gdk_window_get_pointer (src_toplevel,
874                               &x, &y, &state);
875       _gdk_synthesize_crossing_events (display,
876                                        src_window,
877                                        NULL,
878                                        crossing_mode,
879                                        x, y, state,
880                                        time,
881                                        NULL,
882                                        serial, FALSE);
883     }
884   else
885     {
886       /* Different toplevels */
887       gdk_window_get_pointer (src_toplevel,
888                               &x, &y, &state);
889       _gdk_synthesize_crossing_events (display,
890                                        src_window,
891                                        NULL,
892                                        crossing_mode,
893                                        x, y, state,
894                                        time,
895                                        NULL,
896                                        serial, FALSE);
897       gdk_window_get_pointer (dest_toplevel,
898                               &x, &y, &state);
899       _gdk_synthesize_crossing_events (display,
900                                        NULL,
901                                        dest_window,
902                                        crossing_mode,
903                                        x, y, state,
904                                        time,
905                                        NULL,
906                                        serial, FALSE);
907     }
908 }
909
910 static GdkWindow *
911 get_current_toplevel (GdkDisplay *display,
912                       int *x_out, int *y_out,
913                       GdkModifierType *state_out)
914 {
915   GdkWindow *pointer_window;
916   int x, y;
917   GdkModifierType state;
918
919   pointer_window = _gdk_windowing_window_at_pointer (display,  &x, &y, &state, TRUE);
920   if (pointer_window != NULL &&
921       (GDK_WINDOW_DESTROYED (pointer_window) ||
922        GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
923        GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
924     pointer_window = NULL;
925
926   *x_out = x;
927   *y_out = y;
928   *state_out = state;
929   return pointer_window;
930 }
931
932 static void
933 switch_to_pointer_grab (GdkDisplay *display,
934                         GdkPointerGrabInfo *grab,
935                         GdkPointerGrabInfo *last_grab,
936                         guint32 time,
937                         gulong serial)
938 {
939   GdkWindow *src_window, *pointer_window, *new_toplevel;
940   GList *old_grabs;
941   GdkModifierType state;
942   int x, y;
943
944   /* Temporarily unset pointer to make sure we send the crossing events below */
945   old_grabs = display->pointer_grabs;
946   display->pointer_grabs = NULL;
947   
948   if (grab)
949     {
950       /* New grab is in effect */
951       
952       /* We need to generate crossing events for the grab.
953        * However, there are never any crossing events for implicit grabs
954        * TODO: ... Actually, this could happen if the pointer window
955        *           doesn't have button mask so a parent gets the event... 
956        */
957       if (!grab->implicit)
958         {
959           /* We send GRAB crossing events from the window under the pointer to the
960              grab window. Except if there is an old grab then we start from that */
961           if (last_grab)
962             src_window = last_grab->window;
963           else
964             src_window = display->pointer_info.window_under_pointer;
965           
966           if (src_window != grab->window)
967             {
968               synthesize_crossing_events (display,
969                                           src_window, grab->window,
970                                           GDK_CROSSING_GRAB, time, serial);
971             }
972
973           /* !owner_event Grabbing a window that we're not inside, current status is
974              now NULL (i.e. outside grabbed window) */
975           if (!grab->owner_events && display->pointer_info.window_under_pointer != grab->window)
976             _gdk_display_set_window_under_pointer (display, NULL);
977         }
978
979       grab->activated = TRUE;
980     }
981
982   if (last_grab)
983     {
984       new_toplevel = NULL;
985
986       if (grab == NULL /* ungrab */ ||
987           (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
988         {
989           /* We force check what window we're in, and update the toplevel_under_pointer info,
990            * as that won't get told of this change with toplevel enter events.
991            */
992           if (display->pointer_info.toplevel_under_pointer)
993             g_object_unref (display->pointer_info.toplevel_under_pointer);
994           display->pointer_info.toplevel_under_pointer = NULL;
995
996           new_toplevel = get_current_toplevel (display, &x, &y, &state);
997           if (new_toplevel)
998             {
999               /* w is now toplevel and x,y in toplevel coords */
1000               display->pointer_info.toplevel_under_pointer = g_object_ref (new_toplevel);
1001               display->pointer_info.toplevel_x = x;
1002               display->pointer_info.toplevel_y = y;
1003               display->pointer_info.state = state;
1004             }
1005         }
1006
1007       if (grab == NULL) /* Ungrabbed, send events */
1008         {
1009           pointer_window = NULL;
1010           if (new_toplevel)
1011             {
1012               /* Find (possibly virtual) child window */
1013               pointer_window =
1014                 _gdk_window_find_descendant_at (new_toplevel,
1015                                                 x, y,
1016                                                 NULL, NULL);
1017             }
1018           
1019           if (pointer_window != last_grab->window)
1020             synthesize_crossing_events (display,
1021                                         last_grab->window, pointer_window,
1022                                         GDK_CROSSING_UNGRAB, time, serial);
1023           
1024           /* We're now ungrabbed, update the window_under_pointer */
1025           _gdk_display_set_window_under_pointer (display, pointer_window);
1026         }
1027     }
1028   
1029   display->pointer_grabs = old_grabs;
1030
1031 }
1032
1033 void
1034 _gdk_display_pointer_grab_update (GdkDisplay *display,
1035                                   gulong current_serial)
1036 {
1037   GdkPointerGrabInfo *current_grab, *next_grab;
1038   guint32 time;
1039   
1040   time = display->last_event_time;
1041
1042   while (display->pointer_grabs != NULL)
1043     {
1044       current_grab = display->pointer_grabs->data;
1045
1046       if (current_grab->serial_start > current_serial)
1047         return; /* Hasn't started yet */
1048       
1049       if (current_grab->serial_end > current_serial)
1050         {
1051           /* This one hasn't ended yet.
1052              its the currently active one or scheduled to be active */
1053
1054           if (!current_grab->activated)
1055             switch_to_pointer_grab (display, current_grab, NULL, time, current_serial);
1056           
1057           break;
1058         }
1059
1060
1061       next_grab = NULL;
1062       if (display->pointer_grabs->next)
1063         {
1064           /* This is the next active grab */
1065           next_grab = display->pointer_grabs->next->data;
1066           
1067           if (next_grab->serial_start > current_serial)
1068             next_grab = NULL; /* Actually its not yet active */
1069         }
1070
1071       if ((next_grab == NULL && current_grab->implicit_ungrab) ||
1072           (next_grab != NULL && current_grab->window != next_grab->window))
1073         generate_grab_broken_event (GDK_WINDOW (current_grab->window),
1074                                     FALSE, current_grab->implicit,
1075                                     next_grab? next_grab->window : NULL);
1076
1077       /* Remove old grab */
1078       display->pointer_grabs =
1079         g_list_delete_link (display->pointer_grabs,
1080                             display->pointer_grabs);
1081       
1082       switch_to_pointer_grab (display,
1083                               next_grab, current_grab,
1084                               time, current_serial);
1085       
1086       free_pointer_grab (current_grab);
1087     }
1088 }
1089
1090 static GList *
1091 find_pointer_grab (GdkDisplay *display,
1092                    gulong serial)
1093 {
1094   GdkPointerGrabInfo *grab;
1095   GList *l;
1096
1097   for (l = display->pointer_grabs; l != NULL; l = l->next)
1098     {
1099       grab = l->data;
1100
1101       if (serial >= grab->serial_start && serial < grab->serial_end)
1102         return l;
1103     }
1104   
1105   return NULL;
1106 }
1107
1108
1109
1110 GdkPointerGrabInfo *
1111 _gdk_display_has_pointer_grab (GdkDisplay *display,
1112                                gulong serial)
1113 {
1114   GList *l;
1115
1116   l = find_pointer_grab (display, serial);
1117   if (l)
1118     return l->data;
1119   
1120   return NULL;
1121 }
1122
1123 /* Returns true if last grab was ended
1124  * If if_child is non-NULL, end the grab only if the grabbed
1125  * window is the same as if_child or a descendant of it */
1126 gboolean
1127 _gdk_display_end_pointer_grab (GdkDisplay *display,
1128                                gulong serial,
1129                                GdkWindow *if_child,
1130                                gboolean implicit)
1131 {
1132   GdkPointerGrabInfo *grab;
1133   GList *l;
1134
1135   l = find_pointer_grab (display, serial);
1136   
1137   if (l == NULL)
1138     return FALSE;
1139
1140   grab = l->data;
1141   if (grab &&
1142       (if_child == NULL ||
1143        _gdk_window_event_parent_of (if_child, grab->window)))
1144     {
1145       grab->serial_end = serial;
1146       grab->implicit_ungrab = implicit;
1147       return l->next == NULL;
1148     }
1149   
1150   return FALSE;
1151 }
1152
1153 void
1154 _gdk_display_set_has_keyboard_grab (GdkDisplay *display,
1155                                     GdkWindow *window,
1156                                     GdkWindow *native_window,
1157                                     gboolean owner_events,
1158                                     unsigned long serial,
1159                                     guint32 time)
1160 {
1161   if (display->keyboard_grab.window != NULL &&
1162       display->keyboard_grab.window != window)
1163     generate_grab_broken_event (display->keyboard_grab.window,
1164                                 TRUE, FALSE, window);
1165   
1166   display->keyboard_grab.window = window;
1167   display->keyboard_grab.native_window = native_window;
1168   display->keyboard_grab.owner_events = owner_events;
1169   display->keyboard_grab.serial = serial;
1170   display->keyboard_grab.time = time;      
1171 }
1172
1173 void
1174 _gdk_display_unset_has_keyboard_grab (GdkDisplay *display,
1175                                       gboolean implicit)
1176 {
1177   if (implicit)
1178     generate_grab_broken_event (display->keyboard_grab.window,
1179                                 TRUE, FALSE, NULL);
1180   display->keyboard_grab.window = NULL;  
1181 }
1182
1183 /**
1184  * gdk_keyboard_grab_info_libgtk_only:
1185  * @display: the display for which to get the grab information
1186  * @grab_window: location to store current grab window
1187  * @owner_events: location to store boolean indicating whether
1188  *   the @owner_events flag to gdk_keyboard_grab() was %TRUE.
1189  * 
1190  * Determines information about the current keyboard grab.
1191  * This is not public API and must not be used by applications.
1192  * 
1193  * Return value: %TRUE if this application currently has the
1194  *  keyboard grabbed.
1195  **/
1196 gboolean
1197 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
1198                                     GdkWindow **grab_window,
1199                                     gboolean   *owner_events)
1200 {
1201   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
1202
1203   if (display->keyboard_grab.window)
1204     {
1205       if (grab_window)
1206         *grab_window = display->keyboard_grab.window;
1207       if (owner_events)
1208         *owner_events = display->keyboard_grab.owner_events;
1209
1210       return TRUE;
1211     }
1212   else
1213     return FALSE;
1214 }
1215
1216 /**
1217  * gdk_pointer_grab_info_libgtk_only:
1218  * @display: the #GdkDisplay for which to get the grab information
1219  * @grab_window: location to store current grab window
1220  * @owner_events: location to store boolean indicating whether
1221  *   the @owner_events flag to gdk_pointer_grab() was %TRUE.
1222  * 
1223  * Determines information about the current pointer grab.
1224  * This is not public API and must not be used by applications.
1225  * 
1226  * Return value: %TRUE if this application currently has the
1227  *  pointer grabbed.
1228  **/
1229 gboolean
1230 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
1231                                    GdkWindow **grab_window,
1232                                    gboolean   *owner_events)
1233 {
1234   GdkPointerGrabInfo *info;
1235   
1236   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
1237
1238   /* What we're interested in is the steady state (ie last grab),
1239      because we're interested e.g. if we grabbed so that we
1240      can ungrab, even if our grab is not active just yet. */
1241   info = _gdk_display_get_last_pointer_grab (display);
1242   
1243   if (info)
1244     {
1245       if (grab_window)
1246         *grab_window = info->window;
1247       if (owner_events)
1248         *owner_events = info->owner_events;
1249
1250       return TRUE;
1251     }
1252   else
1253     return FALSE;
1254 }
1255
1256
1257 /**
1258  * gdk_display_pointer_is_grabbed:
1259  * @display: a #GdkDisplay
1260  *
1261  * Test if the pointer is grabbed.
1262  *
1263  * Returns: %TRUE if an active X pointer grab is in effect
1264  *
1265  * Since: 2.2
1266  */
1267 gboolean
1268 gdk_display_pointer_is_grabbed (GdkDisplay *display)
1269 {
1270   GdkPointerGrabInfo *info;
1271   
1272   g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
1273
1274   /* What we're interested in is the steady state (ie last grab),
1275      because we're interested e.g. if we grabbed so that we
1276      can ungrab, even if our grab is not active just yet. */
1277   info = _gdk_display_get_last_pointer_grab (display);
1278   
1279   return (info && !info->implicit);
1280 }
1281
1282 #define __GDK_DISPLAY_C__
1283 #include "gdkaliasdef.c"