gdkdisplay.c 44.2 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
static void gdk_display_dispose     (GObject         *object);
static void gdk_display_finalize    (GObject         *object);

83

84
static GdkAppLaunchContext *gdk_display_real_get_app_launch_context (GdkDisplay *display);
85

86
87
static guint signals[LAST_SIGNAL] = { 0 };

Matthias Clasen's avatar
Matthias Clasen committed
88
G_DEFINE_TYPE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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;

108
109
110
111
    case PROP_INPUT_SHAPES:
      g_value_set_boolean (value, gdk_display_supports_input_shapes (display));
      break;

112
113
114
115
116
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

117
118
119
120
121
static void
gdk_display_real_make_default (GdkDisplay *display)
{
}

122
123
124
static void
gdk_display_real_opened (GdkDisplay *display)
{
125
  _gdk_display_manager_add_display (gdk_display_manager_get (), display);
126
127
}

128
129
130
131
132
133
134
135
136
static GdkSeat *
gdk_display_real_get_default_seat (GdkDisplay *display)
{
  if (!display->seats)
    return NULL;

  return display->seats->data;
}

137
138
139
140
static void
gdk_display_class_init (GdkDisplayClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
141

142
  object_class->finalize = gdk_display_finalize;
143
  object_class->dispose = gdk_display_dispose;
144
  object_class->get_property = gdk_display_get_property;
145

146
  class->get_app_launch_context = gdk_display_real_get_app_launch_context;
147
  class->opened = gdk_display_real_opened;
148
  class->make_default = gdk_display_real_make_default;
149
  class->get_default_seat = gdk_display_real_get_default_seat;
150

151
  /**
152
   * GdkDisplay:composited: (attributes org.gtk.Property.get=gdk_display_is_composited)
153
   *
Yuri Chornoivan's avatar
Yuri Chornoivan committed
154
   * %TRUE if the display properly composites the alpha channel.
155
156
157
158
159
160
   */
  props[PROP_COMPOSITED] =
    g_param_spec_boolean ("composited",
                          P_("Composited"),
                          P_("Composited"),
                          TRUE,
161
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
162
163

  /**
164
   * GdkDisplay:rgba: (attributes org.gtk.Property.get=gdk_display_is_rgba)
165
   *
166
   * %TRUE if the display supports an alpha channel.
167
168
169
170
171
172
   */
  props[PROP_RGBA] =
    g_param_spec_boolean ("rgba",
                          P_("RGBA"),
                          P_("RGBA"),
                          TRUE,
173
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
174

175
  /**
176
   * GdkDisplay:input-shapes: (attributes org.gtk.Property.get=gdk_display_supports_input_shapes)
177
   *
178
   * %TRUE if the display supports input shapes.
179
180
181
182
183
184
185
186
   */
  props[PROP_INPUT_SHAPES] =
    g_param_spec_boolean ("input-shapes",
                          P_("Input shapes"),
                          P_("Input shapes"),
                          TRUE,
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

187
188
  g_object_class_install_properties (object_class, LAST_PROP, props);

189
  /**
Matthias Clasen's avatar
Matthias Clasen committed
190
   * GdkDisplay::opened:
191
192
   * @display: the object on which the signal is emitted
   *
193
   * Emitted when the connection to the windowing system for @display is opened.
194
195
196
197
198
   */
  signals[OPENED] =
    g_signal_new (g_intern_static_string ("opened"),
		  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST,
199
200
		  G_STRUCT_OFFSET (GdkDisplayClass, opened),
                  NULL, NULL,
201
                  NULL,
202
203
                  G_TYPE_NONE, 0);

204
205
206
207
208
  /**
   * GdkDisplay::closed:
   * @display: the object on which the signal is emitted
   * @is_error: %TRUE if the display was closed due to an error
   *
209
210
   * Emitted when the connection to the windowing system for @display is closed.
   */
211
  signals[CLOSED] =
Matthias Clasen's avatar
Matthias Clasen committed
212
    g_signal_new (g_intern_static_string ("closed"),
213
214
215
216
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkDisplayClass, closed),
		  NULL, NULL,
217
                  NULL,
218
219
220
		  G_TYPE_NONE,
		  1,
		  G_TYPE_BOOLEAN);
221
222
223
224
225
226

  /**
   * GdkDisplay::seat-added:
   * @display: the object on which the signal is emitted
   * @seat: the seat that was just added
   *
227
   * Emitted whenever a new seat is made known to the windowing system.
228
229
230
231
232
233
   */
  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,
234
                  NULL,
235
236
237
238
239
		  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
240
   * @seat: the seat that was just removed
241
   *
242
   * Emitted whenever a seat is removed by the windowing system.
243
244
245
246
247
248
   */
  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,
249
                  NULL,
250
		  G_TYPE_NONE, 1, GDK_TYPE_SEAT);
251

252
253
254
255
256
  /**
   * GdkDisplay::setting-changed:
   * @display: the object on which the signal is emitted
   * @setting: the name of the setting that changed
   *
257
   * Emitted whenever a setting changes its value.
258
   */
259
260
261
262
263
264
265
  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);
266
267
}

268
static void
269
free_pointer_info (GdkPointerSurfaceInfo *info)
270
{
271
  g_clear_object (&info->surface_under_pointer);
272
  g_slice_free (GdkPointerSurfaceInfo, info);
273
274
275
276
277
}

static void
free_device_grab (GdkDeviceGrabInfo *info)
{
278
  g_object_unref (info->surface);
279
280
281
282
283
284
285
286
287
288
  g_free (info);
}

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

289
  g_list_free_full (list, (GDestroyNotify) free_device_grab);
290
291
292
293

  return TRUE;
}

294
295
296
297
static void
gdk_display_init (GdkDisplay *display)
{
  display->double_click_time = 250;
298
  display->double_click_distance = 5;
299

300
301
302
303
304
  display->device_grabs = g_hash_table_new (NULL, NULL);

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

305
306
  g_queue_init (&display->queued_events);

Matthias Clasen's avatar
Matthias Clasen committed
307
  display->debug_flags = _gdk_debug_flags;
308
309
310

  display->composited = TRUE;
  display->rgba = TRUE;
311
  display->input_shapes = TRUE;
312
313
}

314
315
316
static void
gdk_display_dispose (GObject *object)
{
317
  GdkDisplay *display = GDK_DISPLAY (object);
318

319
320
  _gdk_display_manager_remove_display (gdk_display_manager_get (), display);

321
  g_queue_clear (&display->queued_events);
322

Matthias Clasen's avatar
Matthias Clasen committed
323
  G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
324
325
}

326
327
328
static void
gdk_display_finalize (GObject *object)
{
329
  GdkDisplay *display = GDK_DISPLAY (object);
330
331
332
333
334
335
336
337

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

338
  g_list_free_full (display->seats, g_object_unref);
339

Matthias Clasen's avatar
Matthias Clasen committed
340
  G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
341
342
343
344
}

/**
 * gdk_display_close:
345
346
347
 * @display: a `GdkDisplay`
 *
 * Closes the connection to the windowing system for the given display.
348
 *
349
 * This cleans up associated resources.
350
351
352
353
354
 */
void
gdk_display_close (GdkDisplay *display)
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
355
356
357
358

  if (!display->closed)
    {
      display->closed = TRUE;
359
360
      
      g_signal_emit (display, signals[CLOSED], 0, FALSE);
361
362
      g_object_run_dispose (G_OBJECT (display));
      
363
      g_object_unref (display);
364
    }
365
366
}

John Stowers's avatar
John Stowers committed
367
368
/**
 * gdk_display_is_closed:
369
 * @display: a `GdkDisplay`
John Stowers's avatar
John Stowers committed
370
 *
371
372
373
 * Finds out if the display has been closed.
 *
 * Returns: %TRUE if the display is closed.
John Stowers's avatar
John Stowers committed
374
375
376
377
378
379
380
381
382
 */
gboolean
gdk_display_is_closed  (GdkDisplay  *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

  return display->closed;
}

383
/*<private>
384
 * gdk_display_get_event:
385
 * @display: a `GdkDisplay`
386
 *
387
 * Gets the next `GdkEvent` to be processed for @display, fetching events from the
388
 * windowing system if necessary.
389
 *
390
 * Returns: (nullable) (transfer full): the next `GdkEvent` to be processed,
391
392
393
 *   or %NULL if no events are pending
 */
GdkEvent *
394
395
396
gdk_display_get_event (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
397

398
399
  if (display->event_pause_count == 0)
    GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
400
401

  return _gdk_event_unqueue (display);
402
403
404
405
}

/**
 * gdk_display_put_event:
406
407
 * @display: a `GdkDisplay`
 * @event: (transfer none): a `GdkEvent`
408
 *
409
 * Appends the given event onto the front of the event
410
 * queue for @display.
411
412
413
 *
 * This function is only useful in very special situations
 * and should not be used by applications.
414
415
 **/
void
416
417
gdk_display_put_event (GdkDisplay *display,
                       GdkEvent   *event)
418
419
420
421
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
  g_return_if_fail (event != NULL);

422
  _gdk_event_queue_append (display, gdk_event_ref ((GdkEvent *)event));
423
}
424

425
static void
Matthias Clasen's avatar
Matthias Clasen committed
426
generate_grab_broken_event (GdkDisplay *display,
427
                            GdkSurface  *surface,
Matthias Clasen's avatar
Matthias Clasen committed
428
429
                            GdkDevice  *device,
			    gboolean    implicit,
430
			    GdkSurface  *grab_surface)
431
{
432
  g_return_if_fail (surface != NULL);
433

434
  if (!GDK_SURFACE_DESTROYED (surface))
435
    {
436
437
      GdkEvent *event;

438
      event = gdk_grab_broken_event_new (surface,
439
440
441
                                         device,
                                         grab_surface,
                                         implicit);
442

443
      _gdk_event_queue_append (display, event);
444
445
446
    }
}

447
448
449
GdkDeviceGrabInfo *
_gdk_display_get_last_device_grab (GdkDisplay *display,
                                   GdkDevice  *device)
450
451
452
{
  GList *l;

453
  l = g_hash_table_lookup (display->device_grabs, device);
454

455
456
457
458
459
  if (l)
    {
      l = g_list_last (l);
      return l->data;
    }
460

461
462
  return NULL;
}
463

464
465
466
GdkDeviceGrabInfo *
_gdk_display_add_device_grab (GdkDisplay       *display,
                              GdkDevice        *device,
467
                              GdkSurface        *surface,
468
469
470
471
472
                              gboolean          owner_events,
                              GdkEventMask      event_mask,
                              unsigned long     serial_start,
                              guint32           time,
                              gboolean          implicit)
473
{
474
475
  GdkDeviceGrabInfo *info, *other_info;
  GList *grabs, *l;
476

477
  info = g_new0 (GdkDeviceGrabInfo, 1);
478

479
  info->surface = g_object_ref (surface);
480
481
482
483
484
485
  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;
486
487

  grabs = g_hash_table_lookup (display->device_grabs, device);
488
489
490
491

  /* 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 */
492
  for (l = grabs; l != NULL; l = l->next)
493
    {
494
      other_info = l->data;
495

496
497
498
      if (info->serial_start < other_info->serial_start)
	break;
    }
499
500

  grabs = g_list_insert_before (grabs, l, info);
501
502
503
504
505
506

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

509
  /* Find any previous grab and update its end time */
510
  l = g_list_find (grabs, info);
511
512
  l = l->prev;
  if (l)
513
    {
514
515
516
517
      other_info = l->data;
      other_info->serial_end = serial_start;
    }

518
  g_hash_table_insert (display->device_grabs, device, grabs);
519

520
  return info;
521
522
}

523
static GdkSurface *
524
525
526
527
get_current_toplevel (GdkDisplay      *display,
                      GdkDevice       *device,
                      int             *x_out,
                      int             *y_out,
528
529
		      GdkModifierType *state_out)
{
530
  GdkSurface *pointer_surface;
531
  double x, y;
532
533
  GdkModifierType state;

534
  pointer_surface = _gdk_device_surface_at_position (device, &x, &y, &state);
535

536
  if (pointer_surface != NULL &&
537
      GDK_SURFACE_DESTROYED (pointer_surface))
538
    pointer_surface = NULL;
539

540
541
  *x_out = round (x);
  *y_out = round (y);
542
  *state_out = state;
543

544
  return pointer_surface;
545
546
}

547
static void
548
549
550
551
552
553
switch_to_pointer_grab (GdkDisplay        *display,
                        GdkDevice         *device,
			GdkDeviceGrabInfo *grab,
			GdkDeviceGrabInfo *last_grab,
			guint32            time,
			gulong             serial)
554
{
555
556
  GdkSurface *new_toplevel;
  GdkPointerSurfaceInfo *info;
557
558
  GList *old_grabs;
  GdkModifierType state;
559
  int x = 0, y = 0;
560
561

  /* Temporarily unset pointer to make sure we send the crossing events below */
562
563
564
565
  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);

566
567
568
569
  if (grab)
    {
      /* New grab is in effect */
      if (!grab->implicit)
570
	{
571
572
573
	  /* !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)
574
	    _gdk_display_set_surface_under_pointer (display, device, NULL);
575
	}
576

577
578
      grab->activated = TRUE;
    }
579
580

  if (last_grab)
581
    {
582
583
584
585
586
      new_toplevel = NULL;

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

589
590
591
	  if (new_toplevel)
	    {
	      /* w is now toplevel and x,y in toplevel coords */
592
              _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
593
594
595
	      info->toplevel_x = x;
	      info->toplevel_y = y;
	      info->state = state;
596
597
598
599
	    }
	}

      if (grab == NULL) /* Ungrabbed, send events */
600
	{
601
602
	  /* We're now ungrabbed, update the surface_under_pointer */
	  _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
603
	}
604
605
    }

606
  g_hash_table_insert (display->device_grabs, device, old_grabs);
607
608
}

609
610
void
_gdk_display_update_last_event (GdkDisplay     *display,
Matthias Clasen's avatar
Matthias Clasen committed
611
                                GdkEvent       *event)
612
613
614
615
616
{
  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
    display->last_event_time = gdk_event_get_time (event);
}

617
void
618
619
620
_gdk_display_device_grab_update (GdkDisplay *display,
                                 GdkDevice  *device,
                                 gulong      current_serial)
621
{
622
623
  GdkDeviceGrabInfo *current_grab, *next_grab;
  GList *grabs;
624
  guint32 time;
625

626
  time = display->last_event_time;
627
  grabs = g_hash_table_lookup (display->device_grabs, device);
628

629
  while (grabs != NULL)
630
    {
631
      current_grab = grabs->data;
632

633
634
      if (current_grab->serial_start > current_serial)
	return; /* Hasn't started yet */
635

636
      if (current_grab->serial_end > current_serial)
637
638
639
	{
	  /* This one hasn't ended yet.
	     its the currently active one or scheduled to be active */
640

641
	  if (!current_grab->activated)
642
            {
643
              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
644
                switch_to_pointer_grab (display, device, current_grab, NULL, time, current_serial);
645
646
            }

647
648
649
650
	  break;
	}

      next_grab = NULL;
651
      if (grabs->next)
652
	{
653
	  /* This is the next active grab */
654
655
	  next_grab = grabs->next->data;

656
657
	  if (next_grab->serial_start > current_serial)
	    next_grab = NULL; /* Actually its not yet active */
658
659
	}

660
      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
661
662
          (next_grab != NULL && current_grab->surface != next_grab->surface))
        generate_grab_broken_event (display, GDK_SURFACE (current_grab->surface),
663
                                    device,
664
                                    current_grab->implicit,
665
                                    next_grab? next_grab->surface : NULL);
666

667
      /* Remove old grab */
668
669
670
      grabs = g_list_delete_link (grabs, grabs);
      g_hash_table_insert (display->device_grabs, device, grabs);

671
      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
672
        switch_to_pointer_grab (display, device,
673
674
675
676
                                next_grab, current_grab,
                                time, current_serial);

      free_device_grab (current_grab);
677
    }
678
679
680
}

static GList *
681
682
grab_list_find (GList  *grabs,
                gulong  serial)
683
{
684
  GdkDeviceGrabInfo *grab;
685

686
  while (grabs)
687
    {
688
      grab = grabs->data;
689

690
      if (serial >= grab->serial_start && serial < grab->serial_end)
691
692
693
	return grabs;

      grabs = grabs->next;
694
    }
695

696
697
698
  return NULL;
}

699
700
701
702
703
704
static GList *
find_device_grab (GdkDisplay *display,
                   GdkDevice  *device,
                   gulong      serial)
{
  GList *l;
705

706
707
708
  l = g_hash_table_lookup (display->device_grabs, device);
  return grab_list_find (l, serial);
}
709

710
711
712
713
GdkDeviceGrabInfo *
_gdk_display_has_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial)
714
715
716
{
  GList *l;

717
  l = find_device_grab (display, device, serial);
718
719
  if (l)
    return l->data;
720

721
722
723
  return NULL;
}

724
725
/* Returns true if last grab was ended
 * If if_child is non-NULL, end the grab only if the grabbed
726
 * surface is the same as if_child or a descendant of it */
727
gboolean
728
729
730
_gdk_display_end_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial,
731
                              GdkSurface  *if_child,
732
                              gboolean    implicit)
733
{
734
  GdkDeviceGrabInfo *grab;
735
736
  GList *l;

737
738
  l = find_device_grab (display, device, serial);

739
740
741
742
  if (l == NULL)
    return FALSE;

  grab = l->data;
743
  if (grab && (if_child == NULL || if_child == grab->surface))
744
745
746
747
748
749
750
    {
      grab->serial_end = serial;
      grab->implicit_ungrab = implicit;
      return l->next == NULL;
    }
  
  return FALSE;
751
752
}

753
GdkPointerSurfaceInfo *
754
755
_gdk_display_get_pointer_info (GdkDisplay *display,
                               GdkDevice  *device)
756
{
757
  GdkPointerSurfaceInfo *info;
758
  GdkSeat *seat;
759

760
761
762
763
764
765
766
  if (device)
    {
      seat = gdk_device_get_seat (device);

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

768
769
770
771
772
773
774
  if (G_UNLIKELY (!device))
    return NULL;

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

  if (G_UNLIKELY (!info))
    {
775
      info = g_slice_new0 (GdkPointerSurfaceInfo);
776
777
778
779
      g_hash_table_insert (display->pointers_info, device, info);
    }

  return info;
780
781
}

782
783
784
785
void
_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
                                   GdkDisplayPointerInfoForeach  func,
                                   gpointer                      user_data)
786
{
787
788
  GHashTableIter iter;
  gpointer key, value;
789

790
791
792
  g_hash_table_iter_init (&iter, display->pointers_info);

  while (g_hash_table_iter_next (&iter, &key, &value))
793
    {
794
      GdkPointerSurfaceInfo *info = value;
795
      GdkDevice *device = key;
796

797
      (func) (display, device, info, user_data);
798
799
    }
}
800

801
802
/*< private >
 * gdk_device_grab_info:
803
804
 * @display: the display for which to get the grab information
 * @device: device to get the grab information from
805
 * @grab_surface: (out) (transfer none): location to store current grab surface
806
 * @owner_events: (out): location to store boolean indicating whether
807
 *   the @owner_events flag to gdk_device_grab() was %TRUE.
808
809
 *
 * Determines information about the current keyboard grab.
810
 * This is not public API and must not be used by applications.
811
 *
812
 * Returns: %TRUE if this application currently has the
813
 *  keyboard grabbed.
814
 */
815
gboolean
816
817
gdk_device_grab_info (GdkDisplay  *display,
                      GdkDevice   *device,
818
                      GdkSurface  **grab_surface,
819
                      gboolean    *owner_events)
820
{
821
822
  GdkDeviceGrabInfo *info;

823
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
824
825
826
  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);

  info = _gdk_display_get_last_device_grab (display, device);
827

828
  if (info)
829
    {
830
831
      if (grab_surface)
        *grab_surface = info->surface;
832
      if (owner_events)
833
        *owner_events = info->owner_events;
834
835
836
837
838
839
840

      return TRUE;
    }
  else
    return FALSE;
}

841
842
/**
 * gdk_display_device_is_grabbed:
843
844
 * @display: a `GdkDisplay`
 * @device: a `GdkDevice`
845
846
847
848
 *
 * Returns %TRUE if there is an ongoing grab on @device for @display.
 *
 * Returns: %TRUE if there is a grab in effect for @device.
849
 */
850
851
852
853
854
855
gboolean
gdk_display_device_is_grabbed (GdkDisplay *display,
                               GdkDevice  *device)
{
  GdkDeviceGrabInfo *info;

856
  g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
857
  g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
858

859
860
861
  /* 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. */
862
863
  info = _gdk_display_get_last_device_grab (display, device);

864
  return (info && !info->implicit);
865
866
}

867
868
/**
 * gdk_display_get_name:
869
 * @display: a `GdkDisplay`
870
871
872
873
 *
 * Gets the name of the display.
 *
 * Returns: a string representing the display name. This string is owned
874
 *   by GDK and should not be modified or freed.
875
 */
Benjamin Otte's avatar
Benjamin Otte committed
876
const char *
877
878
gdk_display_get_name (GdkDisplay *display)
{
879
880
881
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_name (display);
882
883
884
885
}

/**
 * gdk_display_beep:
886
 * @display: a `GdkDisplay`
887
888
889
890
891
892
 *
 * Emits a short beep on @display
 */
void
gdk_display_beep (GdkDisplay *display)
{
893
894
895
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->beep (display);
896
897
898
899
}

/**
 * gdk_display_sync:
900
 * @display: a `GdkDisplay`
901
902
 *
 * Flushes any requests queued for the windowing system and waits until all
903
904
905
906
907
908
 * 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.
909
910
911
912
913
914
915
 *
 * 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)
{
916
917
918
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->sync (display);
919
920
921
922
}

/**
 * gdk_display_flush:
923
 * @display: a `GdkDisplay`
924
 *
925
926
927
928
929
 * 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
930
931
932
933
934
935
936
937
938
 * 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)
{
939
940
941
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->flush (display);
942
943
}

944
945
/**
 * gdk_display_get_clipboard:
946
 * @display: a `GdkDisplay`
947
948
949
 *
 * Gets the clipboard used for copy/paste operations.
 *
950
951
 * Returns: (transfer none): the display's clipboard
 */
952
953
954
955
956
957
958
959
960
961
962
963
964
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:
965
 * @display: a `GdkDisplay`
966
 *
967
968
969
970
 * Gets the clipboard used for the primary selection.
 *
 * On backends where the primary clipboard is not supported natively,
 * GDK emulates this clipboard locally.
971
 *
972
973
 * Returns: (transfer none): the primary clipboard
 */
974
975
976
977
978
979
980
981
982
983
984
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;
}

985
/**
986
 * gdk_display_supports_input_shapes: (attributes org.gtk.Method.get_property=input-shapes)
987
 * @display: a `GdkDisplay`
988
 *
989
990
991
 * Returns %TRUE if the display supports input shapes.
 *
 * This means that [method@Gdk.Surface.set_input_region] can
992
 * be used to modify the input shape of surfaces on @display.
993
 *
994
995
 * On modern displays, this value is always %TRUE.
 *
996
 * Returns: %TRUE if surfaces with modified input shape are supported
997
998
999
1000
 */
gboolean
gdk_display_supports_input_shapes (GdkDisplay *display)
{
1001
1002
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  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]);