gdkdisplay.c 48.1 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GDK - The GIMP Drawing Kit
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 * gdkdisplay.c
 * 
 * Copyright 2001 Sun Microsystems Inc. 
 *
 * Erwann Chenede <erwann.chenede@sun.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
Javier Jardón's avatar
Javier Jardón committed
19
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20
21
 */

22
#include "config.h"
23

24
#include "gdkdisplay.h"
25
#include "gdkdisplayprivate.h"
26

27
#include "gdkintl.h"
28
29
#include "gdk-private.h"

30
#include "gdkclipboardprivate.h"
31
#include "gdkdeviceprivate.h"
32
#include "gdkdisplaymanagerprivate.h"
33
#include "gdkevents.h"
34
#include "gdkinternals.h"
35
#include "gdkmonitorprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
36
#include "gdkframeclockidleprivate.h"
37

38
#include <math.h>
39
#include <glib.h>
40

41
/**
42
 * 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
typedef struct _GdkDisplayPrivate GdkDisplayPrivate;

struct _GdkDisplayPrivate {
83
84
85
86
87
88
89
  /* The base context that all other contexts inherit from.
   * This context is never exposed to public API and is
   * allowed to have a %NULL surface.
   */
  GdkGLContext *gl_context;
  GError *gl_error;

90
91
92
93
94
95
96
  guint rgba : 1;
  guint composited : 1;
  guint input_shapes : 1;

  GdkDebugFlags debug_flags;
};

97
98
99
static void gdk_display_dispose     (GObject         *object);
static void gdk_display_finalize    (GObject         *object);

100

101
static GdkAppLaunchContext *gdk_display_real_get_app_launch_context (GdkDisplay *display);
102

103
104
static guint signals[LAST_SIGNAL] = { 0 };

105
G_DEFINE_TYPE_WITH_PRIVATE (GdkDisplay, gdk_display, G_TYPE_OBJECT)
106

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
static void
gdk_display_get_property (GObject    *object,
                          guint       prop_id,
                          GValue     *value,
                          GParamSpec *pspec)
{
  GdkDisplay *display = GDK_DISPLAY (object);

  switch (prop_id)
    {
    case PROP_COMPOSITED:
      g_value_set_boolean (value, gdk_display_is_composited (display));
      break;

    case PROP_RGBA:
      g_value_set_boolean (value, gdk_display_is_rgba (display));
      break;

125
126
127
128
    case PROP_INPUT_SHAPES:
      g_value_set_boolean (value, gdk_display_supports_input_shapes (display));
      break;

129
130
131
132
133
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

134
135
136
137
138
static void
gdk_display_real_make_default (GdkDisplay *display)
{
}

139
140
141
static GdkGLContext *
gdk_display_default_init_gl (GdkDisplay  *display,
                             GError     **error)
142
{
143
144
145
146
  g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
                       _("The current backend does not support OpenGL"));

  return NULL;
147
148
}

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

  return display->seats->data;
}

158
159
160
161
162
163
static void
gdk_display_real_opened (GdkDisplay *display)
{
  _gdk_display_manager_add_display (gdk_display_manager_get (), display);
}

164
165
166
167
static void
gdk_display_class_init (GdkDisplayClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
168

169
  object_class->finalize = gdk_display_finalize;
170
  object_class->dispose = gdk_display_dispose;
171
  object_class->get_property = gdk_display_get_property;
172

173
  class->make_default = gdk_display_real_make_default;
174
175
  class->get_app_launch_context = gdk_display_real_get_app_launch_context;
  class->init_gl = gdk_display_default_init_gl;
176
  class->get_default_seat = gdk_display_real_get_default_seat;
177
  class->opened = gdk_display_real_opened;
178

179
  /**
180
   * GdkDisplay:composited: (attributes org.gtk.Property.get=gdk_display_is_composited)
181
   *
Yuri Chornoivan's avatar
Yuri Chornoivan committed
182
   * %TRUE if the display properly composites the alpha channel.
183
184
185
186
187
188
   */
  props[PROP_COMPOSITED] =
    g_param_spec_boolean ("composited",
                          P_("Composited"),
                          P_("Composited"),
                          TRUE,
189
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
190
191

  /**
192
   * GdkDisplay:rgba: (attributes org.gtk.Property.get=gdk_display_is_rgba)
193
   *
194
   * %TRUE if the display supports an alpha channel.
195
196
197
198
199
200
   */
  props[PROP_RGBA] =
    g_param_spec_boolean ("rgba",
                          P_("RGBA"),
                          P_("RGBA"),
                          TRUE,
201
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
202

203
  /**
204
   * GdkDisplay:input-shapes: (attributes org.gtk.Property.get=gdk_display_supports_input_shapes)
205
   *
206
   * %TRUE if the display supports input shapes.
207
208
209
210
211
212
213
214
   */
  props[PROP_INPUT_SHAPES] =
    g_param_spec_boolean ("input-shapes",
                          P_("Input shapes"),
                          P_("Input shapes"),
                          TRUE,
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

215
216
  g_object_class_install_properties (object_class, LAST_PROP, props);

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

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
   *
237
238
   * Emitted when the connection to the windowing system for @display is closed.
   */
239
  signals[CLOSED] =
Matthias Clasen's avatar
Matthias Clasen committed
240
    g_signal_new (g_intern_static_string ("closed"),
241
242
243
244
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkDisplayClass, closed),
		  NULL, NULL,
245
                  NULL,
246
247
248
		  G_TYPE_NONE,
		  1,
		  G_TYPE_BOOLEAN);
249
250
251
252
253
254

  /**
   * GdkDisplay::seat-added:
   * @display: the object on which the signal is emitted
   * @seat: the seat that was just added
   *
255
   * Emitted whenever a new seat is made known to the windowing system.
256
257
258
259
260
261
   */
  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,
262
                  NULL,
263
264
265
266
267
		  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
268
   * @seat: the seat that was just removed
269
   *
270
   * Emitted whenever a seat is removed by the windowing system.
271
272
273
274
275
276
   */
  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
  /**
   * GdkDisplay::setting-changed:
   * @display: the object on which the signal is emitted
   * @setting: the name of the setting that changed
   *
285
   * Emitted whenever a setting changes its value.
286
   */
287
288
289
290
291
292
293
  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);
294
295
}

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

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

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

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

  return TRUE;
}

322
323
324
static void
gdk_display_init (GdkDisplay *display)
{
325
326
  GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);

327
  display->double_click_time = 250;
328
  display->double_click_distance = 5;
329

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

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

335
336
  g_queue_init (&display->queued_events);

337
  priv->debug_flags = _gdk_debug_flags;
338

339
340
341
  priv->composited = TRUE;
  priv->rgba = TRUE;
  priv->input_shapes = TRUE;
342
343
}

344
345
346
static void
gdk_display_dispose (GObject *object)
{
347
  GdkDisplay *display = GDK_DISPLAY (object);
348
  GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);
349

350
351
  _gdk_display_manager_remove_display (gdk_display_manager_get (), display);

352
  g_queue_clear (&display->queued_events);
353

354
355
356
  g_clear_object (&priv->gl_context);
  g_clear_error (&priv->gl_error);

Matthias Clasen's avatar
Matthias Clasen committed
357
  G_OBJECT_CLASS (gdk_display_parent_class)->dispose (object);
358
359
}

360
361
362
static void
gdk_display_finalize (GObject *object)
{
363
  GdkDisplay *display = GDK_DISPLAY (object);
364
365
366
367
368
369
370
371

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

372
  g_list_free_full (display->seats, g_object_unref);
373

Matthias Clasen's avatar
Matthias Clasen committed
374
  G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
375
376
377
378
}

/**
 * gdk_display_close:
379
380
381
 * @display: a `GdkDisplay`
 *
 * Closes the connection to the windowing system for the given display.
382
 *
383
 * This cleans up associated resources.
384
385
386
387
388
 */
void
gdk_display_close (GdkDisplay *display)
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
389
390
391
392

  if (!display->closed)
    {
      display->closed = TRUE;
393
394
      
      g_signal_emit (display, signals[CLOSED], 0, FALSE);
395
396
      g_object_run_dispose (G_OBJECT (display));
      
397
      g_object_unref (display);
398
    }
399
400
}

John Stowers's avatar
John Stowers committed
401
402
/**
 * gdk_display_is_closed:
403
 * @display: a `GdkDisplay`
John Stowers's avatar
John Stowers committed
404
 *
405
406
407
 * Finds out if the display has been closed.
 *
 * Returns: %TRUE if the display is closed.
John Stowers's avatar
John Stowers committed
408
409
410
411
412
413
414
415
416
 */
gboolean
gdk_display_is_closed  (GdkDisplay  *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);

  return display->closed;
}

417
/*<private>
418
 * gdk_display_get_event:
419
 * @display: a `GdkDisplay`
420
 *
Matthias Clasen's avatar
Matthias Clasen committed
421
422
 * Gets the next `GdkEvent` to be processed for @display,
 * fetching events from the windowing system if necessary.
423
 *
Matthias Clasen's avatar
Matthias Clasen committed
424
425
 * Returns: (nullable) (transfer full): the next `GdkEvent`
 *   to be processed
426
427
 */
GdkEvent *
428
429
430
gdk_display_get_event (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
431

432
433
  if (display->event_pause_count == 0)
    GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
434
435

  return _gdk_event_unqueue (display);
436
437
438
439
}

/**
 * gdk_display_put_event:
440
441
 * @display: a `GdkDisplay`
 * @event: (transfer none): a `GdkEvent`
442
 *
443
 * Appends the given event onto the front of the event
444
 * queue for @display.
445
446
447
 *
 * This function is only useful in very special situations
 * and should not be used by applications.
448
449
 **/
void
450
451
gdk_display_put_event (GdkDisplay *display,
                       GdkEvent   *event)
452
453
454
455
{
  g_return_if_fail (GDK_IS_DISPLAY (display));
  g_return_if_fail (event != NULL);

456
  _gdk_event_queue_append (display, gdk_event_ref ((GdkEvent *)event));
457
}
458

459
static void
Matthias Clasen's avatar
Matthias Clasen committed
460
generate_grab_broken_event (GdkDisplay *display,
461
                            GdkSurface  *surface,
Matthias Clasen's avatar
Matthias Clasen committed
462
463
                            GdkDevice  *device,
			    gboolean    implicit,
464
			    GdkSurface  *grab_surface)
465
{
466
  g_return_if_fail (surface != NULL);
467

468
  if (!GDK_SURFACE_DESTROYED (surface))
469
    {
470
471
      GdkEvent *event;

472
      event = gdk_grab_broken_event_new (surface,
473
474
475
                                         device,
                                         grab_surface,
                                         implicit);
476

477
      _gdk_event_queue_append (display, event);
478
479
480
    }
}

481
482
483
GdkDeviceGrabInfo *
_gdk_display_get_last_device_grab (GdkDisplay *display,
                                   GdkDevice  *device)
484
485
486
{
  GList *l;

487
  l = g_hash_table_lookup (display->device_grabs, device);
488

489
490
491
492
493
  if (l)
    {
      l = g_list_last (l);
      return l->data;
    }
494

495
496
  return NULL;
}
497

498
499
500
GdkDeviceGrabInfo *
_gdk_display_add_device_grab (GdkDisplay       *display,
                              GdkDevice        *device,
501
                              GdkSurface        *surface,
502
503
504
505
506
                              gboolean          owner_events,
                              GdkEventMask      event_mask,
                              unsigned long     serial_start,
                              guint32           time,
                              gboolean          implicit)
507
{
508
509
  GdkDeviceGrabInfo *info, *other_info;
  GList *grabs, *l;
510

511
  info = g_new0 (GdkDeviceGrabInfo, 1);
512

513
  info->surface = g_object_ref (surface);
514
515
516
517
518
519
  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;
520
521

  grabs = g_hash_table_lookup (display->device_grabs, device);
522
523
524
525

  /* 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 */
526
  for (l = grabs; l != NULL; l = l->next)
527
    {
528
      other_info = l->data;
529

530
531
532
      if (info->serial_start < other_info->serial_start)
	break;
    }
533
534

  grabs = g_list_insert_before (grabs, l, info);
535
536
537
538
539
540

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

543
  /* Find any previous grab and update its end time */
544
  l = g_list_find (grabs, info);
545
546
  l = l->prev;
  if (l)
547
    {
548
549
550
551
      other_info = l->data;
      other_info->serial_end = serial_start;
    }

552
  g_hash_table_insert (display->device_grabs, device, grabs);
553

554
  return info;
555
556
}

557
static GdkSurface *
558
559
560
561
get_current_toplevel (GdkDisplay      *display,
                      GdkDevice       *device,
                      int             *x_out,
                      int             *y_out,
562
563
		      GdkModifierType *state_out)
{
564
  GdkSurface *pointer_surface;
565
  double x, y;
566
567
  GdkModifierType state;

568
  pointer_surface = _gdk_device_surface_at_position (device, &x, &y, &state);
569

570
  if (pointer_surface != NULL &&
571
      GDK_SURFACE_DESTROYED (pointer_surface))
572
    pointer_surface = NULL;
573

574
575
  *x_out = round (x);
  *y_out = round (y);
576
  *state_out = state;
577

578
  return pointer_surface;
579
580
}

581
static void
582
583
584
585
586
587
switch_to_pointer_grab (GdkDisplay        *display,
                        GdkDevice         *device,
			GdkDeviceGrabInfo *grab,
			GdkDeviceGrabInfo *last_grab,
			guint32            time,
			gulong             serial)
588
{
589
590
  GdkSurface *new_toplevel;
  GdkPointerSurfaceInfo *info;
591
592
  GList *old_grabs;
  GdkModifierType state;
593
  int x = 0, y = 0;
594
595

  /* Temporarily unset pointer to make sure we send the crossing events below */
596
597
598
599
  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);

600
601
602
603
  if (grab)
    {
      /* New grab is in effect */
      if (!grab->implicit)
604
	{
605
606
607
	  /* !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)
608
	    _gdk_display_set_surface_under_pointer (display, device, NULL);
609
	}
610

611
612
      grab->activated = TRUE;
    }
613
614

  if (last_grab)
615
    {
616
617
618
619
620
      new_toplevel = NULL;

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

623
624
625
	  if (new_toplevel)
	    {
	      /* w is now toplevel and x,y in toplevel coords */
626
              _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
627
628
629
	      info->toplevel_x = x;
	      info->toplevel_y = y;
	      info->state = state;
630
631
632
633
	    }
	}

      if (grab == NULL) /* Ungrabbed, send events */
634
	{
635
636
	  /* We're now ungrabbed, update the surface_under_pointer */
	  _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
637
	}
638
639
    }

640
  g_hash_table_insert (display->device_grabs, device, old_grabs);
641
642
}

643
644
void
_gdk_display_update_last_event (GdkDisplay     *display,
Matthias Clasen's avatar
Matthias Clasen committed
645
                                GdkEvent       *event)
646
647
648
649
650
{
  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
    display->last_event_time = gdk_event_get_time (event);
}

651
void
652
653
654
_gdk_display_device_grab_update (GdkDisplay *display,
                                 GdkDevice  *device,
                                 gulong      current_serial)
655
{
656
657
  GdkDeviceGrabInfo *current_grab, *next_grab;
  GList *grabs;
658
  guint32 time;
659

660
  time = display->last_event_time;
661
  grabs = g_hash_table_lookup (display->device_grabs, device);
662

663
  while (grabs != NULL)
664
    {
665
      current_grab = grabs->data;
666

667
668
      if (current_grab->serial_start > current_serial)
	return; /* Hasn't started yet */
669

670
      if (current_grab->serial_end > current_serial)
671
672
673
	{
	  /* This one hasn't ended yet.
	     its the currently active one or scheduled to be active */
674

675
	  if (!current_grab->activated)
676
            {
677
              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
678
                switch_to_pointer_grab (display, device, current_grab, NULL, time, current_serial);
679
680
            }

681
682
683
684
	  break;
	}

      next_grab = NULL;
685
      if (grabs->next)
686
	{
687
	  /* This is the next active grab */
688
689
	  next_grab = grabs->next->data;

690
691
	  if (next_grab->serial_start > current_serial)
	    next_grab = NULL; /* Actually its not yet active */
692
693
	}

694
      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
695
696
          (next_grab != NULL && current_grab->surface != next_grab->surface))
        generate_grab_broken_event (display, GDK_SURFACE (current_grab->surface),
697
                                    device,
698
                                    current_grab->implicit,
699
                                    next_grab? next_grab->surface : NULL);
700

701
      /* Remove old grab */
702
703
704
      grabs = g_list_delete_link (grabs, grabs);
      g_hash_table_insert (display->device_grabs, device, grabs);

705
      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
706
        switch_to_pointer_grab (display, device,
707
708
709
710
                                next_grab, current_grab,
                                time, current_serial);

      free_device_grab (current_grab);
711
    }
712
713
714
}

static GList *
715
716
grab_list_find (GList  *grabs,
                gulong  serial)
717
{
718
  GdkDeviceGrabInfo *grab;
719

720
  while (grabs)
721
    {
722
      grab = grabs->data;
723

724
      if (serial >= grab->serial_start && serial < grab->serial_end)
725
726
727
	return grabs;

      grabs = grabs->next;
728
    }
729

730
731
732
  return NULL;
}

733
734
735
736
737
738
static GList *
find_device_grab (GdkDisplay *display,
                   GdkDevice  *device,
                   gulong      serial)
{
  GList *l;
739

740
741
742
  l = g_hash_table_lookup (display->device_grabs, device);
  return grab_list_find (l, serial);
}
743

744
745
746
747
GdkDeviceGrabInfo *
_gdk_display_has_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial)
748
749
750
{
  GList *l;

751
  l = find_device_grab (display, device, serial);
752
753
  if (l)
    return l->data;
754

755
756
757
  return NULL;
}

758
759
/* Returns true if last grab was ended
 * If if_child is non-NULL, end the grab only if the grabbed
760
 * surface is the same as if_child or a descendant of it */
761
gboolean
762
763
764
_gdk_display_end_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial,
765
                              GdkSurface  *if_child,
766
                              gboolean    implicit)
767
{
768
  GdkDeviceGrabInfo *grab;
769
770
  GList *l;

771
772
  l = find_device_grab (display, device, serial);

773
774
775
776
  if (l == NULL)
    return FALSE;

  grab = l->data;
777
  if (grab && (if_child == NULL || if_child == grab->surface))
778
779
780
781
782
783
784
    {
      grab->serial_end = serial;
      grab->implicit_ungrab = implicit;
      return l->next == NULL;
    }
  
  return FALSE;
785
786
}

787
GdkPointerSurfaceInfo *
788
789
_gdk_display_get_pointer_info (GdkDisplay *display,
                               GdkDevice  *device)
790
{
791
  GdkPointerSurfaceInfo *info;
792
  GdkSeat *seat;
793

794
795
796
797
798
799
800
  if (device)
    {
      seat = gdk_device_get_seat (device);

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

802
803
804
805
806
807
808
  if (G_UNLIKELY (!device))
    return NULL;

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

  if (G_UNLIKELY (!info))
    {
809
      info = g_slice_new0 (GdkPointerSurfaceInfo);
810
811
812
813
      g_hash_table_insert (display->pointers_info, device, info);
    }

  return info;
814
815
}

816
817
818
819
void
_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
                                   GdkDisplayPointerInfoForeach  func,
                                   gpointer                      user_data)
820
{
821
822
  GHashTableIter iter;
  gpointer key, value;
823

824
825
826
  g_hash_table_iter_init (&iter, display->pointers_info);

  while (g_hash_table_iter_next (&iter, &key, &value))
827
    {
828
      GdkPointerSurfaceInfo *info = value;
829
      GdkDevice *device = key;
830

831
      (func) (display, device, info, user_data);
832
833
    }
}
834

835
836
/*< private >
 * gdk_device_grab_info:
837
838
 * @display: the display for which to get the grab information
 * @device: device to get the grab information from
839
 * @grab_surface: (out) (transfer none): location to store current grab surface
840
 * @owner_events: (out): location to store boolean indicating whether
841
 *   the @owner_events flag to gdk_device_grab() was %TRUE.
842
843
 *
 * Determines information about the current keyboard grab.
844
 * This is not public API and must not be used by applications.
845
 *
846
 * Returns: %TRUE if this application currently has the
847
 *  keyboard grabbed.
848
 */
849
gboolean
850
851
gdk_device_grab_info (GdkDisplay  *display,
                      GdkDevice   *device,
852
                      GdkSurface  **grab_surface,
853
                      gboolean    *owner_events)
854
{
855
856
  GdkDeviceGrabInfo *info;

857
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
858
859
860
  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);

  info = _gdk_display_get_last_device_grab (display, device);
861

862
  if (info)
863
    {
864
865
      if (grab_surface)
        *grab_surface = info->surface;
866
      if (owner_events)
867
        *owner_events = info->owner_events;
868
869
870
871
872
873
874

      return TRUE;
    }
  else
    return FALSE;
}

875
876
/**
 * gdk_display_device_is_grabbed:
877
878
 * @display: a `GdkDisplay`
 * @device: a `GdkDevice`
879
880
881
882
 *
 * Returns %TRUE if there is an ongoing grab on @device for @display.
 *
 * Returns: %TRUE if there is a grab in effect for @device.
883
 */
884
885
886
887
888
889
gboolean
gdk_display_device_is_grabbed (GdkDisplay *display,
                               GdkDevice  *device)
{
  GdkDeviceGrabInfo *info;

890
  g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
891
  g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
892

893
894
895
  /* 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. */
896
897
  info = _gdk_display_get_last_device_grab (display, device);

898
  return (info && !info->implicit);
899
900
}

901
902
/**
 * gdk_display_get_name:
903
 * @display: a `GdkDisplay`
904
905
906
907
 *
 * Gets the name of the display.
 *
 * Returns: a string representing the display name. This string is owned
908
 *   by GDK and should not be modified or freed.
909
 */
Benjamin Otte's avatar
Benjamin Otte committed
910
const char *
911
912
gdk_display_get_name (GdkDisplay *display)
{
913
914
915
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_name (display);
916
917
918
919
}

/**
 * gdk_display_beep:
920
 * @display: a `GdkDisplay`
921
922
923
924
925
926
 *
 * Emits a short beep on @display
 */
void
gdk_display_beep (GdkDisplay *display)
{
927
928
929
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->beep (display);
930
931
932
933
}

/**
 * gdk_display_sync:
934
 * @display: a `GdkDisplay`
935
936
 *
 * Flushes any requests queued for the windowing system and waits until all
937
938
939
940
941
942
 * 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.
943
944
945
946
947
948
949
 *
 * 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)
{
950
951
952
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->sync (display);
953
954
955
956
}

/**
 * gdk_display_flush:
957
 * @display: a `GdkDisplay`
958
 *
959
960
961
962
963
 * 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
964
965
966
967
968
969
970
971
972
 * 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)
{
973
974
975
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->flush (display);
976
977
}

978
979
/**
 * gdk_display_get_clipboard:
980
 * @display: a `GdkDisplay`
981
982
983
 *
 * Gets the clipboard used for copy/paste operations.
 *
984
985
 * Returns: (transfer none): the display's clipboard
 */
986
987
988
989
990
991
992
993
994
995
996
997
998
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:
999
 * @display: a `GdkDisplay`
1000
 *
1001
1002
1003
1004
 * Gets the clipboard used for the primary selection.
 *
 * On backends where the primary clipboard is not supported natively,
 * GDK emulates this clipboard locally.
1005
 *
1006
1007
 * Returns: (transfer none): the primary clipboard
 */
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
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;
}

1019
/**
1020
 * gdk_display_supports_input_shapes: (attributes org.gtk.Method.get_property=input-shapes)
1021
 * @display: a `GdkDisplay`
1022
 *
1023
1024
1025
 * Returns %TRUE if the display supports input shapes.
 *
 * This means that [method@Gdk.Surface.set_input_region] can