gdkdisplay.c 48.6 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->surface_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->surface_under_pointer);
332
  g_slice_free (GdkPointerSurfaceInfo, info);
333
334
335
336
337
}

static void
free_device_grab (GdkDeviceGrabInfo *info)
{
338
  g_object_unref (info->surface);
339
340
341
342
343
344
345
346
347
348
  g_free (info);
}

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

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

  return TRUE;
}

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

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

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

365
366
  g_queue_init (&display->queued_events);

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

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

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

378
379
  _gdk_display_manager_remove_display (gdk_display_manager_get (), display);

380
  g_queue_clear (&display->queued_events);
381

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

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

  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);

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

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

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

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

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

  return display->closed;
}

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

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

  return _gdk_event_unqueue (display);
460
461
462
463
}

/**
 * gdk_display_peek_event:
Alexander Larsson's avatar
Alexander Larsson committed
464
 * @display: a #GdkDisplay 
465
 * 
466
 * Gets a copy of the first #GdkEvent in the @display’s event queue, without
467
468
469
470
 * 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.)
 * 
471
472
 * Returns: (nullable) (transfer full): the first #GdkEvent on the
 *   event queue
473
 **/
474
GdkEvent *
475
476
477
478
479
480
481
482
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);
  
483
  if (tmp_list != NULL)
484
    return g_object_ref (tmp_list->data);
485
486

  return NULL;
487
488
}

Matthias Clasen's avatar
Matthias Clasen committed
489
490
491
492
493
494
495
static void
gdk_display_put_event_nocopy (GdkDisplay *display,
                              GdkEvent   *event)
{
  _gdk_event_queue_append (display, event);
}

496
497
498
499
500
501
502
503
504
/**
 * 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
505
506
gdk_display_put_event (GdkDisplay     *display,
		       const GdkEvent *event)
507
508
509
510
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
  g_return_if_fail (event != NULL);

Matthias Clasen's avatar
Matthias Clasen committed
511
  gdk_display_put_event_nocopy (display, gdk_event_copy (event));
512
}
513

514
static void
Matthias Clasen's avatar
Matthias Clasen committed
515
generate_grab_broken_event (GdkDisplay *display,
516
                            GdkSurface  *surface,
Matthias Clasen's avatar
Matthias Clasen committed
517
518
                            GdkDevice  *device,
			    gboolean    implicit,
519
			    GdkSurface  *grab_surface)
520
{
521
  g_return_if_fail (surface != NULL);
522

523
  if (!GDK_SURFACE_DESTROYED (surface))
524
    {
525
526
527
      GdkEvent *event;

      event = gdk_event_new (GDK_GRAB_BROKEN);
528
      event->any.surface = g_object_ref (surface);
529
      event->any.send_event = FALSE;
530
      event->grab_broken.implicit = implicit;
531
      event->grab_broken.grab_surface = grab_surface;
532
      gdk_event_set_device (event, device);
533
      event->grab_broken.keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) ? TRUE : FALSE;
534

Matthias Clasen's avatar
Matthias Clasen committed
535
      gdk_display_put_event_nocopy (display, event);
536
537
538
    }
}

539
540
541
GdkDeviceGrabInfo *
_gdk_display_get_last_device_grab (GdkDisplay *display,
                                   GdkDevice  *device)
542
543
544
{
  GList *l;

545
  l = g_hash_table_lookup (display->device_grabs, device);
546

547
548
549
550
551
  if (l)
    {
      l = g_list_last (l);
      return l->data;
    }
552

553
554
  return NULL;
}
555

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

570
  info = g_new0 (GdkDeviceGrabInfo, 1);
571

572
  info->surface = g_object_ref (surface);
573
574
575
576
577
578
  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;
579
580
581
  info->ownership = grab_ownership;

  grabs = g_hash_table_lookup (display->device_grabs, device);
582
583
584
585

  /* 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 */
586
  for (l = grabs; l != NULL; l = l->next)
587
    {
588
      other_info = l->data;
589

590
591
592
      if (info->serial_start < other_info->serial_start)
	break;
    }
593
594

  grabs = g_list_insert_before (grabs, l, info);
595
596
597
598
599
600

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

603
  /* Find any previous grab and update its end time */
604
  l = g_list_find (grabs, info);
605
606
  l = l->prev;
  if (l)
607
    {
608
609
610
611
      other_info = l->data;
      other_info->serial_end = serial_start;
    }

612
  g_hash_table_insert (display->device_grabs, device, grabs);
613

614
  return info;
615
616
}

617
static GdkSurface *
618
619
620
621
get_current_toplevel (GdkDisplay      *display,
                      GdkDevice       *device,
                      int             *x_out,
                      int             *y_out,
622
623
		      GdkModifierType *state_out)
{
624
  GdkSurface *pointer_surface;
625
  gdouble x, y;
626
627
  GdkModifierType state;

628
  pointer_surface = _gdk_device_surface_at_position (device, &x, &y, &state, TRUE);
629

630
  if (pointer_surface != NULL &&
631
      GDK_SURFACE_DESTROYED (pointer_surface))
632
    pointer_surface = NULL;
633

634
635
  *x_out = round (x);
  *y_out = round (y);
636
  *state_out = state;
637

638
  return pointer_surface;
639
640
}

641
static void
642
643
switch_to_pointer_grab (GdkDisplay        *display,
                        GdkDevice         *device,
644
                        GdkDevice         *source_device,
645
646
647
648
			GdkDeviceGrabInfo *grab,
			GdkDeviceGrabInfo *last_grab,
			guint32            time,
			gulong             serial)
649
{
650
651
  GdkSurface *new_toplevel;
  GdkPointerSurfaceInfo *info;
652
653
  GList *old_grabs;
  GdkModifierType state;
654
  int x = 0, y = 0;
655
656

  /* Temporarily unset pointer to make sure we send the crossing events below */
657
658
659
660
  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);

661
662
663
664
  if (grab)
    {
      /* New grab is in effect */
      if (!grab->implicit)
665
	{
666
667
668
	  /* !owner_event Grabbing a surface that we're not inside, current status is
	     now NULL (i.e. outside grabbed surface) */
	  if (!grab->owner_events && info->surface_under_pointer != grab->surface)
669
	    _gdk_display_set_surface_under_pointer (display, device, NULL);
670
	}
671

672
673
      grab->activated = TRUE;
    }
674
675

  if (last_grab)
676
    {
677
678
679
680
681
      new_toplevel = NULL;

      if (grab == NULL /* ungrab */ ||
	  (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
	{
682
683
684
685
686
687
688
689
          /* 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);

690
691
692
	  if (new_toplevel)
	    {
	      /* w is now toplevel and x,y in toplevel coords */
693
              _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
694
695
696
	      info->toplevel_x = x;
	      info->toplevel_y = y;
	      info->state = state;
697
698
699
700
	    }
	}

      if (grab == NULL) /* Ungrabbed, send events */
701
	{
702
703
	  /* We're now ungrabbed, update the surface_under_pointer */
	  _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
704
	}
705
706
    }

707
  g_hash_table_insert (display->device_grabs, device, old_grabs);
708
709
}

710
711
712
713
714
715
716
717
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);
}

718
void
719
720
_gdk_display_device_grab_update (GdkDisplay *display,
                                 GdkDevice  *device,
721
                                 GdkDevice  *source_device,
722
                                 gulong      current_serial)
723
{
724
725
  GdkDeviceGrabInfo *current_grab, *next_grab;
  GList *grabs;
726
  guint32 time;
727

728
  time = display->last_event_time;
729
  grabs = g_hash_table_lookup (display->device_grabs, device);
730

731
  while (grabs != NULL)
732
    {
733
      current_grab = grabs->data;
734

735
736
      if (current_grab->serial_start > current_serial)
	return; /* Hasn't started yet */
737

738
      if (current_grab->serial_end > current_serial)
739
740
741
	{
	  /* This one hasn't ended yet.
	     its the currently active one or scheduled to be active */
742

743
	  if (!current_grab->activated)
744
            {
745
              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
746
                switch_to_pointer_grab (display, device, source_device, current_grab, NULL, time, current_serial);
747
748
            }

749
750
751
752
	  break;
	}

      next_grab = NULL;
753
      if (grabs->next)
754
	{
755
	  /* This is the next active grab */
756
757
	  next_grab = grabs->next->data;

758
759
	  if (next_grab->serial_start > current_serial)
	    next_grab = NULL; /* Actually its not yet active */
760
761
	}

762
      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
763
764
          (next_grab != NULL && current_grab->surface != next_grab->surface))
        generate_grab_broken_event (display, GDK_SURFACE (current_grab->surface),
765
                                    device,
766
                                    current_grab->implicit,
767
                                    next_grab? next_grab->surface : NULL);
768

769
      /* Remove old grab */
770
771
772
      grabs = g_list_delete_link (grabs, grabs);
      g_hash_table_insert (display->device_grabs, device, grabs);

773
      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
774
        switch_to_pointer_grab (display, device, source_device,
775
776
777
778
                                next_grab, current_grab,
                                time, current_serial);

      free_device_grab (current_grab);
779
    }
780
781
782
}

static GList *
783
784
grab_list_find (GList  *grabs,
                gulong  serial)
785
{
786
  GdkDeviceGrabInfo *grab;
787

788
  while (grabs)
789
    {
790
      grab = grabs->data;
791

792
      if (serial >= grab->serial_start && serial < grab->serial_end)
793
794
795
	return grabs;

      grabs = grabs->next;
796
    }
797

798
799
800
  return NULL;
}

801
802
803
804
805
806
static GList *
find_device_grab (GdkDisplay *display,
                   GdkDevice  *device,
                   gulong      serial)
{
  GList *l;
807

808
809
810
  l = g_hash_table_lookup (display->device_grabs, device);
  return grab_list_find (l, serial);
}
811

812
813
814
815
GdkDeviceGrabInfo *
_gdk_display_has_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial)
816
817
818
{
  GList *l;

819
  l = find_device_grab (display, device, serial);
820
821
  if (l)
    return l->data;
822

823
824
825
  return NULL;
}

826
827
/* Returns true if last grab was ended
 * If if_child is non-NULL, end the grab only if the grabbed
828
 * surface is the same as if_child or a descendant of it */
829
gboolean
830
831
832
_gdk_display_end_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial,
833
                              GdkSurface  *if_child,
834
                              gboolean    implicit)
835
{
836
  GdkDeviceGrabInfo *grab;
837
838
  GList *l;

839
840
  l = find_device_grab (display, device, serial);

841
842
843
844
  if (l == NULL)
    return FALSE;

  grab = l->data;
845
  if (grab && (if_child == NULL || if_child == grab->surface))
846
847
848
849
850
851
852
    {
      grab->serial_end = serial;
      grab->implicit_ungrab = implicit;
      return l->next == NULL;
    }
  
  return FALSE;
853
854
}

855
856
857
858
859
860
861
862
863
864
865
866
867
/* 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;
868
  device_is_keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD);
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883

  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 */
884
885
      if ((device_is_keyboard && gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD) ||
          (!device_is_keyboard && gdk_device_get_source (dev) == GDK_SOURCE_KEYBOARD))
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
        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;
908
909
}

910
GdkPointerSurfaceInfo *
911
912
_gdk_display_get_pointer_info (GdkDisplay *display,
                               GdkDevice  *device)
913
{
914
  GdkPointerSurfaceInfo *info;
915

916
917
918
  if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
    device = gdk_device_get_associated_device (device);

919
920
921
922
923
924
925
  if (G_UNLIKELY (!device))
    return NULL;

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

  if (G_UNLIKELY (!info))
    {
926
      info = g_slice_new0 (GdkPointerSurfaceInfo);
927
928
929
930
      g_hash_table_insert (display->pointers_info, device, info);
    }

  return info;
931
932
}

933
934
935
936
void
_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
                                   GdkDisplayPointerInfoForeach  func,
                                   gpointer                      user_data)
937
{
938
939
  GHashTableIter iter;
  gpointer key, value;
940

941
942
943
  g_hash_table_iter_init (&iter, display->pointers_info);

  while (g_hash_table_iter_next (&iter, &key, &value))
944
    {
945
      GdkPointerSurfaceInfo *info = value;
946
      GdkDevice *device = key;
947

948
      (func) (display, device, info, user_data);
949
950
    }
}
951

952
953
/*< private >
 * gdk_device_grab_info:
954
955
 * @display: the display for which to get the grab information
 * @device: device to get the grab information from
956
 * @grab_surface: (out) (transfer none): location to store current grab surface
957
 * @owner_events: (out): location to store boolean indicating whether
958
 *   the @owner_events flag to gdk_device_grab() was %TRUE.
959
960
 *
 * Determines information about the current keyboard grab.
961
 * This is not public API and must not be used by applications.
962
 *
963
 * Returns: %TRUE if this application currently has the
964
 *  keyboard grabbed.
965
 */
966
gboolean
967
968
gdk_device_grab_info (GdkDisplay  *display,
                      GdkDevice   *device,
969
                      GdkSurface  **grab_surface,
970
                      gboolean    *owner_events)
971
{
972
973
  GdkDeviceGrabInfo *info;

974
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
975
976
977
  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);

  info = _gdk_display_get_last_device_grab (display, device);
978

979
  if (info)
980
    {
981
982
      if (grab_surface)
        *grab_surface = info->surface;
983
      if (owner_events)
984
        *owner_events = info->owner_events;
985
986
987
988
989
990
991

      return TRUE;
    }
  else
    return FALSE;
}

992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
/**
 * gdk_display_device_is_grabbed:
 * @display: a #GdkDisplay
 * @device: a #GdkDevice
 *
 * Returns %TRUE if there is an ongoing grab on @device for @display.
 *
 * Returns: %TRUE if there is a grab in effect for @device.
 **/
gboolean
gdk_display_device_is_grabbed (GdkDisplay *display,
                               GdkDevice  *device)
{
  GdkDeviceGrabInfo *info;

1007
  g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
1008
  g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
1009

1010
1011
1012
  /* What we're interested in is the steady state (ie last grab),
     because we're interested e.g. if we grabbed so that we
     can ungrab, even if our grab is not active just yet. */
1013
1014
  info = _gdk_display_get_last_device_grab (display, device);

1015
  return (info && !info->implicit);
1016
1017
}

1018
1019
1020
1021
1022
1023
1024
1025
1026
/**
 * gdk_display_get_name:
 * @display: a #GdkDisplay
 *
 * Gets the name of the display.
 *
 * Returns: a string representing the display name. This string is owned
 * by GDK and should not be modified or freed.
 */
1027
const gchar *
1028
1029
gdk_display_get_name (GdkDisplay *display)
{
1030
1031
1032
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_name (display);
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
}

/**
 * gdk_display_beep:
 * @display: a #GdkDisplay
 *
 * Emits a short beep on @display
 */
void
gdk_display_beep (GdkDisplay *display)
{
1044
1045
1046
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->beep (display);
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
}

/**
 * gdk_display_sync:
 * @display: a #GdkDisplay
 *
 * Flushes any requests queued for the windowing system and waits until all
 * requests have been handled. This is often used for making sure that the
 * display is synchronized with the current state of the program. Calling
 * gdk_display_sync() before gdk_error_trap_pop() makes sure that any errors
 * generated from earlier requests are handled before the error trap is
 * removed.
 *
 * This is most useful for X11. On windowing systems where requests are
 * handled synchronously, this function will do nothing.
 */
void
gdk_display_sync (GdkDisplay *display)
{
1066
1067
1068
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->sync (display);
1069
1070
1071
1072
1073
1074
1075
1076
1077
}

/**
 * gdk_display_flush:
 * @display: a #GdkDisplay
 *
 * Flushes any requests queued for the windowing system; this happens automatically
 * when the main loop blocks waiting for new events, but if your application
 * is drawing without returning control to the main loop, you may need
1078
 * to call this function explicitly. A common case where this function
1079
1080
1081
1082
1083
1084
1085
1086
1087
 * needs to be called is when an application is executing drawing commands
 * from a thread other than the thread where the main loop is running.
 *
 * This is most useful for X11. On windowing systems where requests are
 * handled synchronously, this function will do nothing.
 */
void
gdk_display_flush (GdkDisplay *display)
{
1088
1089
1090
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->flush (display);
1091
1092
1093
1094
1095
1096
}

/**
 * gdk_display_get_default_group:
 * @display: a #GdkDisplay
 *
1097
1098
 * Returns the default group leader surface for all toplevel surfaces
 * on @display. This surface is implicitly created by GDK.
1099
 * See gdk_surface_set_group().
1100
 *
1101
 * Returns: (transfer none): The default group leader surface
1102
1103
 * for @display
 **/
1104
GdkSurface *
1105
1106
gdk_display_get_default_group (GdkDisplay *display)
{
1107
1108
1109
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_default_group (display);
1110
1111
}

1112
1113
1114
1115
1116
1117
/**
 * gdk_display_get_clipboard:
 * @display: a #GdkDisplay
 *
 * Gets the clipboard used for copy/paste operations.
 *
1118
1119
 * Returns: (transfer none): the display's clipboard
 */