display.c 91.2 KB
Newer Older
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2

Jasper St. Pierre's avatar
Jasper St. Pierre committed
3
/*
rhp's avatar
...  
rhp committed
4
 * Copyright (C) 2001 Havoc Pennington
5
 * Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
6
 * Copyright (C) 2003, 2004 Rob Adams
7
 * Copyright (C) 2004-2006 Elijah Newren
Jasper St. Pierre's avatar
Jasper St. Pierre committed
8
 *
rhp's avatar
...  
rhp committed
9
10
11
12
13
14
15
16
17
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
Jasper St. Pierre's avatar
Jasper St. Pierre committed
18
 *
rhp's avatar
...  
rhp committed
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
rhp's avatar
...  
rhp committed
21
22
 */

23
24
25
26
/**
 * SECTION:display
 * @title: MetaDisplay
 * @short_description: Mutter X display handler
27
 *
Jasper St. Pierre's avatar
Jasper St. Pierre committed
28
 * The display is represented as a #MetaDisplay struct.
29
30
 */

31
32
#define _XOPEN_SOURCE 600 /* for gethostname() */

33
#include <config.h>
34
#include "display-private.h"
35
#include "events.h"
36
#include "util-private.h"
37
#include <meta/main.h>
38
39
#include "screen-private.h"
#include "window-private.h"
40
41
#include "frame.h"
#include <meta/errors.h>
42
#include "keybindings-private.h"
43
#include <meta/prefs.h>
44
#include "workspace-private.h"
45
#include "bell.h"
46
#include <meta/compositor.h>
47
#include <meta/compositor-mutter.h>
rhp's avatar
...    
rhp committed
48
#include <X11/Xatom.h>
49
#include "mutter-enum-types.h"
50
#include "meta-idle-monitor-dbus.h"
51
#include "meta-cursor-tracker-private.h"
52
#include "meta-backend.h"
53
#include "backends/x11/meta-backend-x11.h"
54
#include <clutter/x11/clutter-x11.h>
55

56
57
58
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
59
#include <X11/extensions/shape.h>
60
#include <X11/Xcursor/Xcursor.h>
Iain Holmes's avatar
Iain Holmes committed
61
62
63
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xfixes.h>
64
#include <stdlib.h>
rhp's avatar
...    
rhp committed
65
#include <string.h>
66
#include <unistd.h>
rhp's avatar
...  
rhp committed
67

68
69
70
71
72
#include "x11/window-x11.h"
#include "x11/window-props.h"
#include "x11/group-props.h"
#include "x11/xprops.h"

73
#include "wayland/meta-xwayland-private.h"
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * SECTION:pings
 *
 * Sometimes we want to see whether a window is responding,
 * so we send it a "ping" message and see whether it sends us back a "pong"
 * message within a reasonable time. Here we have a system which lets us
 * nominate one function to be called if we get the pong in time and another
 * function if we don't. The system is rather more complicated than it needs
 * to be, since we only ever use it to destroy windows which are asked to
 * close themselves and don't do so within a reasonable amount of time, and
 * therefore we always use the same callbacks. It's possible that we might
 * use it for other things in future, or on the other hand we might decide
 * that we're never going to do so and simplify it a bit.
 */

/**
 * MetaPingData:
 *
 * Describes a ping on a window. When we send a ping to a window, we build
 * one of these structs, and it eventually gets passed to the timeout function
 * or to the function which handles the response from the window. If the window
 * does or doesn't respond to the ping, we use this information to deal with
 * these facts; we have a handler function for each.
 */
typedef struct
{
Jasper St. Pierre's avatar
Jasper St. Pierre committed
101
102
103
  MetaWindow *window;
  guint32     serial;
  guint       ping_timeout_id;
104
105
} MetaPingData;

106
107
G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);

108
109
110
111
/* Signals */
enum
{
  OVERLAY_KEY,
112
  ACCELERATOR_ACTIVATED,
113
  MODIFIERS_ACCELERATOR_ACTIVATED,
114
  FOCUS_WINDOW,
115
  WINDOW_CREATED,
116
  WINDOW_DEMANDS_ATTENTION,
117
  WINDOW_MARKED_URGENT,
118
119
  GRAB_OP_BEGIN,
  GRAB_OP_END,
120
121
  SHOW_RESTART_MESSAGE,
  RESTART,
122
123
124
  LAST_SIGNAL
};

125
126
127
128
129
130
enum {
  PROP_0,

  PROP_FOCUS_WINDOW
};

131
132
static guint display_signals [LAST_SIGNAL] = { 0 };

Jasper St. Pierre's avatar
Jasper St. Pierre committed
133
/*
134
135
136
137
138
139
 * The display we're managing.  This is a singleton object.  (Historically,
 * this was a list of displays, but there was never any way to add more
 * than one element to it.)  The goofy name is because we don't want it
 * to shadow the parameter in its object methods.
 */
static MetaDisplay *the_display = NULL;
140

141

142
static const char *gnome_wm_keybindings = "Mutter";
143
144
static const char *net_wm_name = "Mutter";

145
static void update_cursor_theme (void);
146
147
148
149
static void    update_window_grab_modifiers (MetaDisplay *display);

static void    prefs_changed_callback    (MetaPreference pref,
                                          void          *data);
150

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
static void
meta_display_get_property(GObject         *object,
                          guint            prop_id,
                          GValue          *value,
                          GParamSpec      *pspec)
{
  MetaDisplay *display = META_DISPLAY (object);

  switch (prop_id)
    {
    case PROP_FOCUS_WINDOW:
      g_value_set_object (value, display->focus_window);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
meta_display_set_property(GObject         *object,
                          guint            prop_id,
                          const GValue    *value,
                          GParamSpec      *pspec)
{
  switch (prop_id)
    {
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

184
185
186
static void
meta_display_class_init (MetaDisplayClass *klass)
{
187
188
189
190
191
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->get_property = meta_display_get_property;
  object_class->set_property = meta_display_set_property;

192
193
194
195
196
  display_signals[OVERLAY_KEY] =
    g_signal_new ("overlay-key",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
Jasper St. Pierre's avatar
Jasper St. Pierre committed
197
                  NULL, NULL, NULL,
198
199
                  G_TYPE_NONE, 0);

200
201
202
203
204
205
  display_signals[ACCELERATOR_ACTIVATED] =
    g_signal_new ("accelerator-activated",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  NULL, NULL, NULL,
206
                  G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
207

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  /**
   * MetaDisplay::modifiers-accelerator-activated:
   * @display: the #MetaDisplay instance
   *
   * The ::modifiers-accelerator-activated signal will be emitted when
   * a special modifiers-only keybinding is activated.
   *
   * Returns: %TRUE means that the keyboard device should remain
   *    frozen and %FALSE for the default behavior of unfreezing the
   *    keyboard.
   */
  display_signals[MODIFIERS_ACCELERATOR_ACTIVATED] =
    g_signal_new ("modifiers-accelerator-activated",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  g_signal_accumulator_first_wins, NULL, NULL,
                  G_TYPE_BOOLEAN, 0);

227
228
229
230
231
  display_signals[WINDOW_CREATED] =
    g_signal_new ("window-created",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
Jasper St. Pierre's avatar
Jasper St. Pierre committed
232
                  NULL, NULL, NULL,
233
234
                  G_TYPE_NONE, 1, META_TYPE_WINDOW);

235
236
237
238
239
  display_signals[WINDOW_DEMANDS_ATTENTION] =
    g_signal_new ("window-demands-attention",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
Jasper St. Pierre's avatar
Jasper St. Pierre committed
240
                  NULL, NULL, NULL,
241
                  G_TYPE_NONE, 1, META_TYPE_WINDOW);
242

243
244
245
246
247
  display_signals[WINDOW_MARKED_URGENT] =
    g_signal_new ("window-marked-urgent",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
Jasper St. Pierre's avatar
Jasper St. Pierre committed
248
                  NULL, NULL, NULL,
249
250
251
                  G_TYPE_NONE, 1,
                  META_TYPE_WINDOW);

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  display_signals[GRAB_OP_BEGIN] =
    g_signal_new ("grab-op-begin",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  NULL, NULL, NULL,
                  G_TYPE_NONE, 3,
                  META_TYPE_SCREEN,
                  META_TYPE_WINDOW,
                  META_TYPE_GRAB_OP);

  display_signals[GRAB_OP_END] =
    g_signal_new ("grab-op-end",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  NULL, NULL, NULL,
                  G_TYPE_NONE, 3,
                  META_TYPE_SCREEN,
                  META_TYPE_WINDOW,
                  META_TYPE_GRAB_OP);

274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  /**
   * MetaDisplay::show-restart-message:
   * @display: the #MetaDisplay instance
   * @message: (allow-none): The message to display, or %NULL
   *  to clear a previous restart message.
   *
   * The ::show-restart-message signal will be emitted to indicate
   * that the compositor should show a message during restart. This is
   * emitted when meta_restart() is called, either by Mutter
   * internally or by the embedding compositor.  The message should be
   * immediately added to the Clutter stage in its final form -
   * ::restart will be emitted to exit the application and leave the
   * stage contents frozen as soon as the the stage is painted again.
   *
   * On case of failure to restart, this signal will be emitted again
   * with %NULL for @message.
   *
   * Returns: %TRUE means the message was added to the stage; %FALSE
   *   indicates that the compositor did not show the message.
   */
  display_signals[SHOW_RESTART_MESSAGE] =
    g_signal_new ("show-restart-message",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  g_signal_accumulator_true_handled,
                  NULL, NULL,
                  G_TYPE_BOOLEAN, 1,
                  G_TYPE_STRING);

  /**
   * MetaDisplay::restart:
   * @display: the #MetaDisplay instance
   *
   * The ::restart signal is emitted to indicate that compositor
   * should reexec the process. This is
   * emitted when meta_restart() is called, either by Mutter
   * internally or by the embedding compositor. See also
   * ::show-restart-message.
   *
   * Returns: %FALSE to indicate that the compositor could not
   *  be restarted. When the compositor is restarted, the signal
   *  should not return.
   */
  display_signals[RESTART] =
    g_signal_new ("restart",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  g_signal_accumulator_true_handled,
                  NULL, NULL,
                  G_TYPE_BOOLEAN, 0);

327
328
329
330
331
332
333
  g_object_class_install_property (object_class,
                                   PROP_FOCUS_WINDOW,
                                   g_param_spec_object ("focus-window",
                                                        "Focus window",
                                                        "Currently focused window",
                                                        META_TYPE_WINDOW,
                                                        G_PARAM_READABLE));
334
335
}

336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

/**
 * ping_data_free:
 *
 * Destructor for #MetaPingData structs. Will destroy the
 * event source for the struct as well.
 */
static void
ping_data_free (MetaPingData *ping_data)
{
  /* Remove the timeout */
  if (ping_data->ping_timeout_id != 0)
    g_source_remove (ping_data->ping_timeout_id);

  g_free (ping_data);
}

353
354
355
void
meta_display_remove_pending_pings_for_window (MetaDisplay *display,
                                              MetaWindow  *window)
356
357
358
359
360
361
362
363
364
365
366
367
{
  GSList *tmp;
  GSList *dead;

  /* could obviously be more efficient, don't care */

  /* build list to be removed */
  dead = NULL;
  for (tmp = display->pending_pings; tmp; tmp = tmp->next)
    {
      MetaPingData *ping_data = tmp->data;

368
      if (ping_data->window == window)
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
        dead = g_slist_prepend (dead, ping_data);
    }

  /* remove what we found */
  for (tmp = dead; tmp; tmp = tmp->next)
    {
      MetaPingData *ping_data = tmp->data;

      display->pending_pings = g_slist_remove (display->pending_pings, ping_data);
      ping_data_free (ping_data);
    }

  g_slist_free (dead);
}


Havoc Pennington's avatar
Havoc Pennington committed
385
#ifdef HAVE_STARTUP_NOTIFICATION
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
static void
sn_error_trap_push (SnDisplay *sn_display,
                    Display   *xdisplay)
{
  MetaDisplay *display;
  display = meta_display_for_x_display (xdisplay);
  if (display != NULL)
    meta_error_trap_push (display);
}

static void
sn_error_trap_pop (SnDisplay *sn_display,
                   Display   *xdisplay)
{
  MetaDisplay *display;
  display = meta_display_for_x_display (xdisplay);
  if (display != NULL)
403
    meta_error_trap_pop (display);
404
}
Havoc Pennington's avatar
Havoc Pennington committed
405
#endif
406

Søren Sandmann's avatar
Søren Sandmann committed
407
static void
408
enable_compositor (MetaDisplay *display)
Søren Sandmann's avatar
Søren Sandmann committed
409
{
Iain Holmes's avatar
Iain Holmes committed
410
  if (!META_DISPLAY_HAS_COMPOSITE (display) ||
411
      !META_DISPLAY_HAS_DAMAGE (display))
Iain Holmes's avatar
Iain Holmes committed
412
    {
413
      meta_warning ("Missing %s extension required for compositing",
414
                    !META_DISPLAY_HAS_COMPOSITE (display) ? "composite" : "damage");
Iain Holmes's avatar
Iain Holmes committed
415
416
417
      return;
    }

Søren Sandmann's avatar
Søren Sandmann committed
418
419
420
421
422
  if (!display->compositor)
      display->compositor = meta_compositor_new (display);

  if (!display->compositor)
    return;
423

424
  meta_compositor_manage (display->compositor);
Søren Sandmann's avatar
Søren Sandmann committed
425
426
}

427
428
429
430
431
432
433
static void
meta_display_init (MetaDisplay *disp)
{
  /* Some stuff could go in here that's currently in _open,
   * but it doesn't really matter. */
}

434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
/**
 * meta_set_wm_name: (skip)
 * @wm_name: value for _NET_WM_NAME
 *
 * Set the value to use for the _NET_WM_NAME property. To take effect,
 * it is necessary to call this function before meta_init().
 */
void
meta_set_wm_name (const char *wm_name)
{
  g_return_if_fail (the_display == NULL);

  net_wm_name = wm_name;
}

/**
 * meta_set_gnome_wm_keybindings: (skip)
 * @wm_keybindings: value for _GNOME_WM_KEYBINDINGS
 *
 * Set the value to use for the _GNOME_WM_KEYBINDINGS property. To take
 * effect, it is necessary to call this function before meta_init().
 */
void
meta_set_gnome_wm_keybindings (const char *wm_keybindings)
{
  g_return_if_fail (the_display == NULL);

  gnome_wm_keybindings = wm_keybindings;
}

464
void
465
466
467
468
469
470
471
472
473
474
475
meta_display_cancel_touch (MetaDisplay *display)
{
  MetaWaylandCompositor *compositor;

  if (!meta_is_wayland_compositor ())
    return;

  compositor = meta_wayland_compositor_get_default ();
  meta_wayland_touch_cancel (&compositor->seat->touch);
}

476
477
478
479
480
481
static void
gesture_tracker_state_changed (MetaGestureTracker   *tracker,
                               ClutterEventSequence *sequence,
                               MetaSequenceState     state,
                               MetaDisplay          *display)
{
482
483
484
485
486
  if (meta_is_wayland_compositor ())
    {
      if (state == META_SEQUENCE_ACCEPTED)
        meta_display_cancel_touch (display);
    }
487
  else
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
    {
      MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
      int event_mode;

      if (state == META_SEQUENCE_ACCEPTED)
        event_mode = XIAcceptTouch;
      else if (state == META_SEQUENCE_REJECTED)
        event_mode = XIRejectTouch;
      else
        return;

      XIAllowTouchEvents (meta_backend_x11_get_xdisplay (backend),
                          META_VIRTUAL_CORE_POINTER_ID,
                          clutter_x11_event_sequence_get_touch_detail (sequence),
                          DefaultRootWindow (display->xdisplay), event_mode);
    }
504
505
}

506
/**
Jasper St. Pierre's avatar
Jasper St. Pierre committed
507
508
 * meta_display_open:
 *
509
 * Opens a new display, sets it up, initialises all the X extensions
510
511
 * we will need, and adds it to the list of displays.
 *
Jasper St. Pierre's avatar
Jasper St. Pierre committed
512
 * Returns: %TRUE if the display was opened successfully, and %FALSE
513
514
515
 * otherwise-- that is, if the display doesn't exist or it already
 * has a window manager.
 */
rhp's avatar
...  
rhp committed
516
gboolean
517
meta_display_open (void)
rhp's avatar
...  
rhp committed
518
{
519
  MetaDisplay *display;
rhp's avatar
...  
rhp committed
520
  Display *xdisplay;
521
  MetaScreen *screen;
522
  int i;
523
  guint32 timestamp;
524
525

  /* A list of all atom names, so that we can intern them in one go. */
rhp's avatar
...    
rhp committed
526
  char *atom_names[] = {
527
#define item(x) #x,
528
#include <meta/atomnames.h>
529
#undef item
rhp's avatar
...    
rhp committed
530
  };
rhp's avatar
...    
rhp committed
531
  Atom atoms[G_N_ELEMENTS(atom_names)];
Jasper St. Pierre's avatar
Jasper St. Pierre committed
532

533
  meta_verbose ("Opening display '%s'\n", XDisplayName (NULL));
rhp's avatar
...  
rhp committed
534

535
  xdisplay = meta_ui_get_display ();
Jasper St. Pierre's avatar
Jasper St. Pierre committed
536

rhp's avatar
...  
rhp committed
537
538
539
  if (xdisplay == NULL)
    {
      meta_warning (_("Failed to open X Window System display '%s'\n"),
540
		    XDisplayName (NULL));
rhp's avatar
...  
rhp committed
541
542
543
      return FALSE;
    }

544
545
546
  if (meta_is_wayland_compositor ())
    meta_xwayland_complete_init ();

rhp's avatar
...    
rhp committed
547
548
  if (meta_is_syncing ())
    XSynchronize (xdisplay, True);
Jasper St. Pierre's avatar
Jasper St. Pierre committed
549

550
  g_assert (the_display == NULL);
551
  display = the_display = g_object_new (META_TYPE_DISPLAY, NULL);
rhp's avatar
...    
rhp committed
552

553
  display->closing = 0;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
554

rhp's avatar
...    
rhp committed
555
556
557
558
  /* here we use XDisplayName which is what the user
   * probably put in, vs. DisplayString(display) which is
   * canonicalized by XOpenDisplay()
   */
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  display->name = g_strdup (XDisplayName (NULL));
  display->xdisplay = xdisplay;
  display->display_opening = TRUE;

  display->pending_pings = NULL;
  display->autoraise_timeout_id = 0;
  display->autoraise_window = NULL;
  display->focus_window = NULL;
  display->focus_serial = 0;
  display->server_focus_window = None;
  display->server_focus_serial = 0;

  display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
  display->allow_terminal_deactivation = TRUE; /* Only relevant for when a
573
                                                  terminal has the focus */
Jasper St. Pierre's avatar
Jasper St. Pierre committed
574

575
  meta_bell_init (display);
576

577
  meta_display_init_keys (display);
rhp's avatar
rhp committed
578

579
  update_window_grab_modifiers (display);
580

581
  meta_prefs_add_listener (prefs_changed_callback, display);
Iain Holmes's avatar
Iain Holmes committed
582

583
  meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names));
584
  XInternAtoms (display->xdisplay, atom_names, G_N_ELEMENTS (atom_names),
rhp's avatar
rhp committed
585
                False, atoms);
586
  {
Jasper St. Pierre's avatar
Jasper St. Pierre committed
587
    int i = 0;
588
#define item(x) display->atom_##x = atoms[i++];
589
#include <meta/atomnames.h>
590
591
#undef item
  }
592

593
594
595
596
  display->prop_hooks = NULL;
  meta_display_init_window_prop_hooks (display);
  display->group_prop_hooks = NULL;
  meta_display_init_group_prop_hooks (display);
Jasper St. Pierre's avatar
Jasper St. Pierre committed
597

rhp's avatar
...    
rhp committed
598
599
600
  /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK,
   * created in screen_new
   */
601
602
  display->leader_window = None;
  display->timestamp_pinging_window = None;
Havoc Pennington's avatar
Havoc Pennington committed
603

604
  display->monitor_cache_invalidated = TRUE;
605

606
  display->groups_by_leader = NULL;
607

608
  display->screen = NULL;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
609

610
#ifdef HAVE_STARTUP_NOTIFICATION
611
  display->sn_display = sn_display_new (display->xdisplay,
612
613
614
                                        sn_error_trap_push,
                                        sn_error_trap_pop);
#endif
rhp's avatar
...    
rhp committed
615
616

  /* Get events */
617
  meta_display_init_events (display);
618

619
  display->xids = g_hash_table_new (meta_unsigned_long_hash,
620
                                        meta_unsigned_long_equal);
621
  display->wayland_windows = g_hash_table_new (NULL, NULL);
622

623
  i = 0;
624
  while (i < N_IGNORED_CROSSING_SERIALS)
625
    {
626
      display->ignored_crossing_serials[i] = 0;
627
628
      ++i;
    }
629
  display->ungrab_should_not_cause_focus_window = None;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
630

631
632
  display->current_time = CurrentTime;
  display->sentinel_counter = 0;
633

634
635
  display->grab_resize_timeout_id = 0;
  display->grab_have_keyboard = FALSE;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
636
637

#ifdef HAVE_XKB
638
  display->last_bell_time = 0;
639
#endif
640

641
642
643
644
  display->grab_op = META_GRAB_OP_NONE;
  display->grab_window = NULL;
  display->grab_tile_mode = META_TILE_NONE;
  display->grab_tile_monitor_number = -1;
645

646
  display->grab_edge_resistance_data = NULL;
647

648
649
  {
    int major, minor;
650

651
    display->have_xsync = FALSE;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
652

653
654
    display->xsync_error_base = 0;
    display->xsync_event_base = 0;
655
656
657
658

    /* I don't think we really have to fill these in */
    major = SYNC_MAJOR_VERSION;
    minor = SYNC_MINOR_VERSION;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
659

660
661
662
663
    if (!XSyncQueryExtension (display->xdisplay,
                              &display->xsync_event_base,
                              &display->xsync_error_base) ||
        !XSyncInitialize (display->xdisplay,
664
665
                          &major, &minor))
      {
666
667
        display->xsync_error_base = 0;
        display->xsync_event_base = 0;
668
      }
669
    else
Owen W. Taylor's avatar
Owen W. Taylor committed
670
      {
671
672
        display->have_xsync = TRUE;
        XSyncSetPriority (display->xdisplay, None, 10);
Owen W. Taylor's avatar
Owen W. Taylor committed
673
674
      }

675
676
    meta_verbose ("Attempted to init Xsync, found version %d.%d error base %d event base %d\n",
                  major, minor,
677
678
                  display->xsync_error_base,
                  display->xsync_event_base);
679
  }
680
681

  {
682
    display->have_shape = FALSE;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
683

684
685
    display->shape_error_base = 0;
    display->shape_event_base = 0;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
686

687
688
689
    if (!XShapeQueryExtension (display->xdisplay,
                               &display->shape_event_base,
                               &display->shape_error_base))
690
      {
691
692
        display->shape_error_base = 0;
        display->shape_event_base = 0;
693
      }
694
    else
695
      display->have_shape = TRUE;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
696

697
    meta_verbose ("Attempted to init Shape, found error base %d event base %d\n",
698
699
                  display->shape_error_base,
                  display->shape_event_base);
700
  }
Havoc Pennington's avatar
Havoc Pennington committed
701

Iain Holmes's avatar
Iain Holmes committed
702
  {
703
    display->have_composite = FALSE;
Iain Holmes's avatar
Iain Holmes committed
704

705
706
    display->composite_error_base = 0;
    display->composite_event_base = 0;
Iain Holmes's avatar
Iain Holmes committed
707

708
709
710
    if (!XCompositeQueryExtension (display->xdisplay,
                                   &display->composite_event_base,
                                   &display->composite_error_base))
Iain Holmes's avatar
Iain Holmes committed
711
      {
712
713
        display->composite_error_base = 0;
        display->composite_event_base = 0;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
714
      }
Iain Holmes's avatar
Iain Holmes committed
715
    else
716
      {
717
718
719
720
721
        display->composite_major_version = 0;
        display->composite_minor_version = 0;
        if (XCompositeQueryVersion (display->xdisplay,
                                    &display->composite_major_version,
                                    &display->composite_minor_version))
722
          {
723
            display->have_composite = TRUE;
724
725
726
          }
        else
          {
727
728
            display->composite_major_version = 0;
            display->composite_minor_version = 0;
729
730
          }
      }
Iain Holmes's avatar
Iain Holmes committed
731

732
733
    meta_verbose ("Attempted to init Composite, found error base %d event base %d "
                  "extn ver %d %d\n",
734
735
736
737
                  display->composite_error_base,
                  display->composite_event_base,
                  display->composite_major_version,
                  display->composite_minor_version);
Iain Holmes's avatar
Iain Holmes committed
738

739
    display->have_damage = FALSE;
Iain Holmes's avatar
Iain Holmes committed
740

741
742
    display->damage_error_base = 0;
    display->damage_event_base = 0;
Iain Holmes's avatar
Iain Holmes committed
743

744
745
746
    if (!XDamageQueryExtension (display->xdisplay,
                                &display->damage_event_base,
                                &display->damage_error_base))
Iain Holmes's avatar
Iain Holmes committed
747
      {
748
749
        display->damage_error_base = 0;
        display->damage_event_base = 0;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
750
      }
Iain Holmes's avatar
Iain Holmes committed
751
    else
752
      display->have_damage = TRUE;
Iain Holmes's avatar
Iain Holmes committed
753
754

    meta_verbose ("Attempted to init Damage, found error base %d event base %d\n",
755
756
                  display->damage_error_base,
                  display->damage_event_base);
Iain Holmes's avatar
Iain Holmes committed
757

758
759
    display->xfixes_error_base = 0;
    display->xfixes_event_base = 0;
Iain Holmes's avatar
Iain Holmes committed
760

761
762
763
    if (XFixesQueryExtension (display->xdisplay,
                              &display->xfixes_event_base,
                              &display->xfixes_error_base))
Iain Holmes's avatar
Iain Holmes committed
764
      {
765
766
        int xfixes_major, xfixes_minor;

767
        XFixesQueryVersion (display->xdisplay, &xfixes_major, &xfixes_minor);
768
769
770
771

        if (xfixes_major * 100 + xfixes_minor < 500)
          meta_fatal ("Mutter requires XFixes 5.0");
      }
Iain Holmes's avatar
Iain Holmes committed
772
    else
773
774
775
      {
        meta_fatal ("Mutter requires XFixes 5.0");
      }
Iain Holmes's avatar
Iain Holmes committed
776
777

    meta_verbose ("Attempted to init XFixes, found error base %d event base %d\n",
778
779
                  display->xfixes_error_base,
                  display->xfixes_event_base);
Iain Holmes's avatar
Iain Holmes committed
780
  }
781
782

  {
Colin Walters's avatar
Colin Walters committed
783
    int major = 2, minor = 3;
784
785
    gboolean has_xi = FALSE;

786
    if (XQueryExtension (display->xdisplay,
787
                         "XInputExtension",
788
789
790
                         &display->xinput_opcode,
                         &display->xinput_error_base,
                         &display->xinput_event_base))
791
      {
792
        if (XIQueryVersion (display->xdisplay, &major, &minor) == Success)
793
794
795
796
797
798
799
          {
            int version = (major * 10) + minor;
            if (version >= 22)
              has_xi = TRUE;

#ifdef HAVE_XI23
            if (version >= 23)
800
              display->have_xinput_23 = TRUE;
801
802
#endif /* HAVE_XI23 */
          }
803
804
805
806
807
808
      }

    if (!has_xi)
      meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n");
  }

809
  update_cursor_theme ();
810

811
812
813
814
815
816
817
818
  /* Create the leader window here. Set its properties and
   * use the timestamp from one of the PropertyNotify events
   * that will follow.
   */
  {
    gulong data[1];
    XEvent event;

819
820
821
822
823
    /* We only care about the PropertyChangeMask in the next 30 or so lines of
     * code.  Note that gdk will at some point unset the PropertyChangeMask for
     * this window, so we can't rely on it still being set later.  See bug
     * 354213 for details.
     */
824
825
826
    display->leader_window =
      meta_create_offscreen_window (display->xdisplay,
                                    DefaultRootWindow (display->xdisplay),
827
                                    PropertyChangeMask);
828

829
830
831
    meta_prop_set_utf8_string_hint (display,
                                    display->leader_window,
                                    display->atom__NET_WM_NAME,
832
                                    net_wm_name);
833

834
835
836
    meta_prop_set_utf8_string_hint (display,
                                    display->leader_window,
                                    display->atom__GNOME_WM_KEYBINDINGS,
837
                                    gnome_wm_keybindings);
Jasper St. Pierre's avatar
Jasper St. Pierre committed
838

839
840
841
    meta_prop_set_utf8_string_hint (display,
                                    display->leader_window,
                                    display->atom__MUTTER_VERSION,
842
                                    VERSION);
843

844
845
846
847
    data[0] = display->leader_window;
    XChangeProperty (display->xdisplay,
                     display->leader_window,
                     display->atom__NET_SUPPORTING_WM_CHECK,
848
849
850
                     XA_WINDOW,
                     32, PropModeReplace, (guchar*) data, 1);

851
852
    XWindowEvent (display->xdisplay,
                  display->leader_window,
853
854
855
856
                  PropertyChangeMask,
                  &event);

    timestamp = event.xproperty.time;
857
858
859
860

    /* Make it painfully clear that we can't rely on PropertyNotify events on
     * this window, as per bug 354213.
     */
861
862
    XSelectInput(display->xdisplay,
                 display->leader_window,
863
                 NoEventMask);
864
865
  }

866
867
868
  /* Make a little window used only for pinging the server for timestamps; note
   * that meta_create_offscreen_window already selects for PropertyChangeMask.
   */
869
870
871
  display->timestamp_pinging_window =
    meta_create_offscreen_window (display->xdisplay,
                                  DefaultRootWindow (display->xdisplay),
872
                                  PropertyChangeMask);
873

874
875
876
  display->last_focus_time = timestamp;
  display->last_user_time = timestamp;
  display->compositor = NULL;
877

878
879
  /* Mutter used to manage all X screens of the display in a single process, but
   * now it always manages exactly one screen as specified by the DISPLAY
880
   * environment variable.
881
882
   */
  i = meta_ui_get_screen_number ();
883
  screen = meta_screen_new (display, i, timestamp);
884

885
  if (!screen)
886
887
888
889
    {
      /* This would typically happen because all the screens already
       * have window managers.
       */
890
      meta_display_close (display, timestamp);
891
892
      return FALSE;
    }
Iain Holmes's avatar
Iain Holmes committed
893

894
  display->screen = screen;
895

896
897
  meta_screen_init_workspaces (screen);

898
  enable_compositor (display);
899

900
901
  meta_screen_create_guard_window (screen);

902
  /* Set up touch support */
903
904
905
  display->gesture_tracker = meta_gesture_tracker_new ();
  g_signal_connect (display->gesture_tracker, "state-changed",
                    G_CALLBACK (gesture_tracker_state_changed), display);
906

907
908
909
910
911
  /* We know that if mutter is running as a Wayland compositor,
   * we start out with no windows.
   */
  if (!meta_is_wayland_compositor ())
    meta_screen_manage_all_windows (screen);
912
913
914
915
916
917

  {
    Window focus;
    int ret_to;

    /* kinda bogus because GetInputFocus has no possible errors */
918
    meta_error_trap_push (display);
919

920
    /* FIXME: This is totally broken; see comment 9 of bug 88194 about this */
921
    focus = None;
922
    ret_to = RevertToPointerRoot;
923
    XGetInputFocus (display->xdisplay, &focus, &ret_to);
924
925

    /* Force a new FocusIn (does this work?) */
926

927
928
929
    /* Use the same timestamp that was passed to meta_screen_new(),
     * as it is the most recent timestamp.
     */
930
    if (focus == None || focus == PointerRoot)
931
      /* Just focus the no_focus_window on the first screen */
932
933
      meta_display_focus_the_no_focus_window (display,
                                              display->screen,
934
                                              timestamp);
935
936
937
    else
      {
        MetaWindow * window;
938
        window  = meta_display_lookup_x_window (display, focus);
939
        if (window)
940
          meta_display_set_input_focus_window (display, window, FALSE, timestamp);
941
        else
942
          /* Just focus the no_focus_window on the first screen */
943
944
          meta_display_focus_the_no_focus_window (display,
                                                  display->screen,
945
                                                  timestamp);
946
947
      }

948
    meta_error_trap_pop (display);
949
  }
950
951
952

  meta_idle_monitor_init_dbus ();

953
  /* Done opening new display */
954
  display->display_opening = FALSE;
955

rhp's avatar
...  
rhp committed
956
957
958
  return TRUE;
}

rhp's avatar
...    
rhp committed
959
960
961
962
963
964
965
966
967
static gint
ptrcmp (gconstpointer a, gconstpointer b)
{
  if (a < b)
    return -1;
  else if (a > b)
    return 1;
  else
    return 0;
rhp's avatar
...  
rhp committed
968
969
}

970
971
972
973
974
975
976
977
978
979
980
/**
 * meta_display_list_windows:
 * @display: a #MetaDisplay
 * @flags: options for listing
 *
 * Lists windows for the display, the @flags parameter for
 * now determines whether override-redirect windows will be
 * included.
 *
 * Return value: (transfer container): the list of windows.
 */
rhp's avatar
...    
rhp committed
981
GSList*
982
983
meta_display_list_windows (MetaDisplay          *display,
                           MetaListWindowsFlags  flags)
rhp's avatar
...  
rhp committed
984
{
rhp's avatar
...    
rhp committed
985
  GSList *winlist;
rhp's avatar
...    
rhp committed
986
  GSList *prev;
987
  GSList *tmp;
988
989
990
  GHashTableIter iter;
  gpointer key, value;

rhp's avatar
...    
rhp committed
991
  winlist = NULL;
992

993
  g_hash_table_iter_init (&iter, display->xids);
994
995
996
997
  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      MetaWindow *window = value;

998
999
1000
      if (!META_IS_WINDOW (window))
        continue;

1001
1002
1003
1004
      if (!window->override_redirect ||
          (flags & META_LIST_INCLUDE_OVERRIDE_REDIRECT) != 0)
        winlist = g_slist_prepend (winlist, window);
    }
rhp's avatar
...    
rhp committed
1005

1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
  g_hash_table_iter_init (&iter, display->wayland_windows);
  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      MetaWindow *window = value;

      if (!META_IS_WINDOW (window))
        continue;

      if (!window->override_redirect ||
          (flags & META_LIST_INCLUDE_OVERRIDE_REDIRECT) != 0)
        winlist = g_slist_prepend (winlist, window);
    }

rhp's avatar
...    
rhp committed
1019
1020
1021
  /* Uniquify the list, since both frame windows and plain
   * windows are in the hash
   */
rhp's avatar
...    
rhp committed
1022
1023
  winlist = g_slist_sort (winlist, ptrcmp);

rhp's avatar
...    
rhp committed
1024
1025
1026
1027
1028
1029
1030
  prev = NULL;
  tmp = winlist;
  while (tmp != NULL)
    {
      GSList *next;

      next = tmp->next;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
1031

rhp's avatar
...    
rhp committed
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
      if (next &&
          next->data == tmp->data)
        {
          /* Delete tmp from list */

          if (prev)
            prev->next = next;

          if (tmp == winlist)
            winlist = next;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
1042

rhp's avatar
...    
rhp committed
1043
1044
1045
1046
1047
1048
1049
1050
          g_slist_free_1 (tmp);

          /* leave prev unchanged */
        }
      else
        {
          prev = tmp;
        }
Jasper St. Pierre's avatar
Jasper St. Pierre committed
1051

rhp's avatar
...    
rhp committed
1052
1053
1054
1055
1056
1057
1058
      tmp = next;
    }

  return winlist;
}

void
1059
1060
meta_display_close (MetaDisplay *display,
                    guint32      timestamp)
rhp's avatar
...    
rhp committed
1061
{
1062
  g_assert (display != NULL);
1063
  g_assert (display == the_display);
1064

1065
  if (display->closing != 0)
1066
    {
1067
      /* The display's already been closed. */
1068
1069
1070
      return;
    }

1071
  display->closing += 1;
1072
1073

  meta_prefs_remove_listener (prefs_changed_callback, display);
Jasper St. Pierre's avatar
Jasper St. Pierre committed
1074

1075
  meta_display_remove_autoraise_callback (display);
1076

1077
1078
  g_clear_object (&display->gesture_tracker);

1079
  if (display->focus_timeout_id)