gdkdisplay.c 46.3 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
/**
 * SECTION:gdkdisplay
43
 * @Short_description: Controls a set of monitors and their associated input devices
44
45
 * @Title: GdkDisplay
 *
46
 * GdkDisplay objects are the GDK representation of a workstation.
Matthias Clasen's avatar
Matthias Clasen committed
47
 *
48
49
50
 * 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
51
 *
52
53
54
55
56
 * 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
57
 * with gdk_display_get_monitor_at_surface() and similar APIs.
58
59
 */

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

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

77
enum {
78
  OPENED,
79
  CLOSED,
80
81
  SEAT_ADDED,
  SEAT_REMOVED,
82
  SETTING_CHANGED,
83
84
85
  LAST_SIGNAL
};

86
87
88
static void gdk_display_dispose     (GObject         *object);
static void gdk_display_finalize    (GObject         *object);

89

90
static GdkAppLaunchContext *gdk_display_real_get_app_launch_context (GdkDisplay *display);
91

92
93
static guint signals[LAST_SIGNAL] = { 0 };

Matthias Clasen's avatar
Matthias Clasen committed
94
G_DEFINE_TYPE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
95

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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;

114
115
116
117
    case PROP_INPUT_SHAPES:
      g_value_set_boolean (value, gdk_display_supports_input_shapes (display));
      break;

118
119
120
121
122
    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
  /**
   * GdkDisplay:composited:
   *
Yuri Chornoivan's avatar
Yuri Chornoivan committed
175
   * %TRUE if the display properly composites the alpha channel.
176
177
178
179
180
181
182
   * 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
200
201
202
203
204
205
206
207
208
209
210
  /**
   * GdkDisplay:input-shapes:
   *
   * %TRUE if the display supports input shapes. See
   * gdk_display_supports_input_shapes() for details.
   */
  props[PROP_INPUT_SHAPES] =
    g_param_spec_boolean ("input-shapes",
                          P_("Input shapes"),
                          P_("Input shapes"),
                          TRUE,
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

211
212
  g_object_class_install_properties (object_class, LAST_PROP, props);

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

229
230
231
232
233
234
235
236
  /**
   * 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.
   */   
237
  signals[CLOSED] =
Matthias Clasen's avatar
Matthias Clasen committed
238
    g_signal_new (g_intern_static_string ("closed"),
239
240
241
242
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkDisplayClass, closed),
		  NULL, NULL,
243
                  NULL,
244
245
246
		  G_TYPE_NONE,
		  1,
		  G_TYPE_BOOLEAN);
247
248
249
250
251
252
253
254
255
256
257
258
259
260

  /**
   * 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,
261
                  NULL,
262
263
264
265
266
		  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
267
   * @seat: the seat that was just removed
268
269
270
271
272
273
274
275
276
   *
   * 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,
277
                  NULL,
278
		  G_TYPE_NONE, 1, GDK_TYPE_SEAT);
279

280
281
282
283
284
285
286
287
  /**
   * 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.
   */
288
289
290
291
292
293
294
  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);
295
296
}

297
static void
298
free_pointer_info (GdkPointerSurfaceInfo *info)
299
{
300
  g_clear_object (&info->surface_under_pointer);
301
  g_slice_free (GdkPointerSurfaceInfo, info);
302
303
304
305
306
}

static void
free_device_grab (GdkDeviceGrabInfo *info)
{
307
  g_object_unref (info->surface);
308
309
310
311
312
313
314
315
316
317
  g_free (info);
}

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

318
  g_list_free_full (list, (GDestroyNotify) free_device_grab);
319
320
321
322

  return TRUE;
}

323
324
325
326
static void
gdk_display_init (GdkDisplay *display)
{
  display->double_click_time = 250;
327
  display->double_click_distance = 5;
328

329
330
331
332
333
  display->device_grabs = g_hash_table_new (NULL, NULL);

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

334
335
  g_queue_init (&display->queued_events);

Matthias Clasen's avatar
Matthias Clasen committed
336
  display->debug_flags = _gdk_debug_flags;
337
338
339

  display->composited = TRUE;
  display->rgba = TRUE;
340
  display->input_shapes = TRUE;
341
342
}

343
344
345
static void
gdk_display_dispose (GObject *object)
{
346
  GdkDisplay *display = GDK_DISPLAY (object);
347

348
349
  _gdk_display_manager_remove_display (gdk_display_manager_get (), display);

350
  g_queue_clear (&display->queued_events);
351

Matthias Clasen's avatar
Matthias Clasen committed
352
  G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
353
354
}

355
356
357
static void
gdk_display_finalize (GObject *object)
{
358
  GdkDisplay *display = GDK_DISPLAY (object);
359
360
361
362
363
364
365
366

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

367
  g_list_free_full (display->seats, g_object_unref);
368

Matthias Clasen's avatar
Matthias Clasen committed
369
  G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
370
371
372
373
374
375
}

/**
 * gdk_display_close:
 * @display: a #GdkDisplay
 *
376
 * Closes the connection to the windowing system for the given display,
377
 * and cleans up associated resources.
378
379
380
381
382
 */
void
gdk_display_close (GdkDisplay *display)
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
383
384
385
386

  if (!display->closed)
    {
      display->closed = TRUE;
387
388
      
      g_signal_emit (display, signals[CLOSED], 0, FALSE);
389
390
      g_object_run_dispose (G_OBJECT (display));
      
391
      g_object_unref (display);
392
    }
393
394
}

John Stowers's avatar
John Stowers committed
395
396
397
398
/**
 * gdk_display_is_closed:
 * @display: a #GdkDisplay
 *
399
400
401
 * Finds out if the display has been closed.
 *
 * Returns: %TRUE if the display is closed.
John Stowers's avatar
John Stowers committed
402
403
404
405
406
407
408
409
410
 */
gboolean
gdk_display_is_closed  (GdkDisplay  *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

  return display->closed;
}

411
412
413
414
415
416
417
/**
 * gdk_display_get_event:
 * @display: a #GdkDisplay
 * 
 * Gets the next #GdkEvent to be processed for @display, fetching events from the
 * windowing system if necessary.
 * 
418
419
420
421
 * Returns: (nullable) (transfer full): the next #GdkEvent to be processed,
 *   or %NULL if no events are pending
 */
GdkEvent *
422
423
424
gdk_display_get_event (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
425

426
427
  if (display->event_pause_count == 0)
    GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
428
429

  return _gdk_event_unqueue (display);
430
431
432
433
}

/**
 * gdk_display_peek_event:
Alexander Larsson's avatar
Alexander Larsson committed
434
 * @display: a #GdkDisplay 
435
 * 
436
 * Gets a copy of the first #GdkEvent in the @display’s event queue, without
437
438
439
440
 * 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.)
 * 
441
442
 * Returns: (nullable) (transfer full): the first #GdkEvent on the
 *   event queue
443
 **/
444
GdkEvent *
445
446
447
448
449
450
451
452
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);
  
453
  if (tmp_list != NULL)
454
    return gdk_event_ref (tmp_list->data);
455
456

  return NULL;
457
458
459
460
461
}

/**
 * gdk_display_put_event:
 * @display: a #GdkDisplay
Matthias Clasen's avatar
Matthias Clasen committed
462
 * @event: (transfer none): a #GdkEvent
463
 *
464
 * Appends the given event onto the front of the event
465
 * queue for @display.
466
467
468
 *
 * This function is only useful in very special situations
 * and should not be used by applications.
469
470
 **/
void
471
472
gdk_display_put_event (GdkDisplay *display,
                       GdkEvent   *event)
473
474
475
476
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
  g_return_if_fail (event != NULL);

477
  _gdk_event_queue_append (display, gdk_event_ref ((GdkEvent *)event));
478
}
479

480
static void
Matthias Clasen's avatar
Matthias Clasen committed
481
generate_grab_broken_event (GdkDisplay *display,
482
                            GdkSurface  *surface,
Matthias Clasen's avatar
Matthias Clasen committed
483
484
                            GdkDevice  *device,
			    gboolean    implicit,
485
			    GdkSurface  *grab_surface)
486
{
487
  g_return_if_fail (surface != NULL);
488

489
  if (!GDK_SURFACE_DESTROYED (surface))
490
    {
491
492
      GdkEvent *event;

493
      event = gdk_grab_broken_event_new (surface,
494
495
496
                                         device,
                                         grab_surface,
                                         implicit);
497

498
      _gdk_event_queue_append (display, event);
499
500
501
    }
}

502
503
504
GdkDeviceGrabInfo *
_gdk_display_get_last_device_grab (GdkDisplay *display,
                                   GdkDevice  *device)
505
506
507
{
  GList *l;

508
  l = g_hash_table_lookup (display->device_grabs, device);
509

510
511
512
513
514
  if (l)
    {
      l = g_list_last (l);
      return l->data;
    }
515

516
517
  return NULL;
}
518

519
520
521
GdkDeviceGrabInfo *
_gdk_display_add_device_grab (GdkDisplay       *display,
                              GdkDevice        *device,
522
                              GdkSurface        *surface,
523
524
525
526
527
                              gboolean          owner_events,
                              GdkEventMask      event_mask,
                              unsigned long     serial_start,
                              guint32           time,
                              gboolean          implicit)
528
{
529
530
  GdkDeviceGrabInfo *info, *other_info;
  GList *grabs, *l;
531

532
  info = g_new0 (GdkDeviceGrabInfo, 1);
533

534
  info->surface = g_object_ref (surface);
535
536
537
538
539
540
  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;
541
542

  grabs = g_hash_table_lookup (display->device_grabs, device);
543
544
545
546

  /* 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 */
547
  for (l = grabs; l != NULL; l = l->next)
548
    {
549
      other_info = l->data;
550

551
552
553
      if (info->serial_start < other_info->serial_start)
	break;
    }
554
555

  grabs = g_list_insert_before (grabs, l, info);
556
557
558
559
560
561

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

564
  /* Find any previous grab and update its end time */
565
  l = g_list_find (grabs, info);
566
567
  l = l->prev;
  if (l)
568
    {
569
570
571
572
      other_info = l->data;
      other_info->serial_end = serial_start;
    }

573
  g_hash_table_insert (display->device_grabs, device, grabs);
574

575
  return info;
576
577
}

578
static GdkSurface *
579
580
581
582
get_current_toplevel (GdkDisplay      *display,
                      GdkDevice       *device,
                      int             *x_out,
                      int             *y_out,
583
584
		      GdkModifierType *state_out)
{
585
  GdkSurface *pointer_surface;
586
  double x, y;
587
588
  GdkModifierType state;

589
  pointer_surface = _gdk_device_surface_at_position (device, &x, &y, &state);
590

591
  if (pointer_surface != NULL &&
592
      GDK_SURFACE_DESTROYED (pointer_surface))
593
    pointer_surface = NULL;
594

595
596
  *x_out = round (x);
  *y_out = round (y);
597
  *state_out = state;
598

599
  return pointer_surface;
600
601
}

602
static void
603
604
605
606
607
608
switch_to_pointer_grab (GdkDisplay        *display,
                        GdkDevice         *device,
			GdkDeviceGrabInfo *grab,
			GdkDeviceGrabInfo *last_grab,
			guint32            time,
			gulong             serial)
609
{
610
611
  GdkSurface *new_toplevel;
  GdkPointerSurfaceInfo *info;
612
613
  GList *old_grabs;
  GdkModifierType state;
614
  int x = 0, y = 0;
615
616

  /* Temporarily unset pointer to make sure we send the crossing events below */
617
618
619
620
  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);

621
622
623
624
  if (grab)
    {
      /* New grab is in effect */
      if (!grab->implicit)
625
	{
626
627
628
	  /* !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)
629
	    _gdk_display_set_surface_under_pointer (display, device, NULL);
630
	}
631

632
633
      grab->activated = TRUE;
    }
634
635

  if (last_grab)
636
    {
637
638
639
640
641
      new_toplevel = NULL;

      if (grab == NULL /* ungrab */ ||
	  (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
	{
642
          new_toplevel = get_current_toplevel (display, device, &x, &y, &state);
643

644
645
646
	  if (new_toplevel)
	    {
	      /* w is now toplevel and x,y in toplevel coords */
647
              _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
648
649
650
	      info->toplevel_x = x;
	      info->toplevel_y = y;
	      info->state = state;
651
652
653
654
	    }
	}

      if (grab == NULL) /* Ungrabbed, send events */
655
	{
656
657
	  /* We're now ungrabbed, update the surface_under_pointer */
	  _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
658
	}
659
660
    }

661
  g_hash_table_insert (display->device_grabs, device, old_grabs);
662
663
}

664
665
void
_gdk_display_update_last_event (GdkDisplay     *display,
Matthias Clasen's avatar
Matthias Clasen committed
666
                                GdkEvent       *event)
667
668
669
670
671
{
  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
    display->last_event_time = gdk_event_get_time (event);
}

672
void
673
674
675
_gdk_display_device_grab_update (GdkDisplay *display,
                                 GdkDevice  *device,
                                 gulong      current_serial)
676
{
677
678
  GdkDeviceGrabInfo *current_grab, *next_grab;
  GList *grabs;
679
  guint32 time;
680

681
  time = display->last_event_time;
682
  grabs = g_hash_table_lookup (display->device_grabs, device);
683

684
  while (grabs != NULL)
685
    {
686
      current_grab = grabs->data;
687

688
689
      if (current_grab->serial_start > current_serial)
	return; /* Hasn't started yet */
690

691
      if (current_grab->serial_end > current_serial)
692
693
694
	{
	  /* This one hasn't ended yet.
	     its the currently active one or scheduled to be active */
695

696
	  if (!current_grab->activated)
697
            {
698
              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
699
                switch_to_pointer_grab (display, device, current_grab, NULL, time, current_serial);
700
701
            }

702
703
704
705
	  break;
	}

      next_grab = NULL;
706
      if (grabs->next)
707
	{
708
	  /* This is the next active grab */
709
710
	  next_grab = grabs->next->data;

711
712
	  if (next_grab->serial_start > current_serial)
	    next_grab = NULL; /* Actually its not yet active */
713
714
	}

715
      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
716
717
          (next_grab != NULL && current_grab->surface != next_grab->surface))
        generate_grab_broken_event (display, GDK_SURFACE (current_grab->surface),
718
                                    device,
719
                                    current_grab->implicit,
720
                                    next_grab? next_grab->surface : NULL);
721

722
      /* Remove old grab */
723
724
725
      grabs = g_list_delete_link (grabs, grabs);
      g_hash_table_insert (display->device_grabs, device, grabs);

726
      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
727
        switch_to_pointer_grab (display, device,
728
729
730
731
                                next_grab, current_grab,
                                time, current_serial);

      free_device_grab (current_grab);
732
    }
733
734
735
}

static GList *
736
737
grab_list_find (GList  *grabs,
                gulong  serial)
738
{
739
  GdkDeviceGrabInfo *grab;
740

741
  while (grabs)
742
    {
743
      grab = grabs->data;
744

745
      if (serial >= grab->serial_start && serial < grab->serial_end)
746
747
748
	return grabs;

      grabs = grabs->next;
749
    }
750

751
752
753
  return NULL;
}

754
755
756
757
758
759
static GList *
find_device_grab (GdkDisplay *display,
                   GdkDevice  *device,
                   gulong      serial)
{
  GList *l;
760

761
762
763
  l = g_hash_table_lookup (display->device_grabs, device);
  return grab_list_find (l, serial);
}
764

765
766
767
768
GdkDeviceGrabInfo *
_gdk_display_has_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial)
769
770
771
{
  GList *l;

772
  l = find_device_grab (display, device, serial);
773
774
  if (l)
    return l->data;
775

776
777
778
  return NULL;
}

779
780
/* Returns true if last grab was ended
 * If if_child is non-NULL, end the grab only if the grabbed
781
 * surface is the same as if_child or a descendant of it */
782
gboolean
783
784
785
_gdk_display_end_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial,
786
                              GdkSurface  *if_child,
787
                              gboolean    implicit)
788
{
789
  GdkDeviceGrabInfo *grab;
790
791
  GList *l;

792
793
  l = find_device_grab (display, device, serial);

794
795
796
797
  if (l == NULL)
    return FALSE;

  grab = l->data;
798
  if (grab && (if_child == NULL || if_child == grab->surface))
799
800
801
802
803
804
805
    {
      grab->serial_end = serial;
      grab->implicit_ungrab = implicit;
      return l->next == NULL;
    }
  
  return FALSE;
806
807
}

808
GdkPointerSurfaceInfo *
809
810
_gdk_display_get_pointer_info (GdkDisplay *display,
                               GdkDevice  *device)
811
{
812
  GdkPointerSurfaceInfo *info;
813
  GdkSeat *seat;
814

815
816
817
818
819
820
821
  if (device)
    {
      seat = gdk_device_get_seat (device);

      if (device == gdk_seat_get_keyboard (seat))
        device = gdk_seat_get_pointer (seat);
    }
822

823
824
825
826
827
828
829
  if (G_UNLIKELY (!device))
    return NULL;

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

  if (G_UNLIKELY (!info))
    {
830
      info = g_slice_new0 (GdkPointerSurfaceInfo);
831
832
833
834
      g_hash_table_insert (display->pointers_info, device, info);
    }

  return info;
835
836
}

837
838
839
840
void
_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
                                   GdkDisplayPointerInfoForeach  func,
                                   gpointer                      user_data)
841
{
842
843
  GHashTableIter iter;
  gpointer key, value;
844

845
846
847
  g_hash_table_iter_init (&iter, display->pointers_info);

  while (g_hash_table_iter_next (&iter, &key, &value))
848
    {
849
      GdkPointerSurfaceInfo *info = value;
850
      GdkDevice *device = key;
851

852
      (func) (display, device, info, user_data);
853
854
    }
}
855

856
857
/*< private >
 * gdk_device_grab_info:
858
859
 * @display: the display for which to get the grab information
 * @device: device to get the grab information from
860
 * @grab_surface: (out) (transfer none): location to store current grab surface
861
 * @owner_events: (out): location to store boolean indicating whether
862
 *   the @owner_events flag to gdk_device_grab() was %TRUE.
863
864
 *
 * Determines information about the current keyboard grab.
865
 * This is not public API and must not be used by applications.
866
 *
867
 * Returns: %TRUE if this application currently has the
868
 *  keyboard grabbed.
869
 */
870
gboolean
871
872
gdk_device_grab_info (GdkDisplay  *display,
                      GdkDevice   *device,
873
                      GdkSurface  **grab_surface,
874
                      gboolean    *owner_events)
875
{
876
877
  GdkDeviceGrabInfo *info;

878
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
879
880
881
  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);

  info = _gdk_display_get_last_device_grab (display, device);
882

883
  if (info)
884
    {
885
886
      if (grab_surface)
        *grab_surface = info->surface;
887
      if (owner_events)
888
        *owner_events = info->owner_events;
889
890
891
892
893
894
895

      return TRUE;
    }
  else
    return FALSE;
}

896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
/**
 * 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;

911
  g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
912
  g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
913

914
915
916
  /* 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. */
917
918
  info = _gdk_display_get_last_device_grab (display, device);

919
  return (info && !info->implicit);
920
921
}

922
923
924
925
926
927
928
929
930
/**
 * 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.
 */
Benjamin Otte's avatar
Benjamin Otte committed
931
const char *
932
933
gdk_display_get_name (GdkDisplay *display)
{
934
935
936
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_name (display);
937
938
939
940
941
942
943
944
945
946
947
}

/**
 * gdk_display_beep:
 * @display: a #GdkDisplay
 *
 * Emits a short beep on @display
 */
void
gdk_display_beep (GdkDisplay *display)
{
948
949
950
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->beep (display);
951
952
953
954
955
956
957
958
959
}

/**
 * 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
960
961
962
 * gdk_display_sync() before gdk_x11_display_error_trap_pop() makes sure
 * that any errors generated from earlier requests are handled before the
 * error trap is removed.
963
964
965
966
967
968
969
 *
 * 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)
{
970
971
972
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->sync (display);
973
974
975
976
977
978
979
980
981
}

/**
 * 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
982
 * to call this function explicitly. A common case where this function
983
984
985
986
987
988
989
990
991
 * 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)
{
992
993
994
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->flush (display);
995
996
}

997
998
999
1000
1001
1002
/**
 * gdk_display_get_clipboard:
 * @display: a #GdkDisplay
 *
 * Gets the clipboard used for copy/paste operations.
 *
1003
1004
 * Returns: (transfer none): the display's clipboard
 */
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
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.
 *
1024
1025
 * Returns: (transfer none): the primary clipboard
 */
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
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;
}

1037
1038
1039
1040
/**
 * gdk_display_supports_input_shapes:
 * @display: a #GdkDisplay
 *
1041
 * Returns %TRUE if gdk_surface_set_input_region() can
1042
 * be used to modify the input shape of surfaces on @display.
1043
 *
1044
1045
 * On modern displays, this value is always %TRUE.
 *
1046
 * Returns: %TRUE if surfaces with modified input shape are supported
1047
1048
1049
1050
 */
gboolean
gdk_display_supports_input_shapes (GdkDisplay *display)
{
1051
1052
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
  return display->input_shapes;
}

void
gdk_display_set_input_shapes (GdkDisplay *display,
                              gboolean    input_shapes)
{
  g_return_if_fail (GDK_IS_DISPLAY (display));

  if (display->input_shapes == input_shapes)
    return;

  display->input_shapes = input_shapes;

  g_object_notify_by_pspec (G_OBJECT (display), props[PROP_INPUT_SHAPES]);
1068
1069
}

1070
1071
1072
1073
1074
static GdkAppLaunchContext *
gdk_display_real_get_app_launch_context (GdkDisplay *display)
{
  GdkAppLaunchContext *ctx;

1075
1076
1077
  ctx = g_object_new (GDK_TYPE_APP_LAUNCH_CONTEXT,
                      "display", display,
                      NULL);
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088

  return ctx;
}

/**
 * gdk_display_get_app_launch_context:
 * @display: a #GdkDisplay
 *
 * Returns a #GdkAppLaunchContext suitable for launching
 * applications on the given display.
 *
1089
 * Returns: (transfer full): a new #GdkAppLaunchContext for @display.
1090
1091
1092
1093
1094
 *     Free with g_object_unref() when done
 */
GdkAppLaunchContext *
gdk_display_get_app_launch_context (GdkDisplay *display)
{
1095
1096
1097
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_app_launch_context (display);
1098
}
Matthias Clasen's avatar
Matthias Clasen committed
1099

1100
1101
1102
1103
1104
1105
/**
 * gdk_display_open:
 * @display_name: the name of the display to open
 *
 * Opens a display.
 *
1106
1107
 * Returns: (nullable) (transfer none): a #GdkDisplay, or %NULL if the
 *     display could not be opened
1108
1109
 */
GdkDisplay *
Benjamin Otte's avatar
Benjamin Otte committed
1110
gdk_display_open (const char *display_name)
1111
{