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

rhp's avatar
...  
rhp committed
3 4
/* Metacity X display handler */

5
/*
rhp's avatar
...  
rhp committed
6
 * Copyright (C) 2001 Havoc Pennington
7
 * Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
8
 * Copyright (C) 2003, 2004 Rob Adams
9
 * Copyright (C) 2004-2006 Elijah Newren
10
 *
rhp's avatar
...  
rhp committed
11 12 13 14 15 16 17 18 19
 * 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.
20
 *
rhp's avatar
...  
rhp committed
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
rhp's avatar
...  
rhp committed
23 24
 */

25
/**
26
 * \file display.c Handles operations on an X display.
27 28 29 30
 *
 * The display is represented as a MetaDisplay struct.
 */

31 32
#include "config.h"

33
#include "display-private.h"
rhp's avatar
...  
rhp committed
34 35
#include "util.h"
#include "main.h"
36 37
#include "screen-private.h"
#include "window-private.h"
38
#include "window-props.h"
Havoc Pennington's avatar
Havoc Pennington committed
39
#include "group-props.h"
40
#include "frame-private.h"
rhp's avatar
...  
rhp committed
41
#include "errors.h"
rhp's avatar
...  
rhp committed
42
#include "keybindings.h"
43
#include "prefs.h"
44
#include "resizepopup.h"
45
#include "xprops.h"
rhp's avatar
...  
rhp committed
46
#include "workspace.h"
47
#include "bell.h"
48
#include "effects.h"
49
#include "meta-compositor.h"
50
#include <libmetacity/meta-frame-borders.h>
rhp's avatar
...  
rhp committed
51
#include <X11/Xatom.h>
rhp's avatar
...  
rhp committed
52
#include <X11/cursorfont.h>
53 54 55
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
56
#include <X11/extensions/shape.h>
57
#include <X11/extensions/Xrender.h>
58 59 60
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif
61 62 63
#ifdef HAVE_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif
Iain Holmes's avatar
Iain Holmes committed
64 65 66
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xfixes.h>
rhp's avatar
...  
rhp committed
67
#include <string.h>
rhp's avatar
...  
rhp committed
68

69 70
#include "compositor/meta-compositor-none.h"
#include "compositor/meta-compositor-xrender.h"
71
#include "compositor/meta-compositor-xpresent.h"
72
#include "compositor/meta-compositor-external.h"
73 74

#ifdef HAVE_VULKAN
75
#include "compositor/meta-compositor-vulkan.h"
76
#endif
77

78 79 80
#define GRAB_OP_IS_WINDOW_SWITCH(g)                     \
        (g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL  ||  \
         g == META_GRAB_OP_KEYBOARD_TABBING_DOCK    ||  \
81
         g == META_GRAB_OP_KEYBOARD_TABBING_GROUP   ||  \
82
         g == META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL ||  \
83 84
         g == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK   ||  \
         g == META_GRAB_OP_KEYBOARD_ESCAPING_GROUP)
85

86 87
/**
 * \defgroup pings Pings
88
 *
89 90 91 92 93 94 95 96 97 98 99 100
 * 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.
 */

101 102
/**
 * Describes a ping on a window. When we send a ping to a window, we build
103 104 105 106 107 108 109
 * 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.
 *
 * \ingroup pings
 */
110
typedef struct
Havoc Pennington's avatar
Havoc Pennington committed
111
{
112
  MetaDisplay *display;
113 114
  Window       xwindow;
  guint32      timestamp;
115 116
  MetaWindowPingFunc ping_reply_func;
  MetaWindowPingFunc ping_timeout_func;
117 118
  void        *user_data;
  guint        ping_timeout_id;
119 120
} MetaPingData;

121
typedef struct
Havoc Pennington's avatar
Havoc Pennington committed
122 123 124 125 126
{
  MetaDisplay *display;
  Window xwindow;
} MetaAutoRaiseData;

127 128 129 130 131 132 133
/**
 * 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;
134

135 136
static gboolean mousemods_disabled = FALSE;

rhp's avatar
...  
rhp committed
137 138
static void   meta_spew_event           (MetaDisplay    *display,
                                         XEvent         *event);
139

rhp's avatar
...  
rhp committed
140
static gboolean event_callback          (XEvent         *event,
rhp's avatar
...  
rhp committed
141 142 143
                                         gpointer        data);
static Window event_get_modified_window (MetaDisplay    *display,
                                         XEvent         *event);
144 145
static guint32 event_get_time           (MetaDisplay    *display,
                                         XEvent         *event);
146 147
static void    process_request_frame_extents (MetaDisplay    *display,
                                              XEvent         *event);
148 149
static void    process_pong_message     (MetaDisplay    *display,
                                         XEvent         *event);
Havoc Pennington's avatar
Havoc Pennington committed
150 151 152 153
static void    process_selection_request (MetaDisplay   *display,
                                          XEvent        *event);
static void    process_selection_clear   (MetaDisplay   *display,
                                          XEvent        *event);
rhp's avatar
...  
rhp committed
154

155 156
static void    update_window_grab_modifiers (MetaDisplay *display);

157 158 159
static void    set_mousemods_disabled (MetaDisplay *display,
                                       gboolean     setting);

160 161
static void    prefs_changed_callback    (MetaPreference pref,
                                          void          *data);
rhp's avatar
...  
rhp committed
162

163
static void    sanity_check_timestamps   (MetaDisplay *display,
164
                                          guint32      known_good_timestamp);
165

166 167
MetaGroup*     get_focussed_group (MetaDisplay *display);

168 169
/**
 * Destructor for MetaPingData structs. Will destroy the
170 171 172 173
 * event source for the struct as well.
 *
 * \ingroup pings
 */
174 175 176 177 178 179 180 181 182 183
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);
}

184 185
/**
 * Frees every pending ping structure for the given X window on the
186 187 188 189 190 191 192 193
 * given display. This means that we also destroy the timeouts.
 *
 * \param display The display the window appears on
 * \param xwindow The X ID of the window whose pings we should remove
 *
 * \ingroup pings
 *
 */
194 195 196 197 198 199 200
static void
remove_pending_pings_for_window (MetaDisplay *display, Window xwindow)
{
  GSList *tmp;
  GSList *dead;

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

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
  /* build list to be removed */
  dead = NULL;
  for (tmp = display->pending_pings; tmp; tmp = tmp->next)
    {
      MetaPingData *ping_data = tmp->data;

      if (ping_data->xwindow == xwindow)
        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);
}

224

Havoc Pennington's avatar
Havoc Pennington committed
225
#ifdef HAVE_STARTUP_NOTIFICATION
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
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)
Alberts Muktupāvels's avatar
Alberts Muktupāvels committed
243
    meta_error_trap_pop (display);
244
}
Havoc Pennington's avatar
Havoc Pennington committed
245
#endif
246

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
static void
reframe_func (MetaScreen *screen,
              MetaWindow *window,
              gpointer    user_data)
{
  meta_window_reframe (window);
}

static void
notify_composited_cb (MetaCompositor *compositor,
                      GParamSpec     *pspec,
                      MetaDisplay    *display)
{
  gboolean composited;

  meta_screen_foreach_window (display->screen, reframe_func, NULL);

  composited = meta_compositor_is_composited (display->compositor);
  meta_ui_set_composited (display->screen->ui, composited);
}

268 269
static MetaCompositorType
get_compositor_type (MetaDisplay *display)
Søren Sandmann's avatar
Søren Sandmann committed
270
{
271
  const gchar *compositor;
Alberts Muktupāvels's avatar
Alberts Muktupāvels committed
272 273
  MetaCompositorType type;

274
  compositor = g_getenv ("META_COMPOSITOR");
275

276 277 278 279 280 281
  if (compositor != NULL)
    {
      if (g_strcmp0 (compositor, "vulkan") == 0)
        type = META_COMPOSITOR_TYPE_VULKAN;
      else if (g_strcmp0 (compositor, "xrender") == 0)
        type = META_COMPOSITOR_TYPE_XRENDER;
282 283
      else if (g_strcmp0 (compositor, "xpresent") == 0)
        type = META_COMPOSITOR_TYPE_XPRESENT;
284 285
      else if (g_strcmp0 (compositor, "external") == 0)
        type = META_COMPOSITOR_TYPE_EXTERNAL;
286 287 288
      else
        type = META_COMPOSITOR_TYPE_NONE;
    }
Alberts Muktupāvels's avatar
Alberts Muktupāvels committed
289
  else
290
    {
291
      type = meta_prefs_get_compositor ();
292
    }
Søren Sandmann's avatar
Søren Sandmann committed
293

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
  return type;
}

static MetaCompositor *
create_compositor (MetaDisplay         *display,
                   MetaCompositorType   type,
                   GError             **error)
{
  MetaCompositor *compositor;

  compositor = NULL;

  switch (type)
    {
      case META_COMPOSITOR_TYPE_NONE:
        compositor = meta_compositor_none_new (display, error);
        break;

      case META_COMPOSITOR_TYPE_XRENDER:
        compositor = meta_compositor_xrender_new (display, error);
        break;

316 317 318 319
      case META_COMPOSITOR_TYPE_XPRESENT:
        compositor = meta_compositor_xpresent_new (display, error);
        break;

320 321 322 323
      case META_COMPOSITOR_TYPE_EXTERNAL:
        compositor = meta_compositor_external_new (display, error);
        break;

324
      case META_COMPOSITOR_TYPE_VULKAN:
325
#ifdef HAVE_VULKAN
326
        compositor = meta_compositor_vulkan_new (display, error);
327 328 329 330
#else
        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                             "Compiled without Vulkan support");
#endif
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
        break;

      default:
        g_assert_not_reached ();
        break;
    }

  return compositor;
}

static void
update_compositor (MetaDisplay *display,
                   gboolean     composite_windows)
{
  GError *error;
  gboolean old_composited;
  gboolean composited;

  old_composited = FALSE;
  if (display->compositor != NULL)
    {
      old_composited = meta_compositor_is_composited (display->compositor);
      g_object_unref (display->compositor);
    }

  error = NULL;
  display->compositor = create_compositor (display,
                                           get_compositor_type (display),
                                           &error);

  if (error != NULL)
    {
      g_warning ("Failed to create compositor: %s", error->message);
      g_error_free (error);

      g_assert (display->compositor == NULL);
      display->compositor = create_compositor (display,
                                               META_COMPOSITOR_TYPE_NONE,
                                               NULL);

      g_assert (display->compositor != NULL);
    }
373 374 375 376

  g_signal_connect (display->compositor, "notify::composited",
                    G_CALLBACK (notify_composited_cb), display);

377 378 379
  composited = meta_compositor_is_composited (display->compositor);
  meta_ui_set_composited (display->screen->ui, composited);

380 381
  if (old_composited != composited)
    meta_screen_foreach_window (display->screen, reframe_func, NULL);
382

383 384
  if (composite_windows)
    meta_screen_composite_all_windows (display->screen);
Søren Sandmann's avatar
Søren Sandmann committed
385 386
}

387 388
/**
 * Opens a new display, sets it up, initialises all the X extensions
389 390 391 392 393 394 395 396
 * we will need, and adds it to the list of displays.
 *
 * \return True if the display was opened successfully, and False
 * otherwise-- that is, if the display doesn't exist or it already
 * has a window manager.
 *
 * \ingroup main
 */
rhp's avatar
...  
rhp committed
397
gboolean
398
meta_display_open (void)
rhp's avatar
...  
rhp committed
399 400
{
  Display *xdisplay;
401
  int i;
402
  guint32 timestamp;
403
  MetaScreen *screen;
404
  Window old_active_xwindow;
405 406

  /* A list of all atom names, so that we can intern them in one go. */
407
  const gchar *atom_names[] = {
408 409 410
#define item(x) #x,
#include "atomnames.h"
#undef item
rhp's avatar
...  
rhp committed
411
  };
rhp's avatar
...  
rhp committed
412
  Atom atoms[G_N_ELEMENTS(atom_names)];
413

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

416
  xdisplay = meta_ui_get_display ();
417

rhp's avatar
...  
rhp committed
418 419
  if (xdisplay == NULL)
    {
420 421 422
      g_warning ("Failed to open X Window System display '%s'",
                 XDisplayName (NULL));

rhp's avatar
...  
rhp committed
423 424 425
      return FALSE;
    }

rhp's avatar
...  
rhp committed
426 427
  if (meta_is_syncing ())
    XSynchronize (xdisplay, True);
428

429 430
  g_assert (the_display == NULL);
  the_display = g_new (MetaDisplay, 1);
rhp's avatar
...  
rhp committed
431

432
  the_display->closing = 0;
433

rhp's avatar
...  
rhp committed
434 435 436 437
  /* here we use XDisplayName which is what the user
   * probably put in, vs. DisplayString(display) which is
   * canonicalized by XOpenDisplay()
   */
438 439 440 441 442 443 444 445 446 447 448 449
  the_display->name = g_strdup (XDisplayName (NULL));
  the_display->xdisplay = xdisplay;
  the_display->error_trap_synced_at_last_pop = TRUE;
  the_display->error_traps = 0;
  the_display->error_trap_handler = NULL;
  the_display->server_grab_count = 0;
  the_display->display_opening = TRUE;

  the_display->pending_pings = NULL;
  the_display->autoraise_timeout_id = 0;
  the_display->autoraise_window = NULL;
  the_display->focus_window = NULL;
450 451 452
  the_display->focus_serial = 0;
  the_display->server_focus_window = None;
  the_display->server_focus_serial = 0;
453 454 455 456
  the_display->grab_old_window_stacking = NULL;

  the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
  the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a
457
                                                  terminal has the focus */
458

459
  meta_bell_init (the_display);
460

461
  meta_display_init_keys (the_display);
rhp's avatar
rhp committed
462

463
  update_window_grab_modifiers (the_display);
464

465
  meta_prefs_add_listener (prefs_changed_callback, the_display);
Iain Holmes's avatar
Iain Holmes committed
466

467
  meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names));
468 469
  XInternAtoms (the_display->xdisplay, (gchar **) atom_names,
                G_N_ELEMENTS (atom_names), False, atoms);
470
  {
471 472
    int atom_i = 0;
#define item(x) the_display->atom_##x = atoms[atom_i++];
473 474 475
#include "atomnames.h"
#undef item
  }
476 477 478 479 480

  the_display->prop_hooks = NULL;
  meta_display_init_window_prop_hooks (the_display);
  the_display->group_prop_hooks = NULL;
  meta_display_init_group_prop_hooks (the_display);
481

rhp's avatar
...  
rhp committed
482 483 484
  /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK,
   * created in screen_new
   */
485 486
  the_display->leader_window = None;
  the_display->timestamp_pinging_window = None;
Havoc Pennington's avatar
Havoc Pennington committed
487

488
  the_display->monitor_cache_invalidated = TRUE;
489

490
  the_display->groups_by_leader = NULL;
491

492 493
  the_display->window_with_menu = NULL;
  the_display->window_menu = NULL;
494

495
  the_display->screen = NULL;
496

497
#ifdef HAVE_STARTUP_NOTIFICATION
498
  the_display->sn_display = sn_display_new (the_display->xdisplay,
499 500 501
                                        sn_error_trap_push,
                                        sn_error_trap_pop);
#endif
502

rhp's avatar
...  
rhp committed
503
  /* Get events */
504
  meta_ui_add_event_func (the_display->xdisplay,
rhp's avatar
...  
rhp committed
505
                          event_callback,
506
                          the_display);
507

508
  the_display->window_ids = g_hash_table_new (meta_unsigned_long_hash,
509
                                          meta_unsigned_long_equal);
510

511 512 513
  i = 0;
  while (i < N_IGNORED_SERIALS)
    {
514
      the_display->ignored_serials[i] = 0;
515 516
      ++i;
    }
517
  the_display->ungrab_should_not_cause_focus_window = None;
518

519 520
  the_display->current_time = CurrentTime;
  the_display->sentinel_counter = 0;
521

522 523
  the_display->grab_resize_timeout_id = 0;
  the_display->grab_have_keyboard = FALSE;
524 525

#ifdef HAVE_XKB
526
  the_display->last_bell_time = 0;
527
#endif
528

529 530 531 532
  the_display->grab_op = META_GRAB_OP_NONE;
  the_display->grab_window = NULL;
  the_display->grab_screen = NULL;
  the_display->grab_resize_popup = NULL;
Alberts Muktupāvels's avatar
Alberts Muktupāvels committed
533 534
  the_display->grab_tile_mode = META_TILE_NONE;
  the_display->grab_tile_monitor_number = -1;
535

536
  the_display->grab_edge_resistance_data = NULL;
537

538 539
  {
    int major, minor;
540

541
    the_display->have_xsync = FALSE;
542

543 544
    the_display->xsync_error_base = 0;
    the_display->xsync_event_base = 0;
545 546 547 548

    /* I don't think we really have to fill these in */
    major = SYNC_MAJOR_VERSION;
    minor = SYNC_MINOR_VERSION;
549

550 551 552 553
    if (!XSyncQueryExtension (the_display->xdisplay,
                              &the_display->xsync_event_base,
                              &the_display->xsync_error_base) ||
        !XSyncInitialize (the_display->xdisplay,
554 555
                          &major, &minor))
      {
556 557
        the_display->xsync_error_base = 0;
        the_display->xsync_event_base = 0;
558
      }
559
    else
Owen W. Taylor's avatar
Owen W. Taylor committed
560 561 562 563
      {
        the_display->have_xsync = TRUE;
        XSyncSetPriority (the_display->xdisplay, None, 10);
      }
564

565 566
    meta_verbose ("Attempted to init Xsync, found version %d.%d error base %d event base %d\n",
                  major, minor,
567 568
                  the_display->xsync_error_base,
                  the_display->xsync_event_base);
569
  }
570 571

  {
572
    the_display->have_shape = FALSE;
573

574 575
    the_display->shape_error_base = 0;
    the_display->shape_event_base = 0;
576

577 578 579
    if (!XShapeQueryExtension (the_display->xdisplay,
                               &the_display->shape_event_base,
                               &the_display->shape_error_base))
580
      {
581 582
        the_display->shape_error_base = 0;
        the_display->shape_event_base = 0;
583
      }
584
    else
585
      the_display->have_shape = TRUE;
586

587
    meta_verbose ("Attempted to init Shape, found error base %d event base %d\n",
588 589
                  the_display->shape_error_base,
                  the_display->shape_event_base);
590
  }
Havoc Pennington's avatar
Havoc Pennington committed
591

592
  {
593
    the_display->have_render = FALSE;
594

595 596
    the_display->render_error_base = 0;
    the_display->render_event_base = 0;
597

598 599 600
    if (!XRenderQueryExtension (the_display->xdisplay,
                                &the_display->render_event_base,
                                &the_display->render_error_base))
601
      {
602 603
        the_display->render_error_base = 0;
        the_display->render_event_base = 0;
604 605
      }
    else
606
      the_display->have_render = TRUE;
607

608
    meta_verbose ("Attempted to init Render, found error base %d event base %d\n",
609 610
                  the_display->render_error_base,
                  the_display->render_event_base);
611
  }
612

Iain Holmes's avatar
Iain Holmes committed
613
  {
614 615 616
    int composite_major_version = 0;
    int composite_minor_version = 0;

617
    the_display->have_composite = FALSE;
Iain Holmes's avatar
Iain Holmes committed
618

619 620
    the_display->composite_error_base = 0;
    the_display->composite_event_base = 0;
Iain Holmes's avatar
Iain Holmes committed
621

622 623 624
    if (!XCompositeQueryExtension (the_display->xdisplay,
                                   &the_display->composite_event_base,
                                   &the_display->composite_error_base))
Iain Holmes's avatar
Iain Holmes committed
625
      {
626 627
        the_display->composite_error_base = 0;
        the_display->composite_event_base = 0;
628
      }
Iain Holmes's avatar
Iain Holmes committed
629
    else
630
      {
631
        if (XCompositeQueryVersion (the_display->xdisplay,
632 633
                                    &composite_major_version,
                                    &composite_minor_version))
634
          {
635
            the_display->have_composite = TRUE;
636 637 638
          }
        else
          {
639 640
            composite_major_version = 0;
            composite_minor_version = 0;
641 642
          }
      }
Iain Holmes's avatar
Iain Holmes committed
643

644 645
    meta_verbose ("Attempted to init Composite, found error base %d event base %d "
                  "extn ver %d %d\n",
646
                  the_display->composite_error_base,
647
                  the_display->composite_event_base,
648 649
                  composite_major_version,
                  composite_minor_version);
Iain Holmes's avatar
Iain Holmes committed
650

651
    the_display->have_damage = FALSE;
Iain Holmes's avatar
Iain Holmes committed
652

653 654
    the_display->damage_error_base = 0;
    the_display->damage_event_base = 0;
Iain Holmes's avatar
Iain Holmes committed
655

656 657 658
    if (!XDamageQueryExtension (the_display->xdisplay,
                                &the_display->damage_event_base,
                                &the_display->damage_error_base))
Iain Holmes's avatar
Iain Holmes committed
659
      {
660 661
        the_display->damage_error_base = 0;
        the_display->damage_event_base = 0;
662
      }
Iain Holmes's avatar
Iain Holmes committed
663
    else
664
      the_display->have_damage = TRUE;
Iain Holmes's avatar
Iain Holmes committed
665 666

    meta_verbose ("Attempted to init Damage, found error base %d event base %d\n",
667
                  the_display->damage_error_base,
668
                  the_display->damage_event_base);
Iain Holmes's avatar
Iain Holmes committed
669

670
    the_display->have_xfixes = FALSE;
Iain Holmes's avatar
Iain Holmes committed
671

672 673
    the_display->xfixes_error_base = 0;
    the_display->xfixes_event_base = 0;
Iain Holmes's avatar
Iain Holmes committed
674

675 676 677
    if (!XFixesQueryExtension (the_display->xdisplay,
                               &the_display->xfixes_event_base,
                               &the_display->xfixes_error_base))
Iain Holmes's avatar
Iain Holmes committed
678
      {
679 680
        the_display->xfixes_error_base = 0;
        the_display->xfixes_event_base = 0;
681
      }
Iain Holmes's avatar
Iain Holmes committed
682
    else
683
      the_display->have_xfixes = TRUE;
Iain Holmes's avatar
Iain Holmes committed
684 685

    meta_verbose ("Attempted to init XFixes, found error base %d event base %d\n",
686
                  the_display->xfixes_error_base,
687
                  the_display->xfixes_event_base);
Iain Holmes's avatar
Iain Holmes committed
688
  }
689

690 691
#ifdef HAVE_XCURSOR
  {
692 693
    XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ());
    XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ());
694 695 696 697 698
  }
#else /* HAVE_XCURSOR */
  meta_verbose ("Not compiled with Xcursor support\n");
#endif /* !HAVE_XCURSOR */

699 700 701 702 703 704 705 706
  /* 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;

707 708 709 710 711
    /* 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.
     */
712 713 714
    the_display->leader_window =
      meta_create_offscreen_window (the_display->xdisplay,
                                    DefaultRootWindow (the_display->xdisplay),
715
                                    PropertyChangeMask);
716

717 718
    meta_prop_set_utf8_string_hint (the_display,
                                    the_display->leader_window,
719
                                    the_display->atom__NET_WM_NAME,
720
                                    "Metacity");
721

722 723
    meta_prop_set_utf8_string_hint (the_display,
                                    the_display->leader_window,
724
                                    the_display->atom__METACITY_VERSION,
725
                                    VERSION);
726

727 728 729
    data[0] = the_display->leader_window;
    XChangeProperty (the_display->xdisplay,
                     the_display->leader_window,
730
                     the_display->atom__NET_SUPPORTING_WM_CHECK,
731 732 733
                     XA_WINDOW,
                     32, PropModeReplace, (guchar*) data, 1);

734 735
    XWindowEvent (the_display->xdisplay,
                  the_display->leader_window,
736 737 738 739
                  PropertyChangeMask,
                  &event);

    timestamp = event.xproperty.time;
740 741 742 743

    /* Make it painfully clear that we can't rely on PropertyNotify events on
     * this window, as per bug 354213.
     */
744 745
    XSelectInput(the_display->xdisplay,
                 the_display->leader_window,
746
                 NoEventMask);
747 748
  }

749 750 751
  /* Make a little window used only for pinging the server for timestamps; note
   * that meta_create_offscreen_window already selects for PropertyChangeMask.
   */
752 753 754
  the_display->timestamp_pinging_window =
    meta_create_offscreen_window (the_display->xdisplay,
                                  DefaultRootWindow (the_display->xdisplay),
755
                                  PropertyChangeMask);
756

757 758 759
  the_display->last_focus_time = timestamp;
  the_display->last_user_time = timestamp;
  the_display->compositor = NULL;
760

761
  i = XDefaultScreen (the_display->xdisplay);
762
  screen = meta_screen_new (the_display, i, timestamp);
763
  the_display->screen = screen;
764

765
  if (screen == NULL)
766
    {
767 768
      /* This would typically happen because the screen already
       * have window manager.
769
       */
770
      meta_display_close (the_display, timestamp);
771 772
      return FALSE;
    }
Iain Holmes's avatar
Iain Holmes committed
773

774 775 776 777 778
  old_active_xwindow = None;
  meta_prop_get_window (the_display, the_display->screen->xroot,
                        the_display->atom__NET_ACTIVE_WINDOW,
                        &old_active_xwindow);

779 780
  /* We don't composite the windows here because they will be composited
     faster with the call to meta_screen_manage_all_windows further down
Iain Holmes's avatar
Iain Holmes committed
781
     the code */
Alberts Muktupāvels's avatar
Alberts Muktupāvels committed
782
  update_compositor (the_display, FALSE);
783

rhp's avatar
...  
rhp committed
784
  /* Now manage all existing windows */
785
  meta_screen_manage_all_windows (the_display->screen);
786

787 788 789
  if (old_active_xwindow != None)
    {
      MetaWindow *old_active_window;
790

791 792
      old_active_window = meta_display_lookup_x_window (the_display,
                                                        old_active_xwindow);
793

794 795 796 797 798 799
      if (old_active_window)
        {
          meta_window_focus (old_active_window, timestamp);
        }
      else
        {
800
          meta_display_focus_the_no_focus_window (the_display,
801
                                                  the_display->screen,
802
                                                  timestamp);
803 804 805 806 807 808 809 810
        }
    }
  else
    {
      meta_display_focus_the_no_focus_window (the_display,
                                              the_display->screen,
                                              timestamp);
    }
811

812
  /* Done opening new display */
813
  the_display->display_opening = FALSE;
814

rhp's avatar
...  
rhp committed
815 816 817
  return TRUE;
}

rhp's avatar
...  
rhp committed
818 819 820 821 822 823 824 825 826
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
827 828
}

rhp's avatar
...  
rhp committed
829
GSList*
830 831
meta_display_list_windows (MetaDisplay          *display,
                           MetaListWindowsFlags  flags)
rhp's avatar
...  
rhp committed
832
{
rhp's avatar
...  
rhp committed
833 834
  GSList *winlist;
  GSList *tmp;
rhp's avatar
...  
rhp committed
835
  GSList *prev;
836 837
  GHashTableIter iter;
  gpointer key, value;
838

rhp's avatar
...  
rhp committed
839
  winlist = NULL;
840 841 842 843 844 845 846 847 848
  g_hash_table_iter_init (&iter, display->window_ids);
  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      MetaWindow *window = value;

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

rhp's avatar
...  
rhp committed
850 851 852
  /* Uniquify the list, since both frame windows and plain
   * windows are in the hash
   */
rhp's avatar
...  
rhp committed
853 854
  winlist = g_slist_sort (winlist, ptrcmp);

rhp's avatar
...  
rhp committed
855 856 857 858 859 860 861
  prev = NULL;
  tmp = winlist;
  while (tmp != NULL)
    {
      GSList *next;

      next = tmp->next;
862

rhp's avatar
...  
rhp committed
863 864 865 866 867 868 869 870 871 872
      if (next &&
          next->data == tmp->data)
        {
          /* Delete tmp from list */

          if (prev)
            prev->next = next;

          if (tmp == winlist)
            winlist = next;
873

rhp's avatar
...  
rhp committed
874 875 876 877 878 879 880 881
          g_slist_free_1 (tmp);

          /* leave prev unchanged */
        }
      else
        {
          prev = tmp;
        }
882

rhp's avatar
...  
rhp committed
883 884 885 886 887 888
      tmp = next;
    }

  return winlist;
}

889 890 891 892 893 894 895 896 897 898 899 900 901 902
static void
meta_display_unmanage_windows (MetaDisplay *display,
                               guint32      timestamp)
{
  GSList *tmp;
  GSList *winlist;

  winlist = meta_display_list_windows (display, META_LIST_INCLUDE_OVERRIDE_REDIRECT);
  winlist = g_slist_sort (winlist, meta_display_stack_cmp);

  /* Unmanage all windows */
  tmp = winlist;
  while (tmp != NULL)
    {
903
      meta_window_unmanage (tmp->data, timestamp);
904 905 906 907 908 909

      tmp = tmp->next;
    }
  g_slist_free (winlist);
}

rhp's avatar
...  
rhp committed
910
void
911 912
meta_display_close (MetaDisplay *display,
                    guint32      timestamp)
rhp's avatar
...  
rhp committed
913
{
914 915
  g_assert (display != NULL);

916
  if (display->closing != 0)
917
    {
918
      /* The display's already been closed. */
919 920 921
      return;
    }

922
  if (display->error_traps > 0)
923
    g_error ("Display closed with error traps pending");
rhp's avatar
...  
rhp committed
924

</