gdkdisplay.c 48.7 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GDK - The GIMP Drawing Kit
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 * gdkdisplay.c
 * 
 * Copyright 2001 Sun Microsystems Inc. 
 *
 * Erwann Chenede <erwann.chenede@sun.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
Javier Jardón's avatar
Javier Jardón committed
19
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20
21
 */

22
#include "config.h"
23

24
#include "gdkdisplay.h"
25
#include "gdkdisplayprivate.h"
26

27
#include "gdkintl.h"
28
29
#include "gdk-private.h"

30
#include "gdkclipboardprivate.h"
31
#include "gdkdeviceprivate.h"
32
#include "gdkdisplaymanagerprivate.h"
33
#include "gdkevents.h"
34
#include "gdksurfaceimpl.h"
35
#include "gdkinternals.h"
36
#include "gdkmonitorprivate.h"
37

38
#include <math.h>
39
#include <glib.h>
40

41
42
/* for the use of round() */
#include "fallback-c89.c"
43
44
45

/**
 * SECTION:gdkdisplay
46
 * @Short_description: Controls a set of monitors and their associated input devices
47
48
 * @Title: GdkDisplay
 *
49
 * GdkDisplay objects are the GDK representation of a workstation.
Matthias Clasen's avatar
Matthias Clasen committed
50
 *
51
52
53
 * Their purpose are two-fold:
 * - To manage and provide information about input devices (pointers, keyboards, etc)
 * - To manage and provide information about output devices (monitors, projectors, etc)
Matthias Clasen's avatar
Matthias Clasen committed
54
 *
55
56
57
58
59
 * Most of the input device handling has been factored out into separate #GdkSeat
 * objects. Every display has a one or more seats, which can be accessed with
 * gdk_display_get_default_seat() and gdk_display_list_seats().
 *
 * Output devices are represented by #GdkMonitor objects, which can be accessed
60
 * with gdk_display_get_monitor() and similar APIs.
61
62
 */

Matthias Clasen's avatar
Matthias Clasen committed
63
64
65
/**
 * GdkDisplay:
 *
66
 * The GdkDisplay struct contains only private fields and should not
Matthias Clasen's avatar
Matthias Clasen committed
67
68
 * be accessed directly.
 */
69
70
71
72
73
74
75
76
77
enum
{
  PROP_0,
  PROP_COMPOSITED,
  PROP_RGBA,
  LAST_PROP
};

static GParamSpec *props[LAST_PROP] = { NULL, };
78

79
enum {
80
  OPENED,
81
  CLOSED,
82
83
  SEAT_ADDED,
  SEAT_REMOVED,
84
85
  MONITOR_ADDED,
  MONITOR_REMOVED,
86
  SETTING_CHANGED,
87
88
89
  LAST_SIGNAL
};

90
91
static void gdk_display_dispose     (GObject         *object);
static void gdk_display_finalize    (GObject         *object);
Matthias Clasen's avatar
Matthias Clasen committed
92
93
static void gdk_display_put_event_nocopy (GdkDisplay *display,
                                          GdkEvent   *event);
94

95

96
static GdkAppLaunchContext *gdk_display_real_get_app_launch_context (GdkDisplay *display);
97

98
99
static guint signals[LAST_SIGNAL] = { 0 };

Matthias Clasen's avatar
Matthias Clasen committed
100
G_DEFINE_TYPE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
101

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
static void
gdk_display_get_property (GObject    *object,
                          guint       prop_id,
                          GValue     *value,
                          GParamSpec *pspec)
{
  GdkDisplay *display = GDK_DISPLAY (object);

  switch (prop_id)
    {
    case PROP_COMPOSITED:
      g_value_set_boolean (value, gdk_display_is_composited (display));
      break;

    case PROP_RGBA:
      g_value_set_boolean (value, gdk_display_is_rgba (display));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

125
126
127
128
129
static void
gdk_display_real_make_default (GdkDisplay *display)
{
}

130
131
132
static void
gdk_display_real_opened (GdkDisplay *display)
{
133
  _gdk_display_manager_add_display (gdk_display_manager_get (), display);
134
135
}

136
137
138
139
140
141
142
143
144
145
146
147
148
static void
gdk_display_real_event_data_copy (GdkDisplay     *display,
                                  const GdkEvent *src,
                                  GdkEvent       *dst)
{
}

static void
gdk_display_real_event_data_free (GdkDisplay     *display,
                                  GdkEvent       *dst)
{
}

149
150
151
152
153
154
155
156
157
static GdkSeat *
gdk_display_real_get_default_seat (GdkDisplay *display)
{
  if (!display->seats)
    return NULL;

  return display->seats->data;
}

158
159
160
161
162
163
static GdkMonitor *
gdk_display_real_get_primary_monitor (GdkDisplay *display)
{
  return gdk_display_get_monitor (display, 0);
}

164
165
166
167
static void
gdk_display_class_init (GdkDisplayClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
168

169
  object_class->finalize = gdk_display_finalize;
170
  object_class->dispose = gdk_display_dispose;
171
  object_class->get_property = gdk_display_get_property;
172

173
  class->get_app_launch_context = gdk_display_real_get_app_launch_context;
174
  class->window_type = GDK_TYPE_SURFACE;
175

176
  class->opened = gdk_display_real_opened;
177
  class->make_default = gdk_display_real_make_default;
178
179
  class->event_data_copy = gdk_display_real_event_data_copy;
  class->event_data_free = gdk_display_real_event_data_free;
180
  class->get_default_seat = gdk_display_real_get_default_seat;
181

182
183
  class->get_primary_monitor = gdk_display_real_get_primary_monitor;

184
185
186
187
188
189
190
191
192
193
194
  /**
   * GdkDisplay:composited:
   *
   * %TRUE if the display properly composits the alpha channel.
   * See gdk_display_is_composited() for details.
   */
  props[PROP_COMPOSITED] =
    g_param_spec_boolean ("composited",
                          P_("Composited"),
                          P_("Composited"),
                          TRUE,
195
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
196
197
198
199
200
201
202
203
204
205
206
207

  /**
   * GdkDisplay:rgba:
   *
   * %TRUE if the display supports an alpha channel. See gdk_display_is_rgba()
   * for details.
   */
  props[PROP_RGBA] =
    g_param_spec_boolean ("rgba",
                          P_("RGBA"),
                          P_("RGBA"),
                          TRUE,
208
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
209
210
211

  g_object_class_install_properties (object_class, LAST_PROP, props);

212
  /**
Matthias Clasen's avatar
Matthias Clasen committed
213
   * GdkDisplay::opened:
214
215
   * @display: the object on which the signal is emitted
   *
Matthias Clasen's avatar
Matthias Clasen committed
216
217
   * The ::opened signal is emitted when the connection to the windowing
   * system for @display is opened.
218
219
220
221
222
   */
  signals[OPENED] =
    g_signal_new (g_intern_static_string ("opened"),
		  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST,
223
224
		  G_STRUCT_OFFSET (GdkDisplayClass, opened),
                  NULL, NULL,
225
226
227
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);

228
229
230
231
232
233
234
235
  /**
   * GdkDisplay::closed:
   * @display: the object on which the signal is emitted
   * @is_error: %TRUE if the display was closed due to an error
   *
   * The ::closed signal is emitted when the connection to the windowing
   * system for @display is closed.
   */   
236
  signals[CLOSED] =
Matthias Clasen's avatar
Matthias Clasen committed
237
    g_signal_new (g_intern_static_string ("closed"),
238
239
240
241
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkDisplayClass, closed),
		  NULL, NULL,
Benjamin Otte's avatar
Benjamin Otte committed
242
                  g_cclosure_marshal_VOID__BOOLEAN,
243
244
245
		  G_TYPE_NONE,
		  1,
		  G_TYPE_BOOLEAN);
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265

  /**
   * GdkDisplay::seat-added:
   * @display: the object on which the signal is emitted
   * @seat: the seat that was just added
   *
   * The ::seat-added signal is emitted whenever a new seat is made
   * known to the windowing system.
   */
  signals[SEAT_ADDED] =
    g_signal_new (g_intern_static_string ("seat-added"),
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL,
                  g_cclosure_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, GDK_TYPE_SEAT);

  /**
   * GdkDisplay::seat-removed:
   * @display: the object on which the signal is emitted
Matthias Clasen's avatar
Matthias Clasen committed
266
   * @seat: the seat that was just removed
267
268
269
270
271
272
273
274
275
276
277
   *
   * The ::seat-removed signal is emitted whenever a seat is removed
   * by the windowing system.
   */
  signals[SEAT_REMOVED] =
    g_signal_new (g_intern_static_string ("seat-removed"),
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL,
                  g_cclosure_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, GDK_TYPE_SEAT);
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309

  /**
   * GdkDisplay::monitor-added:
   * @display: the objedct on which the signal is emitted
   * @monitor: the monitor that was just added
   *
   * The ::monitor-added signal is emitted whenever a monitor is
   * added.
   */
  signals[MONITOR_ADDED] =
    g_signal_new (g_intern_static_string ("monitor-added"),
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL,
                  g_cclosure_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, GDK_TYPE_MONITOR);

  /**
   * GdkDisplay::monitor-removed:
   * @display: the object on which the signal is emitted
   * @monitor: the monitor that was just removed
   *
   * The ::monitor-removed signal is emitted whenever a monitor is
   * removed.
   */
  signals[MONITOR_REMOVED] =
    g_signal_new (g_intern_static_string ("monitor-removed"),
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL,
                  g_cclosure_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1, GDK_TYPE_MONITOR);
310

311
312
313
314
315
316
317
318
  /**
   * GdkDisplay::setting-changed:
   * @display: the object on which the signal is emitted
   * @setting: the name of the setting that changed
   *
   * The ::setting-changed signal is emitted whenever a setting
   * changes its value.
   */
319
320
321
322
323
324
325
  signals[SETTING_CHANGED] =
    g_signal_new (g_intern_static_string ("setting-changed"),
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL,
                  NULL,
		  G_TYPE_NONE, 1, G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
326
327
}

328
static void
329
free_pointer_info (GdkPointerSurfaceInfo *info)
330
{
331
  g_clear_object (&info->window_under_pointer);
332
  g_slice_free (GdkPointerSurfaceInfo, info);
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
}

static void
free_device_grab (GdkDeviceGrabInfo *info)
{
  g_object_unref (info->window);
  g_object_unref (info->native_window);
  g_free (info);
}

static gboolean
free_device_grabs_foreach (gpointer key,
                           gpointer value,
                           gpointer user_data)
{
  GList *list = value;

350
  g_list_free_full (list, (GDestroyNotify) free_device_grab);
351
352
353
354

  return TRUE;
}

355
356
357
358
static void
gdk_display_init (GdkDisplay *display)
{
  display->double_click_time = 250;
359
  display->double_click_distance = 5;
360

361
362
363
364
365
  display->device_grabs = g_hash_table_new (NULL, NULL);

  display->pointers_info = g_hash_table_new_full (NULL, NULL, NULL,
                                                  (GDestroyNotify) free_pointer_info);

Matthias Clasen's avatar
Matthias Clasen committed
366
  display->debug_flags = _gdk_debug_flags;
367
368
369

  display->composited = TRUE;
  display->rgba = TRUE;
370
371
}

372
373
374
static void
gdk_display_dispose (GObject *object)
{
375
  GdkDisplay *display = GDK_DISPLAY (object);
376

377
378
  _gdk_display_manager_remove_display (gdk_display_manager_get (), display);

379
  g_list_free_full (display->queued_events, (GDestroyNotify) gdk_event_free);
380
381
382
  display->queued_events = NULL;
  display->queued_tail = NULL;

Matthias Clasen's avatar
Matthias Clasen committed
383
  G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
384
385
}

386
387
388
static void
gdk_display_finalize (GObject *object)
{
389
  GdkDisplay *display = GDK_DISPLAY (object);
390
391
392
393
394
395
396
397

  g_hash_table_foreach_remove (display->device_grabs,
                               free_device_grabs_foreach,
                               NULL);
  g_hash_table_destroy (display->device_grabs);

  g_hash_table_destroy (display->pointers_info);

398
  g_list_free_full (display->seats, g_object_unref);
399

Matthias Clasen's avatar
Matthias Clasen committed
400
  G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
401
402
403
404
405
406
}

/**
 * gdk_display_close:
 * @display: a #GdkDisplay
 *
407
 * Closes the connection to the windowing system for the given display,
408
 * and cleans up associated resources.
409
410
411
412
413
 */
void
gdk_display_close (GdkDisplay *display)
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
414
415
416
417

  if (!display->closed)
    {
      display->closed = TRUE;
418
419
      
      g_signal_emit (display, signals[CLOSED], 0, FALSE);
420
421
      g_object_run_dispose (G_OBJECT (display));
      
422
      g_object_unref (display);
423
    }
424
425
}

John Stowers's avatar
John Stowers committed
426
427
428
429
/**
 * gdk_display_is_closed:
 * @display: a #GdkDisplay
 *
430
431
432
 * Finds out if the display has been closed.
 *
 * Returns: %TRUE if the display is closed.
John Stowers's avatar
John Stowers committed
433
434
435
436
437
438
439
440
441
 */
gboolean
gdk_display_is_closed  (GdkDisplay  *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

  return display->closed;
}

442
443
444
445
446
447
448
/**
 * gdk_display_get_event:
 * @display: a #GdkDisplay
 * 
 * Gets the next #GdkEvent to be processed for @display, fetching events from the
 * windowing system if necessary.
 * 
449
450
451
452
 * Returns: (nullable) (transfer full): the next #GdkEvent to be processed,
 *   or %NULL if no events are pending
 */
GdkEvent *
453
454
455
gdk_display_get_event (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
456

457
458
  if (display->event_pause_count == 0)
    GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
459
460

  return _gdk_event_unqueue (display);
461
462
463
464
}

/**
 * gdk_display_peek_event:
Alexander Larsson's avatar
Alexander Larsson committed
465
 * @display: a #GdkDisplay 
466
 * 
467
 * Gets a copy of the first #GdkEvent in the @display’s event queue, without
468
469
470
471
 * removing the event from the queue.  (Note that this function will
 * not get more events from the windowing system.  It only checks the events
 * that have already been moved to the GDK event queue.)
 * 
472
473
 * Returns: (nullable) (transfer full): the first #GdkEvent on the
 *   event queue
474
 **/
475
GdkEvent *
476
477
478
479
480
481
482
483
gdk_display_peek_event (GdkDisplay *display)
{
  GList *tmp_list;

  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  tmp_list = _gdk_event_queue_find_first (display);
  
484
  if (tmp_list != NULL)
485
    return g_object_ref (tmp_list->data);
486
487

  return NULL;
488
489
}

Matthias Clasen's avatar
Matthias Clasen committed
490
491
492
493
494
495
496
497
498
static void
gdk_display_put_event_nocopy (GdkDisplay *display,
                              GdkEvent   *event)
{
  _gdk_event_queue_append (display, event);
  /* If the main loop is blocking in a different thread, wake it up */
  g_main_context_wakeup (NULL);
}

499
500
501
502
503
504
505
506
507
/**
 * gdk_display_put_event:
 * @display: a #GdkDisplay
 * @event: a #GdkEvent.
 *
 * Appends a copy of the given event onto the front of the event
 * queue for @display.
 **/
void
508
509
gdk_display_put_event (GdkDisplay     *display,
		       const GdkEvent *event)
510
511
512
513
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
  g_return_if_fail (event != NULL);

Matthias Clasen's avatar
Matthias Clasen committed
514
  gdk_display_put_event_nocopy (display, gdk_event_copy (event));
515
}
516

517
static void
Matthias Clasen's avatar
Matthias Clasen committed
518
generate_grab_broken_event (GdkDisplay *display,
519
                            GdkSurface  *window,
Matthias Clasen's avatar
Matthias Clasen committed
520
521
                            GdkDevice  *device,
			    gboolean    implicit,
522
			    GdkSurface  *grab_window)
523
524
525
{
  g_return_if_fail (window != NULL);

526
  if (!GDK_SURFACE_DESTROYED (window))
527
    {
528
529
530
      GdkEvent *event;

      event = gdk_event_new (GDK_GRAB_BROKEN);
531
532
      event->any.window = g_object_ref (window);
      event->any.send_event = FALSE;
533
534
535
      event->grab_broken.implicit = implicit;
      event->grab_broken.grab_window = grab_window;
      gdk_event_set_device (event, device);
536
      event->grab_broken.keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) ? TRUE : FALSE;
537

Matthias Clasen's avatar
Matthias Clasen committed
538
      gdk_display_put_event_nocopy (display, event);
539
540
541
    }
}

542
543
544
GdkDeviceGrabInfo *
_gdk_display_get_last_device_grab (GdkDisplay *display,
                                   GdkDevice  *device)
545
546
547
{
  GList *l;

548
  l = g_hash_table_lookup (display->device_grabs, device);
549

550
551
552
553
554
  if (l)
    {
      l = g_list_last (l);
      return l->data;
    }
555

556
557
  return NULL;
}
558

559
560
561
GdkDeviceGrabInfo *
_gdk_display_add_device_grab (GdkDisplay       *display,
                              GdkDevice        *device,
562
563
                              GdkSurface        *window,
                              GdkSurface        *native_window,
564
565
566
567
568
569
                              GdkGrabOwnership  grab_ownership,
                              gboolean          owner_events,
                              GdkEventMask      event_mask,
                              unsigned long     serial_start,
                              guint32           time,
                              gboolean          implicit)
570
{
571
572
  GdkDeviceGrabInfo *info, *other_info;
  GList *grabs, *l;
573

574
  info = g_new0 (GdkDeviceGrabInfo, 1);
575
576
577
578
579
580
581
582
583

  info->window = g_object_ref (window);
  info->native_window = g_object_ref (native_window);
  info->serial_start = serial_start;
  info->serial_end = G_MAXULONG;
  info->owner_events = owner_events;
  info->event_mask = event_mask;
  info->time = time;
  info->implicit = implicit;
584
585
586
  info->ownership = grab_ownership;

  grabs = g_hash_table_lookup (display->device_grabs, device);
587
588
589
590

  /* Find the first grab that has a larger start time (if any) and insert
   * before that. I.E we insert after already existing grabs with same
   * start time */
591
  for (l = grabs; l != NULL; l = l->next)
592
    {
593
      other_info = l->data;
594

595
596
597
      if (info->serial_start < other_info->serial_start)
	break;
    }
598
599

  grabs = g_list_insert_before (grabs, l, info);
600
601
602
603
604
605

  /* Make sure the new grab end before next grab */
  if (l)
    {
      other_info = l->data;
      info->serial_end = other_info->serial_start;
606
    }
607

608
  /* Find any previous grab and update its end time */
609
  l = g_list_find (grabs, info);
610
611
  l = l->prev;
  if (l)
612
    {
613
614
615
616
      other_info = l->data;
      other_info->serial_end = serial_start;
    }

617
  g_hash_table_insert (display->device_grabs, device, grabs);
618

619
  return info;
620
621
}

622
static GdkSurface *
623
624
625
626
get_current_toplevel (GdkDisplay      *display,
                      GdkDevice       *device,
                      int             *x_out,
                      int             *y_out,
627
628
		      GdkModifierType *state_out)
{
629
  GdkSurface *pointer_window;
630
  gdouble x, y;
631
632
  GdkModifierType state;

633
  pointer_window = _gdk_device_window_at_position (device, &x, &y, &state, TRUE);
634

635
  if (pointer_window != NULL &&
636
637
638
      (GDK_SURFACE_DESTROYED (pointer_window) ||
       GDK_SURFACE_TYPE (pointer_window) == GDK_SURFACE_ROOT ||
       GDK_SURFACE_TYPE (pointer_window) == GDK_SURFACE_FOREIGN))
639
640
    pointer_window = NULL;

641
642
  *x_out = round (x);
  *y_out = round (y);
643
  *state_out = state;
644

645
  return pointer_window;
646
647
}

648
static void
649
650
switch_to_pointer_grab (GdkDisplay        *display,
                        GdkDevice         *device,
651
                        GdkDevice         *source_device,
652
653
654
655
			GdkDeviceGrabInfo *grab,
			GdkDeviceGrabInfo *last_grab,
			guint32            time,
			gulong             serial)
656
{
657
658
  GdkSurface *new_toplevel;
  GdkPointerSurfaceInfo *info;
659
660
  GList *old_grabs;
  GdkModifierType state;
661
  int x = 0, y = 0;
662
663

  /* Temporarily unset pointer to make sure we send the crossing events below */
664
665
666
667
  old_grabs = g_hash_table_lookup (display->device_grabs, device);
  g_hash_table_steal (display->device_grabs, device);
  info = _gdk_display_get_pointer_info (display, device);

668
669
670
671
  if (grab)
    {
      /* New grab is in effect */
      if (!grab->implicit)
672
	{
673
674
	  /* !owner_event Grabbing a window that we're not inside, current status is
	     now NULL (i.e. outside grabbed window) */
675
676
	  if (!grab->owner_events && info->window_under_pointer != grab->window)
	    _gdk_display_set_window_under_pointer (display, device, NULL);
677
	}
678

679
680
      grab->activated = TRUE;
    }
681
682

  if (last_grab)
683
    {
684
685
686
687
688
      new_toplevel = NULL;

      if (grab == NULL /* ungrab */ ||
	  (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
	{
689
690
691
692
693
694
695
696
          /* Ungrabbed slave devices don't have a position by
           * itself, rather depend on its master pointer, so
           * it doesn't make sense to track any position for
           * these after the grab
           */
          if (grab || gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_SLAVE)
            new_toplevel = get_current_toplevel (display, device, &x, &y, &state);

697
698
699
	  if (new_toplevel)
	    {
	      /* w is now toplevel and x,y in toplevel coords */
700
              _gdk_display_set_window_under_pointer (display, device, new_toplevel);
701
702
703
	      info->toplevel_x = x;
	      info->toplevel_y = y;
	      info->state = state;
704
705
706
707
	    }
	}

      if (grab == NULL) /* Ungrabbed, send events */
708
	{
709
	  /* We're now ungrabbed, update the window_under_pointer */
710
	  _gdk_display_set_window_under_pointer (display, device, new_toplevel);
711
	}
712
713
    }

714
  g_hash_table_insert (display->device_grabs, device, old_grabs);
715
716
}

717
718
719
720
721
722
723
724
void
_gdk_display_update_last_event (GdkDisplay     *display,
                                const GdkEvent *event)
{
  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
    display->last_event_time = gdk_event_get_time (event);
}

725
void
726
727
_gdk_display_device_grab_update (GdkDisplay *display,
                                 GdkDevice  *device,
728
                                 GdkDevice  *source_device,
729
                                 gulong      current_serial)
730
{
731
732
  GdkDeviceGrabInfo *current_grab, *next_grab;
  GList *grabs;
733
  guint32 time;
734

735
  time = display->last_event_time;
736
  grabs = g_hash_table_lookup (display->device_grabs, device);
737

738
  while (grabs != NULL)
739
    {
740
      current_grab = grabs->data;
741

742
743
      if (current_grab->serial_start > current_serial)
	return; /* Hasn't started yet */
744

745
      if (current_grab->serial_end > current_serial)
746
747
748
	{
	  /* This one hasn't ended yet.
	     its the currently active one or scheduled to be active */
749

750
	  if (!current_grab->activated)
751
            {
752
              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
753
                switch_to_pointer_grab (display, device, source_device, current_grab, NULL, time, current_serial);
754
755
            }

756
757
758
759
	  break;
	}

      next_grab = NULL;
760
      if (grabs->next)
761
	{
762
	  /* This is the next active grab */
763
764
	  next_grab = grabs->next->data;

765
766
	  if (next_grab->serial_start > current_serial)
	    next_grab = NULL; /* Actually its not yet active */
767
768
	}

769
      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
770
          (next_grab != NULL && current_grab->window != next_grab->window))
771
        generate_grab_broken_event (display, GDK_SURFACE (current_grab->window),
772
                                    device,
773
774
                                    current_grab->implicit,
                                    next_grab? next_grab->window : NULL);
775

776
      /* Remove old grab */
777
778
779
      grabs = g_list_delete_link (grabs, grabs);
      g_hash_table_insert (display->device_grabs, device, grabs);

780
      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
781
        switch_to_pointer_grab (display, device, source_device,
782
783
784
785
                                next_grab, current_grab,
                                time, current_serial);

      free_device_grab (current_grab);
786
    }
787
788
789
}

static GList *
790
791
grab_list_find (GList  *grabs,
                gulong  serial)
792
{
793
  GdkDeviceGrabInfo *grab;
794

795
  while (grabs)
796
    {
797
      grab = grabs->data;
798

799
      if (serial >= grab->serial_start && serial < grab->serial_end)
800
801
802
	return grabs;

      grabs = grabs->next;
803
    }
804

805
806
807
  return NULL;
}

808
809
810
811
812
813
static GList *
find_device_grab (GdkDisplay *display,
                   GdkDevice  *device,
                   gulong      serial)
{
  GList *l;
814

815
816
817
  l = g_hash_table_lookup (display->device_grabs, device);
  return grab_list_find (l, serial);
}
818

819
820
821
822
GdkDeviceGrabInfo *
_gdk_display_has_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial)
823
824
825
{
  GList *l;

826
  l = find_device_grab (display, device, serial);
827
828
  if (l)
    return l->data;
829

830
831
832
  return NULL;
}

833
834
835
/* Returns true if last grab was ended
 * If if_child is non-NULL, end the grab only if the grabbed
 * window is the same as if_child or a descendant of it */
836
gboolean
837
838
839
_gdk_display_end_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial,
840
                              GdkSurface  *if_child,
841
                              gboolean    implicit)
842
{
843
  GdkDeviceGrabInfo *grab;
844
845
  GList *l;

846
847
  l = find_device_grab (display, device, serial);

848
849
850
851
852
853
  if (l == NULL)
    return FALSE;

  grab = l->data;
  if (grab &&
      (if_child == NULL ||
854
       _gdk_surface_event_parent_of (if_child, grab->window)))
855
856
857
858
859
860
861
    {
      grab->serial_end = serial;
      grab->implicit_ungrab = implicit;
      return l->next == NULL;
    }
  
  return FALSE;
862
863
}

864
865
866
867
868
869
870
871
872
873
874
875
876
/* Returns TRUE if device events are not blocked by any grab */
gboolean
_gdk_display_check_grab_ownership (GdkDisplay *display,
                                   GdkDevice  *device,
                                   gulong      serial)
{
  GHashTableIter iter;
  gpointer key, value;
  GdkGrabOwnership higher_ownership, device_ownership;
  gboolean device_is_keyboard;

  g_hash_table_iter_init (&iter, display->device_grabs);
  higher_ownership = device_ownership = GDK_OWNERSHIP_NONE;
877
  device_is_keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD);
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892

  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      GdkDeviceGrabInfo *grab;
      GdkDevice *dev;
      GList *grabs;

      dev = key;
      grabs = value;
      grabs = grab_list_find (grabs, serial);

      if (!grabs)
        continue;

      /* Discard device if it's not of the same type */
893
894
      if ((device_is_keyboard && gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD) ||
          (!device_is_keyboard && gdk_device_get_source (dev) == GDK_SOURCE_KEYBOARD))
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
        continue;

      grab = grabs->data;

      if (dev == device)
        device_ownership = grab->ownership;
      else
        {
          if (grab->ownership > higher_ownership)
            higher_ownership = grab->ownership;
        }
    }

  if (higher_ownership > device_ownership)
    {
      /* There's a higher priority ownership
       * going on for other device(s)
       */
      return FALSE;
    }

  return TRUE;
917
918
}

919
GdkPointerSurfaceInfo *
920
921
_gdk_display_get_pointer_info (GdkDisplay *display,
                               GdkDevice  *device)
922
{
923
  GdkPointerSurfaceInfo *info;
924

925
926
927
  if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
    device = gdk_device_get_associated_device (device);

928
929
930
931
932
933
934
  if (G_UNLIKELY (!device))
    return NULL;

  info = g_hash_table_lookup (display->pointers_info, device);

  if (G_UNLIKELY (!info))
    {
935
      info = g_slice_new0 (GdkPointerSurfaceInfo);
936
937
938
939
      g_hash_table_insert (display->pointers_info, device, info);
    }

  return info;
940
941
}

942
943
944
945
void
_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
                                   GdkDisplayPointerInfoForeach  func,
                                   gpointer                      user_data)
946
{
947
948
  GHashTableIter iter;
  gpointer key, value;
949

950
951
952
  g_hash_table_iter_init (&iter, display->pointers_info);

  while (g_hash_table_iter_next (&iter, &key, &value))
953
    {
954
      GdkPointerSurfaceInfo *info = value;
955
      GdkDevice *device = key;
956

957
      (func) (display, device, info, user_data);
958
959
    }
}
960

961
962
/*< private >
 * gdk_device_grab_info:
963
964
 * @display: the display for which to get the grab information
 * @device: device to get the grab information from
965
966
 * @grab_window: (out) (transfer none): location to store current grab window
 * @owner_events: (out): location to store boolean indicating whether
967
 *   the @owner_events flag to gdk_device_grab() was %TRUE.
968
969
 *
 * Determines information about the current keyboard grab.
970
 * This is not public API and must not be used by applications.
971
 *
972
 * Returns: %TRUE if this application currently has the
973
 *  keyboard grabbed.
974
 */
975
gboolean
976
977
gdk_device_grab_info (GdkDisplay  *display,
                      GdkDevice   *device,
978
                      GdkSurface  **grab_window,
979
                      gboolean    *owner_events)
980
{
981
982
  GdkDeviceGrabInfo *info;

983
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
984
985
986
  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);

  info = _gdk_display_get_last_device_grab (display, device);
987

988
  if (info)
989
990
    {
      if (grab_window)
991
        *grab_window = info->window;
992
      if (owner_events)
993
        *owner_events = info->owner_events;
994
995
996
997
998
999
1000

      return TRUE;
    }
  else
    return FALSE;
}