gdkdisplay.c 45 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
 * GdkDisplay:
43
 *
44
 * `GdkDisplay` objects are the GDK representation of a workstation.
Matthias Clasen's avatar
Matthias Clasen committed
45
 *
46
 * Their purpose are two-fold:
47
 *
48
49
 * - 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
50
 *
51
52
53
54
 * Most of the input device handling has been factored out into separate
 * [class@Gdk.Seat] objects. Every display has a one or more seats, which
 * can be accessed with [method@Gdk.Display.get_default_seat] and
 * [method@Gdk.Display.list_seats].
55
 *
56
57
 * Output devices are represented by [class@Gdk.Monitor] objects, which can
 * be accessed with [method@Gdk.Display.get_monitor_at_surface] and similar APIs.
58
59
 */

60
61
62
63
64
enum
{
  PROP_0,
  PROP_COMPOSITED,
  PROP_RGBA,
65
  PROP_INPUT_SHAPES,
66
67
68
69
  LAST_PROP
};

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

71
enum {
72
  OPENED,
73
  CLOSED,
74
75
  SEAT_ADDED,
  SEAT_REMOVED,
76
  SETTING_CHANGED,
77
78
79
  LAST_SIGNAL
};

80
81
82
83
84
85
86
87
88
89
typedef struct _GdkDisplayPrivate GdkDisplayPrivate;

struct _GdkDisplayPrivate {
  guint rgba : 1;
  guint composited : 1;
  guint input_shapes : 1;

  GdkDebugFlags debug_flags;
};

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

98
G_DEFINE_TYPE_WITH_PRIVATE (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
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;

118
119
120
121
    case PROP_INPUT_SHAPES:
      g_value_set_boolean (value, gdk_display_supports_input_shapes (display));
      break;

122
123
124
125
126
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

127
128
129
130
131
static void
gdk_display_real_make_default (GdkDisplay *display)
{
}

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

138
139
140
141
142
143
144
145
146
static GdkSeat *
gdk_display_real_get_default_seat (GdkDisplay *display)
{
  if (!display->seats)
    return NULL;

  return display->seats->data;
}

147
148
149
150
static void
gdk_display_class_init (GdkDisplayClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
151

152
  object_class->finalize = gdk_display_finalize;
153
  object_class->dispose = gdk_display_dispose;
154
  object_class->get_property = gdk_display_get_property;
155

156
  class->get_app_launch_context = gdk_display_real_get_app_launch_context;
157
  class->opened = gdk_display_real_opened;
158
  class->make_default = gdk_display_real_make_default;
159
  class->get_default_seat = gdk_display_real_get_default_seat;
160

161
  /**
162
   * GdkDisplay:composited: (attributes org.gtk.Property.get=gdk_display_is_composited)
163
   *
Yuri Chornoivan's avatar
Yuri Chornoivan committed
164
   * %TRUE if the display properly composites the alpha channel.
165
166
167
168
169
170
   */
  props[PROP_COMPOSITED] =
    g_param_spec_boolean ("composited",
                          P_("Composited"),
                          P_("Composited"),
                          TRUE,
171
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
172
173

  /**
174
   * GdkDisplay:rgba: (attributes org.gtk.Property.get=gdk_display_is_rgba)
175
   *
176
   * %TRUE if the display supports an alpha channel.
177
178
179
180
181
182
   */
  props[PROP_RGBA] =
    g_param_spec_boolean ("rgba",
                          P_("RGBA"),
                          P_("RGBA"),
                          TRUE,
183
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
184

185
  /**
186
   * GdkDisplay:input-shapes: (attributes org.gtk.Property.get=gdk_display_supports_input_shapes)
187
   *
188
   * %TRUE if the display supports input shapes.
189
190
191
192
193
194
195
196
   */
  props[PROP_INPUT_SHAPES] =
    g_param_spec_boolean ("input-shapes",
                          P_("Input shapes"),
                          P_("Input shapes"),
                          TRUE,
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

197
198
  g_object_class_install_properties (object_class, LAST_PROP, props);

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

214
215
216
217
218
  /**
   * GdkDisplay::closed:
   * @display: the object on which the signal is emitted
   * @is_error: %TRUE if the display was closed due to an error
   *
219
220
   * Emitted when the connection to the windowing system for @display is closed.
   */
221
  signals[CLOSED] =
Matthias Clasen's avatar
Matthias Clasen committed
222
    g_signal_new (g_intern_static_string ("closed"),
223
224
225
226
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkDisplayClass, closed),
		  NULL, NULL,
227
                  NULL,
228
229
230
		  G_TYPE_NONE,
		  1,
		  G_TYPE_BOOLEAN);
231
232
233
234
235
236

  /**
   * GdkDisplay::seat-added:
   * @display: the object on which the signal is emitted
   * @seat: the seat that was just added
   *
237
   * Emitted whenever a new seat is made known to the windowing system.
238
239
240
241
242
243
   */
  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,
244
                  NULL,
245
246
247
248
249
		  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
250
   * @seat: the seat that was just removed
251
   *
252
   * Emitted whenever a seat is removed by the windowing system.
253
254
255
256
257
258
   */
  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,
259
                  NULL,
260
		  G_TYPE_NONE, 1, GDK_TYPE_SEAT);
261

262
263
264
265
266
  /**
   * GdkDisplay::setting-changed:
   * @display: the object on which the signal is emitted
   * @setting: the name of the setting that changed
   *
267
   * Emitted whenever a setting changes its value.
268
   */
269
270
271
272
273
274
275
  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);
276
277
}

278
static void
279
free_pointer_info (GdkPointerSurfaceInfo *info)
280
{
281
  g_clear_object (&info->surface_under_pointer);
282
  g_slice_free (GdkPointerSurfaceInfo, info);
283
284
285
286
287
}

static void
free_device_grab (GdkDeviceGrabInfo *info)
{
288
  g_object_unref (info->surface);
289
290
291
292
293
294
295
296
297
298
  g_free (info);
}

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

299
  g_list_free_full (list, (GDestroyNotify) free_device_grab);
300
301
302
303

  return TRUE;
}

304
305
306
static void
gdk_display_init (GdkDisplay *display)
{
307
308
  GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);

309
  display->double_click_time = 250;
310
  display->double_click_distance = 5;
311

312
313
314
315
316
  display->device_grabs = g_hash_table_new (NULL, NULL);

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

317
318
  g_queue_init (&display->queued_events);

319
  priv->debug_flags = _gdk_debug_flags;
320

321
322
323
  priv->composited = TRUE;
  priv->rgba = TRUE;
  priv->input_shapes = TRUE;
324
325
}

326
327
328
static void
gdk_display_dispose (GObject *object)
{
329
  GdkDisplay *display = GDK_DISPLAY (object);
330

331
332
  _gdk_display_manager_remove_display (gdk_display_manager_get (), display);

333
  g_queue_clear (&display->queued_events);
334

Matthias Clasen's avatar
Matthias Clasen committed
335
  G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
336
337
}

338
339
340
static void
gdk_display_finalize (GObject *object)
{
341
  GdkDisplay *display = GDK_DISPLAY (object);
342
343
344
345
346
347
348
349

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

350
  g_list_free_full (display->seats, g_object_unref);
351

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

/**
 * gdk_display_close:
357
358
359
 * @display: a `GdkDisplay`
 *
 * Closes the connection to the windowing system for the given display.
360
 *
361
 * This cleans up associated resources.
362
363
364
365
366
 */
void
gdk_display_close (GdkDisplay *display)
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
367
368
369
370

  if (!display->closed)
    {
      display->closed = TRUE;
371
372
      
      g_signal_emit (display, signals[CLOSED], 0, FALSE);
373
374
      g_object_run_dispose (G_OBJECT (display));
      
375
      g_object_unref (display);
376
    }
377
378
}

John Stowers's avatar
John Stowers committed
379
380
/**
 * gdk_display_is_closed:
381
 * @display: a `GdkDisplay`
John Stowers's avatar
John Stowers committed
382
 *
383
384
385
 * Finds out if the display has been closed.
 *
 * Returns: %TRUE if the display is closed.
John Stowers's avatar
John Stowers committed
386
387
388
389
390
391
392
393
394
 */
gboolean
gdk_display_is_closed  (GdkDisplay  *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

  return display->closed;
}

395
/*<private>
396
 * gdk_display_get_event:
397
 * @display: a `GdkDisplay`
398
 *
Matthias Clasen's avatar
Matthias Clasen committed
399
400
 * Gets the next `GdkEvent` to be processed for @display,
 * fetching events from the windowing system if necessary.
401
 *
Matthias Clasen's avatar
Matthias Clasen committed
402
403
 * Returns: (nullable) (transfer full): the next `GdkEvent`
 *   to be processed
404
405
 */
GdkEvent *
406
407
408
gdk_display_get_event (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
409

410
411
  if (display->event_pause_count == 0)
    GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
412
413

  return _gdk_event_unqueue (display);
414
415
416
417
}

/**
 * gdk_display_put_event:
418
419
 * @display: a `GdkDisplay`
 * @event: (transfer none): a `GdkEvent`
420
 *
421
 * Appends the given event onto the front of the event
422
 * queue for @display.
423
424
425
 *
 * This function is only useful in very special situations
 * and should not be used by applications.
426
427
 **/
void
428
429
gdk_display_put_event (GdkDisplay *display,
                       GdkEvent   *event)
430
431
432
433
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
  g_return_if_fail (event != NULL);

434
  _gdk_event_queue_append (display, gdk_event_ref ((GdkEvent *)event));
435
}
436

437
static void
Matthias Clasen's avatar
Matthias Clasen committed
438
generate_grab_broken_event (GdkDisplay *display,
439
                            GdkSurface  *surface,
Matthias Clasen's avatar
Matthias Clasen committed
440
441
                            GdkDevice  *device,
			    gboolean    implicit,
442
			    GdkSurface  *grab_surface)
443
{
444
  g_return_if_fail (surface != NULL);
445

446
  if (!GDK_SURFACE_DESTROYED (surface))
447
    {
448
449
      GdkEvent *event;

450
      event = gdk_grab_broken_event_new (surface,
451
452
453
                                         device,
                                         grab_surface,
                                         implicit);
454

455
      _gdk_event_queue_append (display, event);
456
457
458
    }
}

459
460
461
GdkDeviceGrabInfo *
_gdk_display_get_last_device_grab (GdkDisplay *display,
                                   GdkDevice  *device)
462
463
464
{
  GList *l;

465
  l = g_hash_table_lookup (display->device_grabs, device);
466

467
468
469
470
471
  if (l)
    {
      l = g_list_last (l);
      return l->data;
    }
472

473
474
  return NULL;
}
475

476
477
478
GdkDeviceGrabInfo *
_gdk_display_add_device_grab (GdkDisplay       *display,
                              GdkDevice        *device,
479
                              GdkSurface        *surface,
480
481
482
483
484
                              gboolean          owner_events,
                              GdkEventMask      event_mask,
                              unsigned long     serial_start,
                              guint32           time,
                              gboolean          implicit)
485
{
486
487
  GdkDeviceGrabInfo *info, *other_info;
  GList *grabs, *l;
488

489
  info = g_new0 (GdkDeviceGrabInfo, 1);
490

491
  info->surface = g_object_ref (surface);
492
493
494
495
496
497
  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;
498
499

  grabs = g_hash_table_lookup (display->device_grabs, device);
500
501
502
503

  /* 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 */
504
  for (l = grabs; l != NULL; l = l->next)
505
    {
506
      other_info = l->data;
507

508
509
510
      if (info->serial_start < other_info->serial_start)
	break;
    }
511
512

  grabs = g_list_insert_before (grabs, l, info);
513
514
515
516
517
518

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

521
  /* Find any previous grab and update its end time */
522
  l = g_list_find (grabs, info);
523
524
  l = l->prev;
  if (l)
525
    {
526
527
528
529
      other_info = l->data;
      other_info->serial_end = serial_start;
    }

530
  g_hash_table_insert (display->device_grabs, device, grabs);
531

532
  return info;
533
534
}

535
static GdkSurface *
536
537
538
539
get_current_toplevel (GdkDisplay      *display,
                      GdkDevice       *device,
                      int             *x_out,
                      int             *y_out,
540
541
		      GdkModifierType *state_out)
{
542
  GdkSurface *pointer_surface;
543
  double x, y;
544
545
  GdkModifierType state;

546
  pointer_surface = _gdk_device_surface_at_position (device, &x, &y, &state);
547

548
  if (pointer_surface != NULL &&
549
      GDK_SURFACE_DESTROYED (pointer_surface))
550
    pointer_surface = NULL;
551

552
553
  *x_out = round (x);
  *y_out = round (y);
554
  *state_out = state;
555

556
  return pointer_surface;
557
558
}

559
static void
560
561
562
563
564
565
switch_to_pointer_grab (GdkDisplay        *display,
                        GdkDevice         *device,
			GdkDeviceGrabInfo *grab,
			GdkDeviceGrabInfo *last_grab,
			guint32            time,
			gulong             serial)
566
{
567
568
  GdkSurface *new_toplevel;
  GdkPointerSurfaceInfo *info;
569
570
  GList *old_grabs;
  GdkModifierType state;
571
  int x = 0, y = 0;
572
573

  /* Temporarily unset pointer to make sure we send the crossing events below */
574
575
576
577
  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);

578
579
580
581
  if (grab)
    {
      /* New grab is in effect */
      if (!grab->implicit)
582
	{
583
584
585
	  /* !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)
586
	    _gdk_display_set_surface_under_pointer (display, device, NULL);
587
	}
588

589
590
      grab->activated = TRUE;
    }
591
592

  if (last_grab)
593
    {
594
595
596
597
598
      new_toplevel = NULL;

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

601
602
603
	  if (new_toplevel)
	    {
	      /* w is now toplevel and x,y in toplevel coords */
604
              _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
605
606
607
	      info->toplevel_x = x;
	      info->toplevel_y = y;
	      info->state = state;
608
609
610
611
	    }
	}

      if (grab == NULL) /* Ungrabbed, send events */
612
	{
613
614
	  /* We're now ungrabbed, update the surface_under_pointer */
	  _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
615
	}
616
617
    }

618
  g_hash_table_insert (display->device_grabs, device, old_grabs);
619
620
}

621
622
void
_gdk_display_update_last_event (GdkDisplay     *display,
Matthias Clasen's avatar
Matthias Clasen committed
623
                                GdkEvent       *event)
624
625
626
627
628
{
  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
    display->last_event_time = gdk_event_get_time (event);
}

629
void
630
631
632
_gdk_display_device_grab_update (GdkDisplay *display,
                                 GdkDevice  *device,
                                 gulong      current_serial)
633
{
634
635
  GdkDeviceGrabInfo *current_grab, *next_grab;
  GList *grabs;
636
  guint32 time;
637

638
  time = display->last_event_time;
639
  grabs = g_hash_table_lookup (display->device_grabs, device);
640

641
  while (grabs != NULL)
642
    {
643
      current_grab = grabs->data;
644

645
646
      if (current_grab->serial_start > current_serial)
	return; /* Hasn't started yet */
647

648
      if (current_grab->serial_end > current_serial)
649
650
651
	{
	  /* This one hasn't ended yet.
	     its the currently active one or scheduled to be active */
652

653
	  if (!current_grab->activated)
654
            {
655
              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
656
                switch_to_pointer_grab (display, device, current_grab, NULL, time, current_serial);
657
658
            }

659
660
661
662
	  break;
	}

      next_grab = NULL;
663
      if (grabs->next)
664
	{
665
	  /* This is the next active grab */
666
667
	  next_grab = grabs->next->data;

668
669
	  if (next_grab->serial_start > current_serial)
	    next_grab = NULL; /* Actually its not yet active */
670
671
	}

672
      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
673
674
          (next_grab != NULL && current_grab->surface != next_grab->surface))
        generate_grab_broken_event (display, GDK_SURFACE (current_grab->surface),
675
                                    device,
676
                                    current_grab->implicit,
677
                                    next_grab? next_grab->surface : NULL);
678

679
      /* Remove old grab */
680
681
682
      grabs = g_list_delete_link (grabs, grabs);
      g_hash_table_insert (display->device_grabs, device, grabs);

683
      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
684
        switch_to_pointer_grab (display, device,
685
686
687
688
                                next_grab, current_grab,
                                time, current_serial);

      free_device_grab (current_grab);
689
    }
690
691
692
}

static GList *
693
694
grab_list_find (GList  *grabs,
                gulong  serial)
695
{
696
  GdkDeviceGrabInfo *grab;
697

698
  while (grabs)
699
    {
700
      grab = grabs->data;
701

702
      if (serial >= grab->serial_start && serial < grab->serial_end)
703
704
705
	return grabs;

      grabs = grabs->next;
706
    }
707

708
709
710
  return NULL;
}

711
712
713
714
715
716
static GList *
find_device_grab (GdkDisplay *display,
                   GdkDevice  *device,
                   gulong      serial)
{
  GList *l;
717

718
719
720
  l = g_hash_table_lookup (display->device_grabs, device);
  return grab_list_find (l, serial);
}
721

722
723
724
725
GdkDeviceGrabInfo *
_gdk_display_has_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial)
726
727
728
{
  GList *l;

729
  l = find_device_grab (display, device, serial);
730
731
  if (l)
    return l->data;
732

733
734
735
  return NULL;
}

736
737
/* Returns true if last grab was ended
 * If if_child is non-NULL, end the grab only if the grabbed
738
 * surface is the same as if_child or a descendant of it */
739
gboolean
740
741
742
_gdk_display_end_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial,
743
                              GdkSurface  *if_child,
744
                              gboolean    implicit)
745
{
746
  GdkDeviceGrabInfo *grab;
747
748
  GList *l;

749
750
  l = find_device_grab (display, device, serial);

751
752
753
754
  if (l == NULL)
    return FALSE;

  grab = l->data;
755
  if (grab && (if_child == NULL || if_child == grab->surface))
756
757
758
759
760
761
762
    {
      grab->serial_end = serial;
      grab->implicit_ungrab = implicit;
      return l->next == NULL;
    }
  
  return FALSE;
763
764
}

765
GdkPointerSurfaceInfo *
766
767
_gdk_display_get_pointer_info (GdkDisplay *display,
                               GdkDevice  *device)
768
{
769
  GdkPointerSurfaceInfo *info;
770
  GdkSeat *seat;
771

772
773
774
775
776
777
778
  if (device)
    {
      seat = gdk_device_get_seat (device);

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

780
781
782
783
784
785
786
  if (G_UNLIKELY (!device))
    return NULL;

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

  if (G_UNLIKELY (!info))
    {
787
      info = g_slice_new0 (GdkPointerSurfaceInfo);
788
789
790
791
      g_hash_table_insert (display->pointers_info, device, info);
    }

  return info;
792
793
}

794
795
796
797
void
_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
                                   GdkDisplayPointerInfoForeach  func,
                                   gpointer                      user_data)
798
{
799
800
  GHashTableIter iter;
  gpointer key, value;
801

802
803
804
  g_hash_table_iter_init (&iter, display->pointers_info);

  while (g_hash_table_iter_next (&iter, &key, &value))
805
    {
806
      GdkPointerSurfaceInfo *info = value;
807
      GdkDevice *device = key;
808

809
      (func) (display, device, info, user_data);
810
811
    }
}
812

813
814
/*< private >
 * gdk_device_grab_info:
815
816
 * @display: the display for which to get the grab information
 * @device: device to get the grab information from
817
 * @grab_surface: (out) (transfer none): location to store current grab surface
818
 * @owner_events: (out): location to store boolean indicating whether
819
 *   the @owner_events flag to gdk_device_grab() was %TRUE.
820
821
 *
 * Determines information about the current keyboard grab.
822
 * This is not public API and must not be used by applications.
823
 *
824
 * Returns: %TRUE if this application currently has the
825
 *  keyboard grabbed.
826
 */
827
gboolean
828
829
gdk_device_grab_info (GdkDisplay  *display,
                      GdkDevice   *device,
830
                      GdkSurface  **grab_surface,
831
                      gboolean    *owner_events)
832
{
833
834
  GdkDeviceGrabInfo *info;

835
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
836
837
838
  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);

  info = _gdk_display_get_last_device_grab (display, device);
839

840
  if (info)
841
    {
842
843
      if (grab_surface)
        *grab_surface = info->surface;
844
      if (owner_events)
845
        *owner_events = info->owner_events;
846
847
848
849
850
851
852

      return TRUE;
    }
  else
    return FALSE;
}

853
854
/**
 * gdk_display_device_is_grabbed:
855
856
 * @display: a `GdkDisplay`
 * @device: a `GdkDevice`
857
858
859
860
 *
 * Returns %TRUE if there is an ongoing grab on @device for @display.
 *
 * Returns: %TRUE if there is a grab in effect for @device.
861
 */
862
863
864
865
866
867
gboolean
gdk_display_device_is_grabbed (GdkDisplay *display,
                               GdkDevice  *device)
{
  GdkDeviceGrabInfo *info;

868
  g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
869
  g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
870

871
872
873
  /* 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. */
874
875
  info = _gdk_display_get_last_device_grab (display, device);

876
  return (info && !info->implicit);
877
878
}

879
880
/**
 * gdk_display_get_name:
881
 * @display: a `GdkDisplay`
882
883
884
885
 *
 * Gets the name of the display.
 *
 * Returns: a string representing the display name. This string is owned
886
 *   by GDK and should not be modified or freed.
887
 */
Benjamin Otte's avatar
Benjamin Otte committed
888
const char *
889
890
gdk_display_get_name (GdkDisplay *display)
{
891
892
893
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_name (display);
894
895
896
897
}

/**
 * gdk_display_beep:
898
 * @display: a `GdkDisplay`
899
900
901
902
903
904
 *
 * Emits a short beep on @display
 */
void
gdk_display_beep (GdkDisplay *display)
{
905
906
907
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->beep (display);
908
909
910
911
}

/**
 * gdk_display_sync:
912
 * @display: a `GdkDisplay`
913
914
 *
 * Flushes any requests queued for the windowing system and waits until all
915
916
917
918
919
920
 * requests have been handled.
 *
 * This is often used for making sure that the display is synchronized
 * with the current state of the program. Calling [method@Gdk.Display.sync]
 * before [method@GdkX11.Display.error_trap_pop] makes sure that any errors
 * generated from earlier requests are handled before the error trap is removed.
921
922
923
924
925
926
927
 *
 * 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)
{
928
929
930
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->sync (display);
931
932
933
934
}

/**
 * gdk_display_flush:
935
 * @display: a `GdkDisplay`
936
 *
937
938
939
940
941
 * 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 to call this function explicitly. A common case where this function
942
943
944
945
946
947
948
949
950
 * 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)
{
951
952
953
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->flush (display);
954
955
}

956
957
/**
 * gdk_display_get_clipboard:
958
 * @display: a `GdkDisplay`
959
960
961
 *
 * Gets the clipboard used for copy/paste operations.
 *
962
963
 * Returns: (transfer none): the display's clipboard
 */
964
965
966
967
968
969
970
971
972
973
974
975
976
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:
977
 * @display: a `GdkDisplay`
978
 *
979
980
981
982
 * Gets the clipboard used for the primary selection.
 *
 * On backends where the primary clipboard is not supported natively,
 * GDK emulates this clipboard locally.
983
 *
984
985
 * Returns: (transfer none): the primary clipboard
 */
986
987
988
989
990
991
992
993
994
995
996
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;
}

997
/**
998
 * gdk_display_supports_input_shapes: (attributes org.gtk.Method.get_property=input-shapes)
999
 * @display: a `GdkDisplay`
1000
 *
1001
1002
1003
 * Returns %TRUE if the display supports input shapes.
 *
 * This means that [method@Gdk.Surface.set_input_region] can
1004
 * be used to modify the input shape of surfaces on @display.
1005
 *
1006
1007
 * On modern displays, this value is always %TRUE.
 *
1008
 * Returns: %TRUE if surfaces with modified input shape are supported
1009
1010
1011
1012
 */
gboolean
gdk_display_supports_input_shapes (GdkDisplay *display)
{
1013
1014
  GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);