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

22
#include "config.h"
23

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

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

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

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

41
42
/**
 * SECTION:gdkdisplay
43
 * @Short_description: Controls a set of monitors and their associated input devices
44
45
 * @Title: GdkDisplay
 *
46
 * GdkDisplay objects are the GDK representation of a workstation.
Matthias Clasen's avatar
Matthias Clasen committed
47
 *
48
49
50
 * Their purpose are two-fold:
 * - To manage and provide information about input devices (pointers, keyboards, etc)
 * - To manage and provide information about output devices (monitors, projectors, etc)
Matthias Clasen's avatar
Matthias Clasen committed
51
 *
52
53
54
55
56
 * Most of the input device handling has been factored out into separate #GdkSeat
 * objects. Every display has a one or more seats, which can be accessed with
 * gdk_display_get_default_seat() and gdk_display_list_seats().
 *
 * Output devices are represented by #GdkMonitor objects, which can be accessed
57
 * with gdk_display_get_monitor() and similar APIs.
58
59
 */

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

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

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

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

89

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

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

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

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
static void
gdk_display_get_property (GObject    *object,
                          guint       prop_id,
                          GValue     *value,
                          GParamSpec *pspec)
{
  GdkDisplay *display = GDK_DISPLAY (object);

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

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

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

118
119
120
121
122
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

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

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

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

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

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

  return display->seats->data;
}

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

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

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

172
173
174
  /**
   * GdkDisplay:composited:
   *
Yuri Chornoivan's avatar
Yuri Chornoivan committed
175
   * %TRUE if the display properly composites the alpha channel.
176
177
178
179
180
181
182
   * See gdk_display_is_composited() for details.
   */
  props[PROP_COMPOSITED] =
    g_param_spec_boolean ("composited",
                          P_("Composited"),
                          P_("Composited"),
                          TRUE,
183
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
184
185
186
187
188
189
190
191
192
193
194
195

  /**
   * GdkDisplay:rgba:
   *
   * %TRUE if the display supports an alpha channel. See gdk_display_is_rgba()
   * for details.
   */
  props[PROP_RGBA] =
    g_param_spec_boolean ("rgba",
                          P_("RGBA"),
                          P_("RGBA"),
                          TRUE,
196
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
197

198
199
200
201
202
203
204
205
206
207
208
209
210
  /**
   * GdkDisplay:input-shapes:
   *
   * %TRUE if the display supports input shapes. See
   * gdk_display_supports_input_shapes() for details.
   */
  props[PROP_INPUT_SHAPES] =
    g_param_spec_boolean ("input-shapes",
                          P_("Input shapes"),
                          P_("Input shapes"),
                          TRUE,
                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

211
212
  g_object_class_install_properties (object_class, LAST_PROP, props);

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

229
230
231
232
233
234
235
236
  /**
   * GdkDisplay::closed:
   * @display: the object on which the signal is emitted
   * @is_error: %TRUE if the display was closed due to an error
   *
   * The ::closed signal is emitted when the connection to the windowing
   * system for @display is closed.
   */   
237
  signals[CLOSED] =
Matthias Clasen's avatar
Matthias Clasen committed
238
    g_signal_new (g_intern_static_string ("closed"),
239
240
241
242
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkDisplayClass, closed),
		  NULL, NULL,
243
                  NULL,
244
245
246
		  G_TYPE_NONE,
		  1,
		  G_TYPE_BOOLEAN);
247
248
249
250
251
252
253
254
255
256
257
258
259
260

  /**
   * GdkDisplay::seat-added:
   * @display: the object on which the signal is emitted
   * @seat: the seat that was just added
   *
   * The ::seat-added signal is emitted whenever a new seat is made
   * known to the windowing system.
   */
  signals[SEAT_ADDED] =
    g_signal_new (g_intern_static_string ("seat-added"),
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL,
261
                  NULL,
262
263
264
265
266
		  G_TYPE_NONE, 1, GDK_TYPE_SEAT);

  /**
   * GdkDisplay::seat-removed:
   * @display: the object on which the signal is emitted
Matthias Clasen's avatar
Matthias Clasen committed
267
   * @seat: the seat that was just removed
268
269
270
271
272
273
274
275
276
   *
   * The ::seat-removed signal is emitted whenever a seat is removed
   * by the windowing system.
   */
  signals[SEAT_REMOVED] =
    g_signal_new (g_intern_static_string ("seat-removed"),
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL,
277
                  NULL,
278
		  G_TYPE_NONE, 1, GDK_TYPE_SEAT);
279

280
281
282
283
284
285
286
287
  /**
   * GdkDisplay::setting-changed:
   * @display: the object on which the signal is emitted
   * @setting: the name of the setting that changed
   *
   * The ::setting-changed signal is emitted whenever a setting
   * changes its value.
   */
288
289
290
291
292
293
294
  signals[SETTING_CHANGED] =
    g_signal_new (g_intern_static_string ("setting-changed"),
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  0, NULL, NULL,
                  NULL,
		  G_TYPE_NONE, 1, G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
295
296
}

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

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

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

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

  return TRUE;
}

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

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

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

334
335
  g_queue_init (&display->queued_events);

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

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

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

348
349
  _gdk_display_manager_remove_display (gdk_display_manager_get (), display);

350
  g_queue_clear (&display->queued_events);
351

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

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

  g_hash_table_foreach_remove (display->device_grabs,
                               free_device_grabs_foreach,
                               NULL);
  g_hash_table_destroy (display->device_grabs);

  g_hash_table_destroy (display->pointers_info);

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

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

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

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

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

  return display->closed;
}

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

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

  return _gdk_event_unqueue (display);
430
431
432
433
}

/**
 * gdk_display_peek_event:
Alexander Larsson's avatar
Alexander Larsson committed
434
 * @display: a #GdkDisplay 
435
 * 
436
 * Gets a copy of the first #GdkEvent in the @display’s event queue, without
437
438
439
440
 * removing the event from the queue.  (Note that this function will
 * not get more events from the windowing system.  It only checks the events
 * that have already been moved to the GDK event queue.)
 * 
441
442
 * Returns: (nullable) (transfer full): the first #GdkEvent on the
 *   event queue
443
 **/
444
GdkEvent *
445
446
447
448
449
450
451
452
gdk_display_peek_event (GdkDisplay *display)
{
  GList *tmp_list;

  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  tmp_list = _gdk_event_queue_find_first (display);
  
453
  if (tmp_list != NULL)
454
    return gdk_event_ref (tmp_list->data);
455
456

  return NULL;
457
458
459
460
461
}

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

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

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

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

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

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

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

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

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

516
517
  return NULL;
}
518

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

532
  info = g_new0 (GdkDeviceGrabInfo, 1);
533

534
  info->surface = g_object_ref (surface);
535
536
537
538
539
540
  info->serial_start = serial_start;
  info->serial_end = G_MAXULONG;
  info->owner_events = owner_events;
  info->event_mask = event_mask;
  info->time = time;
  info->implicit = implicit;
541
542

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

  /* Find the first grab that has a larger start time (if any) and insert
   * before that. I.E we insert after already existing grabs with same
   * start time */
547
  for (l = grabs; l != NULL; l = l->next)
548
    {
549
      other_info = l->data;
550

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

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

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

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

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

575
  return info;
576
577
}

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

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

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

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

599
  return pointer_surface;
600
601
}

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

  /* Temporarily unset pointer to make sure we send the crossing events below */
617
618
619
620
  old_grabs = g_hash_table_lookup (display->device_grabs, device);
  g_hash_table_steal (display->device_grabs, device);
  info = _gdk_display_get_pointer_info (display, device);

621
622
623
624
  if (grab)
    {
      /* New grab is in effect */
      if (!grab->implicit)
625
	{
626
627
628
	  /* !owner_event Grabbing a surface that we're not inside, current status is
	     now NULL (i.e. outside grabbed surface) */
	  if (!grab->owner_events && info->surface_under_pointer != grab->surface)
629
	    _gdk_display_set_surface_under_pointer (display, device, NULL);
630
	}
631

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

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

      if (grab == NULL /* ungrab */ ||
	  (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ )
	{
642
643
          /* Ungrabbed physical devices don't have a position by
           * itself, rather depend on its logical pointer, so
644
645
646
           * it doesn't make sense to track any position for
           * these after the grab
           */
647
          if (grab || gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_PHYSICAL)
648
649
            new_toplevel = get_current_toplevel (display, device, &x, &y, &state);

650
651
652
	  if (new_toplevel)
	    {
	      /* w is now toplevel and x,y in toplevel coords */
653
              _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
654
655
656
	      info->toplevel_x = x;
	      info->toplevel_y = y;
	      info->state = state;
657
658
659
660
	    }
	}

      if (grab == NULL) /* Ungrabbed, send events */
661
	{
662
663
	  /* We're now ungrabbed, update the surface_under_pointer */
	  _gdk_display_set_surface_under_pointer (display, device, new_toplevel);
664
	}
665
666
    }

667
  g_hash_table_insert (display->device_grabs, device, old_grabs);
668
669
}

670
671
void
_gdk_display_update_last_event (GdkDisplay     *display,
Matthias Clasen's avatar
Matthias Clasen committed
672
                                GdkEvent       *event)
673
674
675
676
677
{
  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
    display->last_event_time = gdk_event_get_time (event);
}

678
void
679
680
681
_gdk_display_device_grab_update (GdkDisplay *display,
                                 GdkDevice  *device,
                                 gulong      current_serial)
682
{
683
684
  GdkDeviceGrabInfo *current_grab, *next_grab;
  GList *grabs;
685
  guint32 time;
686

687
  time = display->last_event_time;
688
  grabs = g_hash_table_lookup (display->device_grabs, device);
689

690
  while (grabs != NULL)
691
    {
692
      current_grab = grabs->data;
693

694
695
      if (current_grab->serial_start > current_serial)
	return; /* Hasn't started yet */
696

697
      if (current_grab->serial_end > current_serial)
698
699
700
	{
	  /* This one hasn't ended yet.
	     its the currently active one or scheduled to be active */
701

702
	  if (!current_grab->activated)
703
            {
704
              if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
705
                switch_to_pointer_grab (display, device, current_grab, NULL, time, current_serial);
706
707
            }

708
709
710
711
	  break;
	}

      next_grab = NULL;
712
      if (grabs->next)
713
	{
714
	  /* This is the next active grab */
715
716
	  next_grab = grabs->next->data;

717
718
	  if (next_grab->serial_start > current_serial)
	    next_grab = NULL; /* Actually its not yet active */
719
720
	}

721
      if ((next_grab == NULL && current_grab->implicit_ungrab) ||
722
723
          (next_grab != NULL && current_grab->surface != next_grab->surface))
        generate_grab_broken_event (display, GDK_SURFACE (current_grab->surface),
724
                                    device,
725
                                    current_grab->implicit,
726
                                    next_grab? next_grab->surface : NULL);
727

728
      /* Remove old grab */
729
730
731
      grabs = g_list_delete_link (grabs, grabs);
      g_hash_table_insert (display->device_grabs, device, grabs);

732
      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
733
        switch_to_pointer_grab (display, device,
734
735
736
737
                                next_grab, current_grab,
                                time, current_serial);

      free_device_grab (current_grab);
738
    }
739
740
741
}

static GList *
742
743
grab_list_find (GList  *grabs,
                gulong  serial)
744
{
745
  GdkDeviceGrabInfo *grab;
746

747
  while (grabs)
748
    {
749
      grab = grabs->data;
750

751
      if (serial >= grab->serial_start && serial < grab->serial_end)
752
753
754
	return grabs;

      grabs = grabs->next;
755
    }
756

757
758
759
  return NULL;
}

760
761
762
763
764
765
static GList *
find_device_grab (GdkDisplay *display,
                   GdkDevice  *device,
                   gulong      serial)
{
  GList *l;
766

767
768
769
  l = g_hash_table_lookup (display->device_grabs, device);
  return grab_list_find (l, serial);
}
770

771
772
773
774
GdkDeviceGrabInfo *
_gdk_display_has_device_grab (GdkDisplay *display,
                              GdkDevice  *device,
                              gulong      serial)
775
776
777
{
  GList *l;

778
  l = find_device_grab (display, device, serial);
779
780
  if (l)
    return l->data;
781

782
783
784
  return NULL;
}

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

798
799
  l = find_device_grab (display, device, serial);

800
801
802
803
  if (l == NULL)
    return FALSE;

  grab = l->data;
804
  if (grab && (if_child == NULL || if_child == grab->surface))
805
806
807
808
809
810
811
    {
      grab->serial_end = serial;
      grab->implicit_ungrab = implicit;
      return l->next == NULL;
    }
  
  return FALSE;
812
813
}

814
GdkPointerSurfaceInfo *
815
816
_gdk_display_get_pointer_info (GdkDisplay *display,
                               GdkDevice  *device)
817
{
818
  GdkPointerSurfaceInfo *info;
819
  GdkSeat *seat;
820

821
822
823
824
825
826
827
  if (device)
    {
      seat = gdk_device_get_seat (device);

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

829
830
831
832
833
834
835
  if (G_UNLIKELY (!device))
    return NULL;

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

  if (G_UNLIKELY (!info))
    {
836
      info = g_slice_new0 (GdkPointerSurfaceInfo);
837
838
839
840
      g_hash_table_insert (display->pointers_info, device, info);
    }

  return info;
841
842
}

843
844
845
846
void
_gdk_display_pointer_info_foreach (GdkDisplay                   *display,
                                   GdkDisplayPointerInfoForeach  func,
                                   gpointer                      user_data)
847
{
848
849
  GHashTableIter iter;
  gpointer key, value;
850

851
852
853
  g_hash_table_iter_init (&iter, display->pointers_info);

  while (g_hash_table_iter_next (&iter, &key, &value))
854
    {
855
      GdkPointerSurfaceInfo *info = value;
856
      GdkDevice *device = key;
857

858
      (func) (display, device, info, user_data);
859
860
    }
}
861

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

884
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
885
886
887
  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);

  info = _gdk_display_get_last_device_grab (display, device);
888

889
  if (info)
890
    {
891
892
      if (grab_surface)
        *grab_surface = info->surface;
893
      if (owner_events)
894
        *owner_events = info->owner_events;
895
896
897
898
899
900
901

      return TRUE;
    }
  else
    return FALSE;
}

902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
/**
 * gdk_display_device_is_grabbed:
 * @display: a #GdkDisplay
 * @device: a #GdkDevice
 *
 * Returns %TRUE if there is an ongoing grab on @device for @display.
 *
 * Returns: %TRUE if there is a grab in effect for @device.
 **/
gboolean
gdk_display_device_is_grabbed (GdkDisplay *display,
                               GdkDevice  *device)
{
  GdkDeviceGrabInfo *info;

917
  g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
918
  g_return_val_if_fail (GDK_IS_DEVICE (device), TRUE);
919

920
921
922
  /* 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. */
923
924
  info = _gdk_display_get_last_device_grab (display, device);

925
  return (info && !info->implicit);
926
927
}

928
929
930
931
932
933
934
935
936
/**
 * gdk_display_get_name:
 * @display: a #GdkDisplay
 *
 * Gets the name of the display.
 *
 * Returns: a string representing the display name. This string is owned
 * by GDK and should not be modified or freed.
 */
Benjamin Otte's avatar
Benjamin Otte committed
937
const char *
938
939
gdk_display_get_name (GdkDisplay *display)
{
940
941
942
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

  return GDK_DISPLAY_GET_CLASS (display)->get_name (display);
943
944
945
946
947
948
949
950
951
952
953
}

/**
 * gdk_display_beep:
 * @display: a #GdkDisplay
 *
 * Emits a short beep on @display
 */
void
gdk_display_beep (GdkDisplay *display)
{
954
955
956
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->beep (display);
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
}

/**
 * gdk_display_sync:
 * @display: a #GdkDisplay
 *
 * Flushes any requests queued for the windowing system and waits until all
 * requests have been handled. This is often used for making sure that the
 * display is synchronized with the current state of the program. Calling
 * gdk_display_sync() before gdk_error_trap_pop() makes sure that any errors
 * generated from earlier requests are handled before the error trap is
 * removed.
 *
 * This is most useful for X11. On windowing systems where requests are
 * handled synchronously, this function will do nothing.
 */
void
gdk_display_sync (GdkDisplay *display)
{
976
977
978
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->sync (display);
979
980
981
982
983
984
985
986
987
}

/**
 * gdk_display_flush:
 * @display: a #GdkDisplay
 *
 * Flushes any requests queued for the windowing system; this happens automatically
 * when the main loop blocks waiting for new events, but if your application
 * is drawing without returning control to the main loop, you may need
988
 * to call this function explicitly. A common case where this function
989
990
991
992
993
994
995
996
997
 * 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)
{
998
999
1000
  g_return_if_fail (GDK_IS_DISPLAY (display));

  GDK_DISPLAY_GET_CLASS (display)->flush (display);
1001
1002
}

1003
1004
1005
1006
1007
1008
/**
 * gdk_display_get_clipboard:
 * @display: a #GdkDisplay
 *
 * Gets the clipboard used for copy/paste operations.
 *
1009
1010
 * Returns: (transfer none): the display's clipboard
 */
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
GdkClipboard *
gdk_display_get_clipboard (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

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

  return display->clipboard;
}

/**
 * gdk_display_get_primary_clipboard:
 * @display: a #GdkDisplay
 *
 * Gets the clipboard used for the primary selection. On backends where the
 * primary clipboard is not supported natively, GDK emulates this clipboard
 * locally.
 *
1030
1031
 * Returns: (transfer none): the primary clipboard
 */
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
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;
}

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

1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
  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]);
1074
1075
}

1076
1077
1078
1079
1080
static GdkAppLaunchContext *
gdk_display_real_get_app_launch_context (GdkDisplay *display)
{
  GdkAppLaunchContext *ctx;

1081
1082
1083
  ctx = g_object_new (GDK_TYPE_APP_LAUNCH_CONTEXT,
                      "display", display,
                      NULL);
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094

  return ctx;
}

/**
 * gdk_display_get_app_launch_context:
 * @display: a #GdkDisplay
 *
 * Returns a #GdkAppLaunchContext suitable for launching
 * applications on the given display.
 *
1095
 * Returns: (transfer full): a new #GdkAppLaunchContext for @display.
1096
1097
1098
1099
1100
 *     Free with g_object_unref() when done
 */
GdkAppLaunchContext *
gdk_display_get_app_launch_context (GdkDisplay *display)
{
1101
1102
1103
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);

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

1106
1107
1108
1109
1110
1111
/**
 * gdk_display_open:
 * @display_name: the name of the display to open
 *
 * Opens a display.
 *
1112
1113
 * Returns: (nullable) (transfer none): a #GdkDisplay, or %NULL if the
 *     display could not be opened
1114
1115
 */
GdkDisplay *
Benjamin Otte's avatar
Benjamin Otte committed
1116
gdk_display_open (const char *display_name)