gdkdisplay.c 48.1 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 "gdkinternals.h"
35
#include "gdkmonitorprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
36
#include "gdkframeclockidleprivate.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
92
static void gdk_display_dispose     (GObject         *object);
static void gdk_display_finalize    (GObject         *object);

93

94
static GdkAppLaunchContext *gdk_display_real_get_app_launch_context (GdkDisplay *display);
95

96
97
static guint signals[LAST_SIGNAL] = { 0 };

Matthias Clasen's avatar
Matthias Clasen committed
98
G_DEFINE_TYPE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
99

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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);
    }
}

123
124
125
126
127
static void
gdk_display_real_make_default (GdkDisplay *display)
{
}

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

134
135
static void
gdk_display_real_event_data_copy (GdkDisplay     *display,
Matthias Clasen's avatar
Matthias Clasen committed
136
                                  GdkEvent       *src,
137
138
139
140
141
142
143
144
145
146
                                  GdkEvent       *dst)
{
}

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

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

  return display->seats->data;
}

156
157
158
159
static void
gdk_display_class_init (GdkDisplayClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
160

161
  object_class->finalize = gdk_display_finalize;
162
  object_class->dispose = gdk_display_dispose;
163
  object_class->get_property = gdk_display_get_property;
164

165
  class->get_app_launch_context = gdk_display_real_get_app_launch_context;
166
  class->opened = gdk_display_real_opened;
167
  class->make_default = gdk_display_real_make_default;
168
169
  class->event_data_copy = gdk_display_real_event_data_copy;
  class->event_data_free = gdk_display_real_event_data_free;
170
  class->get_default_seat = gdk_display_real_get_default_seat;
171

172
173
174
175
176
177
178
179
180
181
182
  /**
   * 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,
183
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
184
185
186
187
188
189
190
191
192
193
194
195

  /**
   * 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,
196
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
197
198
199

  g_object_class_install_properties (object_class, LAST_PROP, props);

200
  /**
Matthias Clasen's avatar
Matthias Clasen committed
201
   * GdkDisplay::opened:
202
203
   * @display: the object on which the signal is emitted
   *
Matthias Clasen's avatar
Matthias Clasen committed
204
205
   * The ::opened signal is emitted when the connection to the windowing
   * system for @display is opened.
206
207
208
209
210
   */
  signals[OPENED] =
    g_signal_new (g_intern_static_string ("opened"),
		  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST,
211
212
		  G_STRUCT_OFFSET (GdkDisplayClass, opened),
                  NULL, NULL,
213
                  NULL,
214
215
                  G_TYPE_NONE, 0);

216
217
218
219
220
221
222
223
  /**
   * 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.
   */   
224
  signals[CLOSED] =
Matthias Clasen's avatar
Matthias Clasen committed
225
    g_signal_new (g_intern_static_string ("closed"),
226
227
228
229
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkDisplayClass, closed),
		  NULL, NULL,
230
                  NULL,
231
232
233
		  G_TYPE_NONE,
		  1,
		  G_TYPE_BOOLEAN);
234
235
236
237
238
239
240
241
242
243
244
245
246
247

  /**
   * 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,
248
                  NULL,
249
250
251
252
253
		  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
254
   * @seat: the seat that was just removed
255
256
257
258
259
260
261
262
263
   *
   * 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,
264
                  NULL,
265
		  G_TYPE_NONE, 1, GDK_TYPE_SEAT);
266
267
268
269
270
271
272
273
274
275
276
277
278
279

  /**
   * 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,
280
                  NULL,
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
		  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,
296
                  NULL,
297
		  G_TYPE_NONE, 1, GDK_TYPE_MONITOR);
298

299
300
301
302
303
304
305
306
  /**
   * 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.
   */
307
308
309
310
311
312
313
  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);
314
315
}

316
static void
317
free_pointer_info (GdkPointerSurfaceInfo *info)
318
{
319
  g_clear_object (&info->surface_under_pointer);
320
  g_slice_free (GdkPointerSurfaceInfo, info);
321
322
323
324
325
}

static void
free_device_grab (GdkDeviceGrabInfo *info)
{
326
  g_object_unref (info->surface);
327
328
329
330
331
332
333
334
335
336
  g_free (info);
}

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

337
  g_list_free_full (list, (GDestroyNotify) free_device_grab);
338
339
340
341

  return TRUE;
}

342
343
344
345
static void
gdk_display_init (GdkDisplay *display)
{
  display->double_click_time = 250;
346
  display->double_click_distance = 5;
347

348
349
350
351
352
  display->device_grabs = g_hash_table_new (NULL, NULL);

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

353
354
  g_queue_init (&display->queued_events);

Matthias Clasen's avatar
Matthias Clasen committed
355
  display->debug_flags = _gdk_debug_flags;
356
357
358

  display->composited = TRUE;
  display->rgba = TRUE;
359
360
}

361
362
363
static void
gdk_display_dispose (GObject *object)
{
364
  GdkDisplay *display = GDK_DISPLAY (object);
365

366
367
  _gdk_display_manager_remove_display (gdk_display_manager_get (), display);

368
  g_queue_clear (&display->queued_events);
369

Matthias Clasen's avatar
Matthias Clasen committed
370
  G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
371
372
}

373
374
375
static void
gdk_display_finalize (GObject *object)
{
376
  GdkDisplay *display = GDK_DISPLAY (object);
377
378
379
380
381
382
383
384

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

385
  g_list_free_full (display->seats, g_object_unref);
386

Matthias Clasen's avatar
Matthias Clasen committed
387
  G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
388
389
390
391
392
393
}

/**
 * gdk_display_close:
 * @display: a #GdkDisplay
 *
394
 * Closes the connection to the windowing system for the given display,
395
 * and cleans up associated resources.
396
397
398
399
400
 */
void
gdk_display_close (GdkDisplay *display)
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
401
402
403
404

  if (!display->closed)
    {
      display->closed = TRUE;
405
406
      
      g_signal_emit (display, signals[CLOSED], 0, FALSE);
407
408
      g_object_run_dispose (G_OBJECT (display));
      
409
      g_object_unref (display);
410
    }
411
412
}

John Stowers's avatar
John Stowers committed
413
414
415
416
/**
 * gdk_display_is_closed:
 * @display: a #GdkDisplay
 *
417
418
419
 * Finds out if the display has been closed.
 *
 * Returns: %TRUE if the display is closed.
John Stowers's avatar
John Stowers committed
420
421
422
423
424
425
426
427
428
 */
gboolean
gdk_display_is_closed  (GdkDisplay  *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

  return display->closed;
}

429
430
431
432
433
434
435
/**
 * gdk_display_get_event:
 * @display: a #GdkDisplay
 * 
 * Gets the next #GdkEvent to be processed for @display, fetching events from the
 * windowing system if necessary.
 * 
436
437
438
439
 * Returns: (nullable) (transfer full): the next #GdkEvent to be processed,
 *   or %NULL if no events are pending
 */
GdkEvent *
440
441
442
gdk_display_get_event (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
443

444
445
  if (display->event_pause_count == 0)
    GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
446
447

  return _gdk_event_unqueue (display);
448
449
450
451
}

/**
 * gdk_display_peek_event:
Alexander Larsson's avatar
Alexander Larsson committed
452
 * @display: a #GdkDisplay 
453
 * 
454
 * Gets a copy of the first #GdkEvent in the @display’s event queue, without
455
456
457
458
 * 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.)
 * 
459
460
 * Returns: (nullable) (transfer full): the first #GdkEvent on the
 *   event queue
461
 **/
462
GdkEvent *
463
464
465
466
467
468
469
470
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);
  
471
  if (tmp_list != NULL)
472
    return gdk_event_ref (tmp_list->data);
473
474

  return NULL;
475
476
477
478
479
}

/**
 * gdk_display_put_event:
 * @display: a #GdkDisplay
Matthias Clasen's avatar
Matthias Clasen committed
480
 * @event: (transfer none): a #GdkEvent
481
 *
482
 * Appends the given event onto the front of the event
483
484
485
 * queue for @display.
 **/
void
486
gdk_display_put_event (GdkDisplay     *display,
Matthias Clasen's avatar
Matthias Clasen committed
487
		       GdkEvent       *event)
488
489
490
491
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
  g_return_if_fail (event != NULL);

492
  _gdk_event_queue_append (display, gdk_event_ref ((GdkEvent *)event));
493
}
494

495
static void
Matthias Clasen's avatar
Matthias Clasen committed
496
generate_grab_broken_event (GdkDisplay *display,
497
                            GdkSurface  *surface,
Matthias Clasen's avatar
Matthias Clasen committed
498
499
                            GdkDevice  *device,
			    gboolean    implicit,
500
			    GdkSurface  *grab_surface)
501
{
502
  g_return_if_fail (surface != NULL);
503

504
  if (!GDK_SURFACE_DESTROYED (surface))
505
    {
506
507
      GdkEvent *event;

508
      event = gdk_grab_broken_event_new (surface,
509
510
511
512
                                         device,
                                         device,
                                         grab_surface,
                                         implicit);
513

514
      _gdk_event_queue_append (display, event);
515
516
517
    }
}

518
519
520
GdkDeviceGrabInfo *
_gdk_display_get_last_device_grab (GdkDisplay *display,
                                   GdkDevice  *device)
521
522
523
{
  GList *l;

524
  l = g_hash_table_lookup (display->device_grabs, device);
525

526
527
528
529
530
  if (l)
    {
      l = g_list_last (l);
      return l->data;
    }
531

532
533
  return NULL;
}
534

535
536
537
GdkDeviceGrabInfo *
_gdk_display_add_device_grab (GdkDisplay       *display,
                              GdkDevice        *device,
538
                              GdkSurface        *surface,
539
540
541
542
543
544
                              GdkGrabOwnership  grab_ownership,
                              gboolean          owner_events,
                              GdkEventMask      event_mask,
                              unsigned long     serial_start,
                              guint32           time,
                              gboolean          implicit)
545
{
546
547
  GdkDeviceGrabInfo *info, *other_info;
  GList *grabs, *l;
548

549
  info = g_new0 (GdkDeviceGrabInfo, 1);
550

551
  info->surface = g_object_ref (surface);
552
553
554
555
556
557
  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;
558
559
560
  info->ownership = grab_ownership;

  grabs = g_hash_table_lookup (display->device_grabs, device);
561
562
563
564

  /* 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 */
565
  for (l = grabs; l != NULL; l = l->next)
566
    {
567
      other_info = l->data;
568

569
570
571
      if (info->serial_start < other_info->serial_start)
	break;
    }
572
573

  grabs = g_list_insert_before (grabs, l, info);
574
575
576
577
578
579

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

582
  /* Find any previous grab and update its end time */
583
  l = g_list_find (grabs, info);
584
585
  l = l->prev;
  if (l)
586
    {
587
588
589
590
      other_info = l->data;
      other_info->serial_end = serial_start;
    }

591
  g_hash_table_insert (display->device_grabs, device, grabs);
592

593
  return info;
594
595
}

596
static GdkSurface *
597
598
599
600
get_current_toplevel (GdkDisplay      *display,
                      GdkDevice       *device,
                      int             *x_out,
                      int             *y_out,
601
602
		      GdkModifierType *state_out)
{
603
  GdkSurface *pointer_surface;
604
  gdouble x, y;
605
606
  GdkModifierType state;

607
  pointer_surface = _gdk_device_surface_at_position (device, &x, &y, &state, TRUE);
608

609
  if (pointer_surface != NULL &&
610
      GDK_SURFACE_DESTROYED (pointer_surface))
611
    pointer_surface = NULL;
612

613
614
  *x_out = round (x);
  *y_out = round (y);
615
  *state_out = state;
616

617
  return pointer_surface;
618
619
}

620
static void
621
622
switch_to_pointer_grab (GdkDisplay        *display,
                        GdkDevice         *device,
623
                        GdkDevice         *source_device,
624
625
626
627
			GdkDeviceGrabInfo *grab,
			GdkDeviceGrabInfo *last_grab,
			guint32            time,
			gulong             serial)
628
{
629
630
  GdkSurface *new_toplevel;
  GdkPointerSurfaceInfo *info;
631
632
  GList *old_grabs;
  GdkModifierType state;
633
  int x = 0, y = 0;
634
635

  /* Temporarily unset pointer to make sure we send the crossing events below */
636
637
638
639
  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);

640
641
642
643
  if (grab)
    {
      /* New grab is in effect */
      if (!grab->implicit)
644
	{
645
646
647
	  /* !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)
648
	    _gdk_display_set_surface_under_pointer (display, device, NULL);
649
	}
650

651
652
      grab->activated = TRUE;
    }
653
654

  if (last_grab)
655
    {
656
657
658
659
660
      new_toplevel = NULL;

      if (grab == NULL /* ungrab */ ||
	  (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
	{
661
662
663
664
665
666
667
668
          /* 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);

669
670
671
	  if (new_toplevel)
	    {
	      /* w is now toplevel and x,y in toplevel coords */
672
              _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
673
674
675
	      info->toplevel_x = x;
	      info->toplevel_y = y;
	      info->state = state;
676
677
678
679
	    }
	}

      if (grab == NULL) /* Ungrabbed, send events */
680
	{
681
682
	  /* We're now ungrabbed, update the surface_under_pointer */
	  _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
683
	}
684
685
    }

686
  g_hash_table_insert (display->device_grabs, device, old_grabs);
687
688
}

689
690
void
_gdk_display_update_last_event (GdkDisplay     *display,
Matthias Clasen's avatar
Matthias Clasen committed
691
                                GdkEvent       *event)
692
693
694
695
696
{
  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
    display->last_event_time = gdk_event_get_time (event);
}

697
void
698
699
_gdk_display_device_grab_update (GdkDisplay *display,
                                 GdkDevice  *device,
700
                                 GdkDevice  *source_device,
701
                                 gulong      current_serial)
702
{
703
704
  GdkDeviceGrabInfo *current_grab, *next_grab;
  GList *grabs;
705
  guint32 time;
706

707
  time = display->last_event_time;
708
  grabs = g_hash_table_lookup (display->device_grabs, device);
709

710
  while (grabs != NULL)
711
    {
712
      current_grab = grabs->data;
713

714
715
      if (current_grab->serial_start > current_serial)
	return; /* Hasn't started yet */
716

717
      if (current_grab->serial_end > current_serial)
718
719
720
	{
	  /* This one hasn't ended yet.
	     its the currently active one or scheduled to be active */
721

722
	  if (!current_grab->activated)
723
            {
724
              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
725
                switch_to_pointer_grab (display, device, source_device, current_grab, NULL, time, current_serial);
726
727
            }

728
729
730
731
	  break;
	}

      next_grab = NULL;
732
      if (grabs->next)
733
	{
734
	  /* This is the next active grab */
735
736
	  next_grab = grabs->next->data;

737
738
	  if (next_grab->serial_start > current_serial)
	    next_grab = NULL; /* Actually its not yet active */
739
740
	}

741
      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
742
743
          (next_grab != NULL && current_grab->surface != next_grab->surface))
        generate_grab_broken_event (display, GDK_SURFACE (current_grab->surface),
744
                                    device,
745
                                    current_grab->implicit,
746
                                    next_grab? next_grab->surface : NULL);
747

748
      /* Remove old grab */
749
750
751
      grabs = g_list_delete_link (grabs, grabs);
      g_hash_table_insert (display->device_grabs, device, grabs);

752
      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
753
        switch_to_pointer_grab (display, device, source_device,
754
755
756
757
                                next_grab, current_grab,
                                time, current_serial);

      free_device_grab (current_grab);
758
    }
759
760
761
}

static GList *
762
763
grab_list_find (GList  *grabs,
                gulong  serial)
764
{
765
  GdkDeviceGrabInfo *grab;
766

767
  while (grabs)
768
    {
769
      grab = grabs->data;
770

771
      if (serial >= grab->serial_start && serial < grab->serial_end)
772
773
774
	return grabs;

      grabs = grabs->next;
775
    }
776

777
778
779
  return NULL;
}

780
781
782
783
784
785
static GList *
find_device_grab (GdkDisplay *display,
                   GdkDevice  *device,
                   gulong      serial)
{
  GList *l;
786

787
788
789
  l = g_hash_table_lookup (display->device_grabs, device);
  return grab_list_find (l, serial);
}
790

791
792
793
794
GdkDeviceGrabInfo *
_gdk_display_has_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial)
795
796
797
{
  GList *l;

798
  l = find_device_grab (display, device, serial);
799
800
  if (l)
    return l->data;
801

802
803
804
  return NULL;
}

805
806
/* Returns true if last grab was ended
 * If if_child is non-NULL, end the grab only if the grabbed
807
 * surface is the same as if_child or a descendant of it */
808
gboolean
809
810
811
_gdk_display_end_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial,
812
                              GdkSurface  *if_child,
813
                              gboolean    implicit)
814
{
815
  GdkDeviceGrabInfo *grab;
816
817
  GList *l;

818
819
  l = find_device_grab (display, device, serial);

820
821
822
823
  if (l == NULL)
    return FALSE;

  grab = l->data;
824
  if (grab && (if_child == NULL || if_child == grab->surface))
825
826
827
828
829
830
831
    {
      grab->serial_end = serial;
      grab->implicit_ungrab = implicit;
      return l->next == NULL;
    }
  
  return FALSE;
832
833
}

834
835
836
837
838
839
840
841
842
843
844
845
846
/* 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;
847
  device_is_keyboard = (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD);
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862

  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 */
863
864
      if ((device_is_keyboard && gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD) ||
          (!device_is_keyboard && gdk_device_get_source (dev) == GDK_SOURCE_KEYBOARD))
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
        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;
887
888
}

889
GdkPointerSurfaceInfo *
890
891
_gdk_display_get_pointer_info (GdkDisplay *display,
                               GdkDevice  *device)
892
{
893
  GdkPointerSurfaceInfo *info;
894

895
896
897
  if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
    device = gdk_device_get_associated_device (device);

898
899
900
901
902
903
904
  if (G_UNLIKELY (!device))
    return NULL;

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

  if (G_UNLIKELY (!info))
    {
905
      info = g_slice_new0 (GdkPointerSurfaceInfo);
906
907
908
909
      g_hash_table_insert (display->pointers_info, device, info);
    }

  return info;
910
911
}

912
913
914
915
void
_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
                                   GdkDisplayPointerInfoForeach  func,
                                   gpointer                      user_data)
916
{
917
918
  GHashTableIter iter;
  gpointer key, value;
919

920
921
922
  g_hash_table_iter_init (&iter, display->pointers_info);

  while (g_hash_table_iter_next (&iter, &key, &value))
923
    {
924
      GdkPointerSurfaceInfo *info = value;
925
      GdkDevice *device = key;
926

927
      (func) (display, device, info, user_data);
928
929
    }
}
930

931
932
/*< private >
 * gdk_device_grab_info:
933
934
 * @display: the display for which to get the grab information
 * @device: device to get the grab information from
935
 * @grab_surface: (out) (transfer none): location to store current grab surface
936
 * @owner_events: (out): location to store boolean indicating whether
937
 *   the @owner_events flag to gdk_device_grab() was %TRUE.
938
939
 *
 * Determines information about the current keyboard grab.
940
 * This is not public API and must not be used by applications.
941
 *
942
 * Returns: %TRUE if this application currently has the
943
 *  keyboard grabbed.
944
 */
945
gboolean
946
947
gdk_device_grab_info (GdkDisplay  *display,
                      GdkDevice   *device,
948
                      GdkSurface  **grab_surface,
949
                      gboolean    *owner_events)
950
{
951
952
  GdkDeviceGrabInfo *info;

953
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
954
955
956
  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);

  info = _gdk_display_get_last_device_grab (display, device);
957

958
  if (info)
959
    {
960
961
      if (grab_surface)
        *grab_surface = info->surface;
962
      if (owner_events)
963
        *owner_events = info->owner_events;
964
965
966
967
968
969
970

      return TRUE;
    }
  else
    return FALSE;
}

971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
/**
 * 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;

986
  g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
987
  g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
988

989
990
991
  /* 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. */
992
993
  info = _gdk_display_get_last_device_grab (display, device);

994
  return (info && !info->implicit);
995
996
}

997
998
999
1000
1001
1002
1003
1004
1005
/**
 * 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.
 */
1006
const gchar *
1007
1008
gdk_display_get_name (GdkDisplay *display)
{
1009
1010
1011
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_name (display);
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
}

/**
 * gdk_display_beep:
 * @display: a #GdkDisplay
 *
 * Emits a short beep on @display
 */
void
gdk_display_beep (GdkDisplay *display)
{
1023
1024
1025
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->beep (display);
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
}

/**
 * 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)
{
1045
1046
1047
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->sync (display);
1048
1049
1050
1051
1052
1053
1054
1055
1056
}

/**
 * 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
1057
 * to call this function explicitly. A common case where this function
1058
1059
1060
1061
1062
1063
1064
1065
1066
 * 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)
{
1067
1068
1069
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->flush (display);
1070
1071
1072
1073
1074
1075
}

/**
 * gdk_display_get_default_group:
 * @display: a #GdkDisplay
 *
1076
1077
 * Returns the default group leader surface for all toplevel surfaces
 * on @display. This surface is implicitly created by GDK.
1078
 * See gdk_surface_set_group().
1079
 *
1080
 * Returns: (transfer none): The default group leader surface
1081
1082
 * for @display
 **/
1083
GdkSurface *
1084
1085
gdk_display_get_default_group (GdkDisplay *display)
{
1086
1087
1088
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_default_group (display);
1089
1090
}

1091
1092
1093
1094
1095
1096
/**
 * gdk_display_get_clipboard:
 * @display: a #GdkDisplay
 *
 * Gets the clipboard used for copy/paste operations.
 *
1097
1098
 * Returns: (transfer none): the display's clipboard
 */
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
GdkClipboard *
gdk_display_get_clipboard (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  if (display->clipboard == NULL)
    display->clipboard = gdk_clipboard_new (display);

  return display->clipboard;
}

/**
 * gdk_display_get_primary_clipboard:
 * @display: a #GdkDisplay
 *
 * Gets the clipboard used for the primary selection. On backends where the
 * primary clipboard is not supported natively, GDK emulates this clipboard
 * locally.
 *
1118
1119
 * Returns: (transfer none): the primary clipboard
 */
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
GdkClipboard *
gdk_display_get_primary_clipboard (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  if (display->primary_clipboard == NULL)
    display->primary_clipboard = gdk_clipboard_new (display);

  return display->primary_clipboard;
}

1131
1132
1133
1134
/**
 * gdk_display_supports_shapes:
 * @display: a #GdkDisplay
 *
1135
 * Returns %TRUE if gdk_surface_shape_combine_mask() can
1136
1137
1138
1139
1140
1141
1142
 * be used to create shaped windows on @display.
 *
 * Returns: %TRUE if shaped windows are supported
 */
gboolean
gdk_display_supports_shapes (GdkDisplay *display)
{
1143
1144
1145
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

  return GDK_DISPLAY_GET_CLASS (display)