compositor.c 44.1 KB
Newer Older
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3
4
5
6

/**
 * SECTION:compositor
 * @Title: MetaCompositor
 * @Short_Description: Compositor API
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 *
 * At a high-level, a window is not-visible or visible. When a
 * window is added (with meta_compositor_add_window()) it is not visible.
 * meta_compositor_show_window() indicates a transition from not-visible to
 * visible. Some of the reasons for this:
 *
 * - Window newly created
 * - Window is unminimized
 * - Window is moved to the current desktop
 * - Window was made sticky
 *
 * meta_compositor_hide_window() indicates that the window has transitioned from
 * visible to not-visible. Some reasons include:
 *
 * - Window was destroyed
 * - Window is minimized
 * - Window is moved to a different desktop
 * - Window no longer sticky.
 *
 * Note that combinations are possible - a window might have first
 * been minimized and then moved to a different desktop. The 'effect' parameter
 * to meta_compositor_show_window() and meta_compositor_hide_window() is a hint
 * as to the appropriate effect to show the user and should not
 * be considered to be indicative of a state change.
 *
 * When the active workspace is changed, meta_compositor_switch_workspace() is
 * called first, then meta_compositor_show_window() and
 * meta_compositor_hide_window() are called individually for each window
 * affected, with an effect of META_COMP_EFFECT_NONE.
 * If hiding windows will affect the switch workspace animation, the
 * compositor needs to delay hiding the windows until the switch
 * workspace animation completes.
 *
 * meta_compositor_maximize_window() and meta_compositor_unmaximize_window()
 * are transitions within the visible state. The window is resized __before__
 * the call, so it may be necessary to readjust the display based on the
 * old_rect to start the animation.
 *
45
46
 * # Containers #
 *
47
 * There's two containers in the stage that are used to place window actors, here
48
49
50
51
52
53
54
 * are listed in the order in which they are painted:
 *
 * - window group, accessible with meta_get_window_group_for_screen()
 * - top window group, accessible with meta_get_top_window_group_for_screen()
 *
 * Mutter will place actors representing windows in the window group, except for
 * override-redirect windows (ie. popups and menus) which will be placed in the
55
 * top window group.
56
 */
57

58
59
#include <config.h>

60
#include <clutter/x11/clutter-x11.h>
61

62
#include "core.h"
63
64
65
#include <meta/screen.h>
#include <meta/errors.h>
#include <meta/window.h>
66
#include "compositor-private.h"
67
68
#include <meta/compositor-mutter.h>
#include <meta/prefs.h>
69
#include <meta/main.h>
70
71
#include <meta/meta-background-actor.h>
#include <meta/meta-background-group.h>
72
#include <meta/meta-shadow-factory.h>
73
74
#include "meta-window-actor-private.h"
#include "meta-window-group.h"
75
#include "meta-stage.h"
76
#include "window-private.h" /* to check window->hidden */
77
#include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */
78
#include "util-private.h"
79
#include "frame.h"
80
81
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
82

83
#include "backends/meta-backend.h"
84
85
#include "backends/x11/meta-backend-x11.h"

86
87
#include "wayland/meta-wayland-private.h"

88
89
90
91
92
93
static gboolean
is_modal (MetaDisplay *display)
{
  return display->grab_op == META_GRAB_OP_COMPOSITOR;
}

94
static inline gboolean
95
composite_at_least_version (MetaDisplay *display, int maj, int min)
96
97
98
99
100
101
{
  static int major = -1;
  static int minor = -1;

  if (major == -1)
    meta_display_get_compositor_version (display, &major, &minor);
Tomas Frydrych's avatar
Tomas Frydrych committed
102

103
104
105
  return (major > maj || (major == maj && minor >= min));
}

106
static void sync_actor_stacking (MetaCompositor *compositor);
107

108
static void
109
meta_finish_workspace_switch (MetaCompositor *compositor)
110
{
111
  GList *l;
112

113
  /* Finish hiding and showing actors for the new workspace */
114
  for (l = compositor->windows; l; l = l->next)
115
    meta_window_actor_sync_visibility (l->data);
116

Jasper St. Pierre's avatar
Jasper St. Pierre committed
117
  /* Fix up stacking order. */
118
  sync_actor_stacking (compositor);
119
}
120

121
void
122
meta_switch_workspace_completed (MetaCompositor *compositor)
123
{
124
  /* FIXME -- must redo stacking order */
125
126
  compositor->switch_workspace_in_progress--;
  if (compositor->switch_workspace_in_progress < 0)
127
    {
128
      g_warning ("Error in workspace_switch accounting!");
129
      compositor->switch_workspace_in_progress = 0;
130
    }
131

132
133
  if (!compositor->switch_workspace_in_progress)
    meta_finish_workspace_switch (compositor);
134
135
136
137
138
}

void
meta_compositor_destroy (MetaCompositor *compositor)
{
139
  clutter_threads_remove_repaint_func (compositor->repaint_func_id);
140
141
142
}

static void
143
process_damage (MetaCompositor     *compositor,
144
145
                XDamageNotifyEvent *event,
                MetaWindow         *window)
146
{
Jasper St. Pierre's avatar
Jasper St. Pierre committed
147
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
148
  meta_window_actor_process_x11_damage (window_actor, event);
149
150

  compositor->frame_has_updated_xsurfaces = TRUE;
151
152
}

153
154
155
156
157
158
159
/* compat helper */
static MetaCompositor *
get_compositor_for_screen (MetaScreen *screen)
{
  return screen->display->compositor;
}

160
/**
161
 * meta_get_stage_for_screen:
162
163
164
165
 * @screen: a #MetaScreen
 *
 * Returns: (transfer none): The #ClutterStage for the screen
 */
166
ClutterActor *
167
meta_get_stage_for_screen (MetaScreen *screen)
168
{
169
170
  MetaCompositor *compositor = get_compositor_for_screen (screen);
  return compositor->stage;
171
172
}

173
/**
174
 * meta_get_window_group_for_screen:
175
176
177
178
 * @screen: a #MetaScreen
 *
 * Returns: (transfer none): The window group corresponding to @screen
 */
179
ClutterActor *
180
meta_get_window_group_for_screen (MetaScreen *screen)
181
{
182
183
  MetaCompositor *compositor = get_compositor_for_screen (screen);
  return compositor->window_group;
184
185
}

186
187
188
189
190
191
192
193
194
/**
 * meta_get_top_window_group_for_screen:
 * @screen: a #MetaScreen
 *
 * Returns: (transfer none): The top window group corresponding to @screen
 */
ClutterActor *
meta_get_top_window_group_for_screen (MetaScreen *screen)
{
195
196
  MetaCompositor *compositor = get_compositor_for_screen (screen);
  return compositor->top_window_group;
197
198
}

199
/**
200
 * meta_get_window_actors:
201
202
 * @screen: a #MetaScreen
 *
203
 * Returns: (transfer none) (element-type Clutter.Actor): The set of #MetaWindowActor on @screen
204
 */
205
GList *
206
meta_get_window_actors (MetaScreen *screen)
207
{
208
209
  MetaCompositor *compositor = get_compositor_for_screen (screen);
  return compositor->windows;
210
}
211

212
void
213
214
meta_set_stage_input_region (MetaScreen   *screen,
                             XserverRegion region)
215
{
216
217
218
219
220
221
  /* As a wayland compositor we can simply ignore all this trickery
   * for setting an input region on the stage for capturing events in
   * clutter since all input comes to us first and we get to choose
   * who else sees them.
   */
  if (!meta_is_wayland_compositor ())
222
    {
223
224
225
226
      MetaDisplay *display = screen->display;
      MetaCompositor *compositor = display->compositor;
      Display *xdpy = meta_display_get_xdisplay (display);
      Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
227

228
229
230
231
232
233
234
      XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region);

      /* It's generally a good heuristic that when a crossing event is generated because
       * we reshape the overlay, we don't want it to affect focus-follows-mouse focus -
       * it's not the user doing something, it's the environment changing under the user.
       */
      meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
235
      XFixesSetWindowShapeRegion (xdpy, compositor->output, ShapeInput, 0, 0, region);
236
    }
237
238
239
}

void
240
meta_empty_stage_input_region (MetaScreen *screen)
241
242
243
244
245
246
247
248
249
250
251
252
{
  /* Using a static region here is a bit hacky, but Metacity never opens more than
   * one XDisplay, so it works fine. */
  static XserverRegion region = None;

  if (region == None)
    {
      MetaDisplay  *display = meta_screen_get_display (screen);
      Display      *xdpy    = meta_display_get_xdisplay (display);
      region = XFixesCreateRegion (xdpy, NULL, 0);
    }

253
  meta_set_stage_input_region (screen, region);
254
255
}

256
257
258
259
260
261
262
263
264
265
266
void
meta_focus_stage_window (MetaScreen *screen,
                         guint32     timestamp)
{
  ClutterStage *stage;
  Window window;

  stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
  if (!stage)
    return;

267
  window = clutter_x11_get_stage_window (stage);
268

269
270
  if (window == None)
    return;
271

272
273
274
275
  meta_display_set_input_focus_xwindow (screen->display,
                                        screen,
                                        window,
                                        timestamp);
276
277
}

278
279
280
281
gboolean
meta_stage_is_focused (MetaScreen *screen)
{
  ClutterStage *stage;
282
  Window window;
283

284
285
286
  if (meta_is_wayland_compositor ())
    return TRUE;

287
288
289
290
  stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
  if (!stage)
    return FALSE;

291
292
293
294
295
296
  window = clutter_x11_get_stage_window (stage);

  if (window == None)
    return FALSE;

  return (screen->display->focus_xwindow == window);
297
298
}

299
static gboolean
300
301
grab_devices (MetaModalOptions  options,
              guint32           timestamp)
Owen W. Taylor's avatar
Owen W. Taylor committed
302
{
303
304
305
  MetaBackend *backend = META_BACKEND (meta_get_backend ());
  gboolean pointer_grabbed = FALSE;
  gboolean keyboard_grabbed = FALSE;
Owen W. Taylor's avatar
Owen W. Taylor committed
306
307
308

  if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
    {
309
      if (!meta_backend_grab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp))
Owen W. Taylor's avatar
Owen W. Taylor committed
310
311
312
313
314
315
316
        goto fail;

      pointer_grabbed = TRUE;
    }

  if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
    {
317
      if (!meta_backend_grab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp))
Owen W. Taylor's avatar
Owen W. Taylor committed
318
319
320
321
322
323
324
325
326
        goto fail;

      keyboard_grabbed = TRUE;
    }

  return TRUE;

 fail:
  if (pointer_grabbed)
327
    meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp);
Owen W. Taylor's avatar
Owen W. Taylor committed
328
  if (keyboard_grabbed)
329
    meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
Owen W. Taylor's avatar
Owen W. Taylor committed
330
331
332
333

  return FALSE;
}

334
gboolean
335
meta_begin_modal_for_plugin (MetaCompositor   *compositor,
336
337
338
339
340
341
342
343
                             MetaPlugin       *plugin,
                             MetaModalOptions  options,
                             guint32           timestamp)
{
  /* To some extent this duplicates code in meta_display_begin_grab_op(), but there
   * are significant differences in how we handle grabs that make it difficult to
   * merge the two.
   */
344
  MetaDisplay *display = compositor->display;
345

346
  if (is_modal (display) || display->grab_op != META_GRAB_OP_NONE)
347
348
    return FALSE;

349
350
351
352
353
354
  /* XXX: why is this needed? */
  XIUngrabDevice (display->xdisplay,
                  META_VIRTUAL_CORE_POINTER_ID,
                  timestamp);
  XSync (display->xdisplay, False);

355
356
  if (!grab_devices (options, timestamp))
    return FALSE;
357
358
359
360
361
362

  display->grab_op = META_GRAB_OP_COMPOSITOR;
  display->grab_window = NULL;
  display->grab_have_pointer = TRUE;
  display->grab_have_keyboard = TRUE;

363
364
365
366
  g_signal_emit_by_name (display, "grab-op-begin",
                         meta_plugin_get_screen (plugin),
                         display->grab_window, display->grab_op);

367
  if (meta_is_wayland_compositor ())
368
369
370
371
    {
      meta_display_sync_wayland_input_focus (display);
      meta_display_cancel_touch (display);
    }
372

373
374
375
  return TRUE;
}

Owen W. Taylor's avatar
Owen W. Taylor committed
376
void
377
meta_end_modal_for_plugin (MetaCompositor *compositor,
378
379
                           MetaPlugin     *plugin,
                           guint32         timestamp)
Owen W. Taylor's avatar
Owen W. Taylor committed
380
{
381
  MetaDisplay *display = compositor->display;
382
  MetaBackend *backend = meta_get_backend ();
Owen W. Taylor's avatar
Owen W. Taylor committed
383

384
  g_return_if_fail (is_modal (display));
Owen W. Taylor's avatar
Owen W. Taylor committed
385

386
387
388
389
  g_signal_emit_by_name (display, "grab-op-end",
                         meta_plugin_get_screen (plugin),
                         display->grab_window, display->grab_op);

Owen W. Taylor's avatar
Owen W. Taylor committed
390
391
392
393
  display->grab_op = META_GRAB_OP_NONE;
  display->grab_window = NULL;
  display->grab_have_pointer = FALSE;
  display->grab_have_keyboard = FALSE;
394

395
396
397
  meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp);
  meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);

398
  if (meta_is_wayland_compositor ())
399
    meta_display_sync_wayland_input_focus (display);
Owen W. Taylor's avatar
Owen W. Taylor committed
400
401
}

402
403
404
static void
after_stage_paint (ClutterStage *stage,
                   gpointer      data)
405
{
406
  MetaCompositor *compositor = data;
407
408
  GList *l;

409
  for (l = compositor->windows; l; l = l->next)
410
    meta_window_actor_post_paint (l->data);
411

412
413
  if (meta_is_wayland_compositor ())
    meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ());
414
415
}

416
static void
417
redirect_windows (MetaScreen *screen)
418
{
419
420
421
422
423
424
  MetaDisplay *display       = meta_screen_get_display (screen);
  Display     *xdisplay      = meta_display_get_xdisplay (display);
  Window       xroot         = meta_screen_get_xroot (screen);
  int          screen_number = meta_screen_get_screen_number (screen);
  guint        n_retries;
  guint        max_retries;
425

426
427
428
429
  if (meta_get_replace_current_wm ())
    max_retries = 5;
  else
    max_retries = 1;
430

431
432
  n_retries = 0;

433
434
435
  /* Some compositors (like old versions of Mutter) might not properly unredirect
   * subwindows before destroying the WM selection window; so we wait a while
   * for such a compositor to exit before giving up.
436
437
   */
  while (TRUE)
438
    {
439
      meta_error_trap_push (display);
440
441
442
443
444
445
446
      XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
      XSync (xdisplay, FALSE);

      if (!meta_error_trap_pop_with_return (display))
        break;

      if (n_retries == max_retries)
447
448
449
450
451
452
        {
          /* This probably means that a non-WM compositor like xcompmgr is running;
           * we have no way to get it to exit */
          meta_fatal (_("Another compositing manager is already running on screen %i on display \"%s\"."),
                      screen_number, display->name);
        }
453
454
455

      n_retries++;
      g_usleep (G_USEC_PER_SEC);
456
    }
457
458
459
}

void
460
meta_compositor_manage (MetaCompositor *compositor)
461
{
462
463
464
  MetaDisplay *display = compositor->display;
  Display *xdisplay = display->xdisplay;
  MetaScreen *screen = display->screen;
465
  Window xwin = 0;
466
  gint width, height;
467

468
  meta_screen_set_cm_selection (display->screen);
469

470
471
  if (meta_is_wayland_compositor ())
    {
472
473
      MetaWaylandCompositor *wayland_compositor = meta_wayland_compositor_get_default ();

474
      compositor->stage = meta_stage_new ();
475
476

      wayland_compositor->stage = compositor->stage;
477
478

      meta_screen_get_size (screen, &width, &height);
479
      clutter_actor_set_size (compositor->stage, width, height);
480
      clutter_actor_show (compositor->stage);
481
482
483
    }
  else
    {
484
      compositor->stage = clutter_stage_new ();
485
486

      meta_screen_get_size (screen, &width, &height);
487
      clutter_actor_realize (compositor->stage);
488

489
      xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
490
491
492
493

      XResizeWindow (xdisplay, xwin, width, height);

        {
494
495
          MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
          Display *backend_xdisplay = meta_backend_x11_get_xdisplay (backend);
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
          unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
          XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };

          XISetMask (mask.mask, XI_KeyPress);
          XISetMask (mask.mask, XI_KeyRelease);
          XISetMask (mask.mask, XI_ButtonPress);
          XISetMask (mask.mask, XI_ButtonRelease);
          XISetMask (mask.mask, XI_Enter);
          XISetMask (mask.mask, XI_Leave);
          XISetMask (mask.mask, XI_FocusIn);
          XISetMask (mask.mask, XI_FocusOut);
          XISetMask (mask.mask, XI_Motion);
          XIClearMask (mask.mask, XI_TouchBegin);
          XIClearMask (mask.mask, XI_TouchEnd);
          XIClearMask (mask.mask, XI_TouchUpdate);
511
          XISelectEvents (backend_xdisplay, xwin, &mask, 1);
512
513
        }
    }
514

515
516
517
518
519
520
521
522
523
524
  /* We use connect_after() here to accomodate code in GNOME Shell that,
   * when benchmarking drawing performance, connects to ::after-paint
   * and calls glFinish(). The timing information from that will be
   * more accurate if we hold off until that completes before we signal
   * apps to begin drawing the next frame. If there are no other
   * connections to ::after-paint, connect() vs. connect_after() doesn't
   * matter.
   */
  g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint",
                          G_CALLBACK (after_stage_paint), compositor);
525

526
  clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY);
527

528
529
  compositor->window_group = meta_window_group_new (screen);
  compositor->top_window_group = meta_window_group_new (screen);
530

531
532
  clutter_actor_add_child (compositor->stage, compositor->window_group);
  clutter_actor_add_child (compositor->stage, compositor->top_window_group);
533

534
  if (meta_is_wayland_compositor ())
535
    {
536
537
538
      /* NB: When running as a wayland compositor we don't need an X
       * composite overlay window, and we don't need to play any input
       * region tricks to redirect events into clutter. */
539
      compositor->output = None;
540
    }
541
542
  else
    {
543
544
      compositor->output = screen->composite_overlay_window;

545
      XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
546

547
548
      meta_empty_stage_input_region (screen);

Jasper St. Pierre's avatar
Jasper St. Pierre committed
549
      /* Make sure there isn't any left-over output shape on the
550
551
       * overlay window by setting the whole screen to be an
       * output region.
Jasper St. Pierre's avatar
Jasper St. Pierre committed
552
       *
553
554
555
556
       * Note: there doesn't seem to be any real chance of that
       *  because the X server will destroy the overlay window
       *  when the last client using it exits.
       */
557
      XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None);
558

559
560
561
      /* Map overlay window before redirecting windows offscreen so we catch their
       * contents until we show the stage.
       */
562
      XMapWindow (xdisplay, compositor->output);
563
    }
564

565
  redirect_windows (display->screen);
566

567
  compositor->plugin_mgr = meta_plugin_manager_new (compositor);
568
569
}

570
void
571
meta_compositor_unmanage (MetaCompositor *compositor)
572
{
573
574
  if (!meta_is_wayland_compositor ())
    {
575
576
577
      MetaDisplay *display = compositor->display;
      Display *xdisplay = meta_display_get_xdisplay (display);
      Window xroot = display->screen->xroot;
578
579
580
581
582
583

      /* This is the most important part of cleanup - we have to do this
       * before giving up the window manager selection or the next
       * window manager won't be able to redirect subwindows */
      XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
    }
584
585
}

586
587
/**
 * meta_shape_cow_for_window:
588
 * @compositor: A #MetaCompositor
589
 * @window: (nullable): A #MetaWindow to shape the COW for
590
591
592
593
594
595
 *
 * Sets an bounding shape on the COW so that the given window
 * is exposed. If @window is %NULL it clears the shape again.
 *
 * Used so we can unredirect windows, by shaping away the part
 * of the COW, letting the raw window be seen through below.
Adel Gadllah's avatar
Adel Gadllah committed
596
597
 */
static void
598
meta_shape_cow_for_window (MetaCompositor *compositor,
599
                           MetaWindow *window)
Adel Gadllah's avatar
Adel Gadllah committed
600
{
601
602
  MetaDisplay *display = compositor->display;
  Display *xdisplay = meta_display_get_xdisplay (display);
Adel Gadllah's avatar
Adel Gadllah committed
603

604
  if (window == NULL)
605
    XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None);
Adel Gadllah's avatar
Adel Gadllah committed
606
607
608
  else
    {
      XserverRegion output_region;
609
      XRectangle screen_rect, window_bounds;
Adel Gadllah's avatar
Adel Gadllah committed
610
      int width, height;
611
612
      MetaRectangle rect;

613
      meta_window_get_frame_rect (window, &rect);
614
615
616
617
618

      window_bounds.x = rect.x;
      window_bounds.y = rect.y;
      window_bounds.width = rect.width;
      window_bounds.height = rect.height;
Adel Gadllah's avatar
Adel Gadllah committed
619

620
      meta_screen_get_size (display->screen, &width, &height);
Adel Gadllah's avatar
Adel Gadllah committed
621
622
623
624
625
      screen_rect.x = 0;
      screen_rect.y = 0;
      screen_rect.width = width;
      screen_rect.height = height;

626
627
      output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1);

Adel Gadllah's avatar
Adel Gadllah committed
628
      XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
629
      XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region);
Adel Gadllah's avatar
Adel Gadllah committed
630
631
632
633
      XFixesDestroyRegion (xdisplay, output_region);
    }
}

634
static void
635
set_unredirected_window (MetaCompositor *compositor,
636
637
                         MetaWindow     *window)
{
638
  if (compositor->unredirected_window == window)
639
640
    return;

641
  if (compositor->unredirected_window != NULL)
642
    {
643
      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
644
      meta_window_actor_set_unredirected (window_actor, FALSE);
645
646
    }

647
  compositor->unredirected_window = window;
648

649
  if (compositor->unredirected_window != NULL)
650
    {
651
      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
652
      meta_window_actor_set_unredirected (window_actor, TRUE);
653
654
    }

655
  meta_shape_cow_for_window (compositor, compositor->unredirected_window);
656
657
}

658
659
660
void
meta_compositor_add_window (MetaCompositor    *compositor,
                            MetaWindow        *window)
661
{
662
  MetaDisplay *display = compositor->display;
663

664
  meta_error_trap_push (display);
665

Jasper St. Pierre's avatar
Jasper St. Pierre committed
666
  meta_window_actor_new (window);
667
  sync_actor_stacking (compositor);
668

669
  meta_error_trap_pop (display);
670
671
}

672
673
674
void
meta_compositor_remove_window (MetaCompositor *compositor,
                               MetaWindow     *window)
675
{
Jasper St. Pierre's avatar
Jasper St. Pierre committed
676
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
677

678
679
  if (compositor->unredirected_window == window)
    set_unredirected_window (compositor, NULL);
Adel Gadllah's avatar
Adel Gadllah committed
680

681
  meta_window_actor_destroy (window_actor);
682
683
}

684
void
685
686
meta_compositor_sync_updates_frozen (MetaCompositor *compositor,
                                     MetaWindow     *window)
687
{
Jasper St. Pierre's avatar
Jasper St. Pierre committed
688
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
689
  meta_window_actor_sync_updates_frozen (window_actor);
690
691
}

692
693
694
695
696
void
meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
                                   MetaWindow     *window,
                                   gboolean        no_delay_frame)
{
Jasper St. Pierre's avatar
Jasper St. Pierre committed
697
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
698
699
700
  meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
}

701
void
702
meta_compositor_window_shape_changed (MetaCompositor *compositor,
703
                                      MetaWindow     *window)
704
705
706
{
  MetaWindowActor *window_actor;
  window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
707
708
709
  if (!window_actor)
    return;

710
  meta_window_actor_update_shape (window_actor);
711
712
}

713
714
715
716
717
718
719
720
721
722
723
724
void
meta_compositor_window_opacity_changed (MetaCompositor *compositor,
                                        MetaWindow     *window)
{
  MetaWindowActor *window_actor;
  window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  if (!window_actor)
    return;

  meta_window_actor_update_opacity (window_actor);
}

725
726
727
728
729
730
731
732
733
734
735
736
void
meta_compositor_window_surface_changed (MetaCompositor *compositor,
                                        MetaWindow     *window)
{
  MetaWindowActor *window_actor;
  window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  if (!window_actor)
    return;

  meta_window_actor_update_surface (window_actor);
}

737
738
/**
 * meta_compositor_process_event: (skip)
Jasper St. Pierre's avatar
Jasper St. Pierre committed
739
740
741
 * @compositor:
 * @event:
 * @window:
742
743
 *
 */
744
745
746
747
gboolean
meta_compositor_process_event (MetaCompositor *compositor,
                               XEvent         *event,
                               MetaWindow     *window)
748
{
749
750
  if (!meta_is_wayland_compositor () &&
      event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
751
    {
752
753
754
755
      /* Core code doesn't handle damage events, so we need to extract the MetaWindow
       * ourselves
       */
      if (window == NULL)
756
        {
757
758
          Window xwin = ((XDamageNotifyEvent *) event)->drawable;
          window = meta_display_lookup_x_window (compositor->display, xwin);
759
        }
760

761
762
      if (window)
        process_damage (compositor, (XDamageNotifyEvent *) event, window);
763
    }
Tomas Frydrych's avatar
Tomas Frydrych committed
764

765
766
  /* Clutter needs to know about MapNotify events otherwise it will
     think the stage is invisible */
767
  if (!meta_is_wayland_compositor () && event->type == MapNotify)
768
769
    clutter_x11_handle_event (event);

770
771
772
773
774
  /* The above handling is basically just "observing" the events, so we return
   * FALSE to indicate that the event should not be filtered out; if we have
   * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example.
   */
  return FALSE;
775
776
}

777
778
779
780
gboolean
meta_compositor_filter_keybinding (MetaCompositor *compositor,
                                   MetaKeyBinding *binding)
{
781
  return meta_plugin_manager_filter_keybinding (compositor->plugin_mgr, binding);
782
783
}

784
void
785
786
787
meta_compositor_show_window (MetaCompositor *compositor,
			     MetaWindow	    *window,
                             MetaCompEffect  effect)
788
{
789
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
Jasper St. Pierre's avatar
Jasper St. Pierre committed
790
 meta_window_actor_show (window_actor, effect);
791
}
792

793
void
794
795
796
meta_compositor_hide_window (MetaCompositor *compositor,
                             MetaWindow     *window,
                             MetaCompEffect  effect)
797
{
798
799
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_hide (window_actor, effect);
800
801
}

802
803
804
void
meta_compositor_maximize_window (MetaCompositor    *compositor,
                                 MetaWindow        *window,
805
806
				 MetaRectangle	   *old_rect,
				 MetaRectangle	   *new_rect)
807
{
808
809
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_maximize (window_actor, old_rect, new_rect);
810
811
}

812
813
814
void
meta_compositor_unmaximize_window (MetaCompositor    *compositor,
                                   MetaWindow        *window,
815
816
				   MetaRectangle     *old_rect,
				   MetaRectangle     *new_rect)
Tomas Frydrych's avatar
Tomas Frydrych committed
817
{
818
819
  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  meta_window_actor_unmaximize (window_actor, old_rect, new_rect);
820
821
}

822
823
824
825
826
void
meta_compositor_switch_workspace (MetaCompositor     *compositor,
                                  MetaWorkspace      *from,
                                  MetaWorkspace      *to,
                                  MetaMotionDirection direction)
827
{
828
  gint to_indx, from_indx;
829
830
831

  to_indx   = meta_workspace_index (to);
  from_indx = meta_workspace_index (from);
832

833
  compositor->switch_workspace_in_progress++;
834

835
836
837
  if (!meta_plugin_manager_switch_workspace (compositor->plugin_mgr,
                                             from_indx,
                                             to_indx,
838
                                             direction))
839
    {
840
      compositor->switch_workspace_in_progress--;
841
842
843
844
845
846

      /* We have to explicitely call this to fix up stacking order of the
       * actors; this is because the abs stacking position of actors does not
       * necessarily change during the window hiding/unhiding, only their
       * relative position toward the destkop window.
       */
847
      meta_finish_workspace_switch (compositor);
848
    }
Tomas Frydrych's avatar
Tomas Frydrych committed
849
}
850

851
static void
852
sync_actor_stacking (MetaCompositor *compositor)
853
{
854
  GList *children;
855
  GList *expected_window_node;
856
  GList *tmp;
857
  GList *old;
858
  GList *backgrounds;
859
  gboolean has_windows;
860
  gboolean reordered;
861

862
  /* NB: The first entries in the lists are stacked the lowest */
863

864
865
866
867
  /* Restacking will trigger full screen redraws, so it's worth a
   * little effort to make sure we actually need to restack before
   * we go ahead and do it */

868
  children = clutter_actor_get_children (compositor->window_group);
869
  has_windows = FALSE;
870
871
  reordered = FALSE;

872
873
874
875
876
  /* We allow for actors in the window group other than the actors we
   * know about, but it's up to a plugin to try and keep them stacked correctly
   * (we really need extra API to make that reliable.)
   */

877
878
879
  /* First we collect a list of all backgrounds, and check if they're at the
   * bottom. Then we check if the window actors are in the correct sequence */
  backgrounds = NULL;
880
  expected_window_node = compositor->windows;
881
  for (old = children; old != NULL; old = old->next)
882
    {
883
      ClutterActor *actor = old->data;
884

885
886
      if (META_IS_BACKGROUND_GROUP (actor) ||
          META_IS_BACKGROUND_ACTOR (actor))
887
        {
888
889
          backgrounds = g_list_prepend (backgrounds, actor);

890
891
          if (has_windows)
            reordered = TRUE;
892
        }
893
894
895
      else if (META_IS_WINDOW_ACTOR (actor) && !reordered)
        {
          has_windows = TRUE;
896

897
898
899
900
901
          if (expected_window_node != NULL && actor == expected_window_node->data)
            expected_window_node = expected_window_node->next;
          else
            reordered = TRUE;
        }
902
903
904
905
906
    }

  g_list_free (children);

  if (!reordered)
907
908
909
910
    {
      g_list_free (backgrounds);
      return;
    }
911

912
  /* reorder the actors by lowering them in turn to the bottom of the stack.
913
914
915
916
917
   * windows first, then background.
   *
   * We reorder the actors even if they're not parented to the window group,
   * to allow stacking to work with intermediate actors (eg during effects)
   */
918
  for (tmp = g_list_last (compositor->windows); tmp != NULL; tmp = tmp->prev)
919
    {
920
      ClutterActor *actor = tmp->data, *parent;
921

922
923
      parent = clutter_actor_get_parent (actor);
      clutter_actor_set_child_below_sibling (parent, actor, NULL);
924
    }
925

926
927
928
929
930
  /* we prepended the backgrounds above so the last actor in the list
   * should get lowered to the bottom last.
   */
  for (tmp = backgrounds; tmp != NULL; tmp = tmp->next)
    {
931
      ClutterActor *actor = tmp->data, *parent;
932

933
934
      parent = clutter_actor_get_parent (actor);
      clutter_actor_set_child_below_sibling (parent, actor, NULL);
935
936
    }
  g_list_free (backgrounds);
937
938
}

939
940
941
void
meta_compositor_sync_stack (MetaCompositor  *compositor,
			    GList	    *stack)
942
{