Example #1
0
static void
meta_background_actor_get_preferred_height (ClutterActor *actor,
                                            gfloat        for_width,
                                            gfloat       *min_height_p,
                                            gfloat       *natural_height_p)

{
  MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
  MetaBackgroundActorPrivate *priv = self->priv;
  int width, height;

  meta_screen_get_size (priv->background->screen, &width, &height);

  if (min_height_p)
    *min_height_p = height;
  if (natural_height_p)
    *natural_height_p = height;
}
Example #2
0
static void reposition_switcher(MetaSwitcher* self)
{
    MetaSwitcherPrivate* priv = self->priv;
    MetaScreen* screen = meta_plugin_get_screen(priv->plugin);

    gint screen_width = 0, screen_height = 0;
    meta_screen_get_size(screen, &screen_width, &screen_height);

    clutter_actor_save_easing_state(priv->top);
    clutter_actor_set_easing_duration(priv->top, 400);
    clutter_actor_set_easing_mode(priv->top, CLUTTER_LINEAR);

    gfloat w = clutter_actor_get_width(priv->top), h = clutter_actor_get_height(priv->top),
            tx = (screen_width - w)/2, ty = (screen_height - h)/2;
    clutter_actor_set_position(priv->top, tx, ty);

    clutter_actor_restore_easing_state(priv->top);
}
Example #3
0
gboolean meta_switcher_show(MetaSwitcher* self)
{
    MetaSwitcherPrivate* priv = self->priv;
    int screen_width, screen_height;

    MetaScreen* screen = meta_plugin_get_screen(priv->plugin);
    priv->workspace = meta_screen_get_active_workspace(screen);

    meta_screen_get_size(screen, &screen_width, &screen_height);

    meta_switcher_present_list(self);
    if (priv->apps == NULL || priv->apps->len == 0) goto _end;

    _capture_desktop(self);
    clutter_content_invalidate(clutter_actor_get_content(priv->top));

    ClutterActor* stage = meta_get_stage_for_screen(screen);
    clutter_actor_insert_child_above(stage, priv->top, NULL);
    clutter_actor_show(priv->top);

    if (!meta_plugin_begin_modal(priv->plugin, 0, clutter_get_current_event_time())) {
        if (!meta_plugin_begin_modal(priv->plugin, META_MODAL_POINTER_ALREADY_GRABBED,
                    clutter_get_current_event_time())) {
            g_warning("can not be modal");
            goto _end;
        }
    }

    meta_disable_unredirect_for_screen(screen);
    priv->modaled = TRUE;

    priv->previous_focused = clutter_stage_get_key_focus(CLUTTER_STAGE(stage));
    if (priv->previous_focused == stage) priv->previous_focused = NULL;
    clutter_stage_set_key_focus(CLUTTER_STAGE(stage), priv->top);
    clutter_actor_grab_key_focus(priv->top);

    return TRUE;

_end:
    clutter_actor_hide(priv->top);
    return FALSE;
}
Example #4
0
static void
update_wrap_mode (MetaScreenBackground *background)
{
  GSList *l;
  int width, height;

  meta_screen_get_size (background->screen, &width, &height);

  /* We turn off repeating when we have a full-screen pixmap to keep from
   * getting artifacts from one side of the image sneaking into the other
   * side of the image via bilinear filtering.
   */
  if (width == background->texture_width && height == background->texture_height)
    background->wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE;
  else
    background->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;

  for (l = background->actors; l; l = l->next)
    update_wrap_mode_of_actor (l->data);
}
Example #5
0
static ClutterActor* load_icon_for_window(MetaSwitcher* self, MetaWindow* window)
{
    MetaSwitcherPrivate *priv = self->priv;
    MetaScreen *screen = meta_plugin_get_screen(priv->plugin);
    ShellWindowTracker* tracker = shell_window_tracker_get_default();
    ShellApp* app = shell_window_tracker_get_window_app(tracker, window);
    gint screen_width, screen_height, app_icon_size = APP_ICON_SIZE;

    /* TODO: @sonald scale app icon size at first */
    meta_screen_get_size(screen, &screen_width, &screen_height);
    if (priv->apps->len)
        app_icon_size = (screen_width - priv->apps->len * APP_ICON_PADDING ) / 
                        priv->apps->len;

    if (app_icon_size > APP_ICON_SIZE)
        app_icon_size = APP_ICON_SIZE;

    if (app)
        return shell_app_create_icon_texture(app, app_icon_size);

    return NULL;
}
Example #6
0
/**
 * meta_shape_cow_for_window:
 * @compositor: A #MetaCompositor
 * @window: (nullable): A #MetaWindow to shape the COW for
 *
 * 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.
 */
static void
meta_shape_cow_for_window (MetaCompositor *compositor,
                           MetaWindow *window)
{
  MetaDisplay *display = compositor->display;
  Display *xdisplay = meta_display_get_xdisplay (display);

  if (window == NULL)
    XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None);
  else
    {
      XserverRegion output_region;
      XRectangle screen_rect, window_bounds;
      int width, height;
      MetaRectangle rect;

      meta_window_get_frame_rect (window, &rect);

      window_bounds.x = rect.x;
      window_bounds.y = rect.y;
      window_bounds.width = rect.width;
      window_bounds.height = rect.height;

      meta_screen_get_size (display->screen, &width, &height);
      screen_rect.x = 0;
      screen_rect.y = 0;
      screen_rect.width = width;
      screen_rect.height = height;

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

      XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
      XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region);
      XFixesDestroyRegion (xdisplay, output_region);
    }
}
Example #7
0
/*
 * Shapes the cow so that the given window is exposed,
 * when metaWindow is NULL it clears the shape again
 */
static void
meta_shape_cow_for_window (MetaScreen *screen,
                           MetaWindow *metaWindow)
{
    MetaCompScreen *info = meta_screen_get_compositor_data (screen);
    Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen));

    if (metaWindow == NULL)
        XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
    else
    {
        XserverRegion output_region;
        XRectangle screen_rect, window_bounds;
        int width, height;
        MetaRectangle rect;

        meta_window_get_outer_rect (metaWindow, &rect);

        window_bounds.x = rect.x;
        window_bounds.y = rect.y;
        window_bounds.width = rect.width;
        window_bounds.height = rect.height;

        meta_screen_get_size (screen, &width, &height);
        screen_rect.x = 0;
        screen_rect.y = 0;
        screen_rect.width = width;
        screen_rect.height = height;

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

        XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
        XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, output_region);
        XFixesDestroyRegion (xdisplay, output_region);
    }
}
Example #8
0
static void
meta_window_group_paint (ClutterActor *actor)
{
  cairo_region_t *clip_region;
  cairo_region_t *unobscured_region;
  cairo_rectangle_int_t visible_rect, clip_rect;
  int paint_x_origin, paint_y_origin;
  int screen_width, screen_height;

  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
  ClutterActor *stage = clutter_actor_get_stage (actor);

  meta_screen_get_size (window_group->screen, &screen_width, &screen_height);

  /* Normally we expect an actor to be drawn at it's position on the screen.
   * However, if we're inside the paint of a ClutterClone, that won't be the
   * case and we need to compensate. We look at the position of the window
   * group under the current model-view matrix and the position of the actor.
   * If they are both simply integer translations, then we can compensate
   * easily, otherwise we give up.
   *
   * Possible cleanup: work entirely in paint space - we can compute the
   * combination of the model-view matrix with the local matrix for each child
   * actor and get a total transformation for that actor for how we are
   * painting currently, and never worry about how actors are positioned
   * on the stage.
   */
  if (!meta_actor_painting_untransformed (screen_width, screen_height, &paint_x_origin, &paint_y_origin) ||
      !meta_actor_is_untransformed (actor, NULL, NULL))
    {
      CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
      return;
    }

  visible_rect.x = visible_rect.y = 0;
  visible_rect.width = clutter_actor_get_width (CLUTTER_ACTOR (stage));
  visible_rect.height = clutter_actor_get_height (CLUTTER_ACTOR (stage));

  unobscured_region = cairo_region_create_rectangle (&visible_rect);

  /* Get the clipped redraw bounds from Clutter so that we can avoid
   * painting shadows on windows that don't need to be painted in this
   * frame. In the case of a multihead setup with mismatched monitor
   * sizes, we could intersect this with an accurate union of the
   * monitors to avoid painting shadows that are visible only in the
   * holes. */
  clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
                                        &clip_rect);

  clip_region = cairo_region_create_rectangle (&clip_rect);

  cairo_region_translate (clip_region, -paint_x_origin, -paint_y_origin);

  meta_cullable_cull_out (META_CULLABLE (window_group), unobscured_region, clip_region);

  cairo_region_destroy (unobscured_region);
  cairo_region_destroy (clip_region);

  CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);

  meta_cullable_reset_culling (META_CULLABLE (window_group));
}
Example #9
0
static void
switch_workspace (MetaPlugin *plugin,
                  gint from, gint to,
                  MetaMotionDirection direction)
{
  MetaScreen *screen;
  MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
  GList        *l;
  ClutterActor *workspace0  = clutter_group_new ();
  ClutterActor *workspace1  = clutter_group_new ();
  ClutterActor *stage;
  int           screen_width, screen_height;
  ClutterAnimation *animation;

  screen = meta_plugin_get_screen (plugin);
  stage = meta_get_stage_for_screen (screen);

  meta_screen_get_size (screen,
                        &screen_width,
                        &screen_height);

  clutter_actor_set_anchor_point (workspace1,
                                  screen_width,
                                  screen_height);
  clutter_actor_set_position (workspace1,
                              screen_width,
                              screen_height);

  clutter_actor_set_scale (workspace1, 0.0, 0.0);

  clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace1);
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace0);

  if (from == to)
    {
      meta_plugin_switch_workspace_completed (plugin);
      return;
    }

  l = g_list_last (meta_get_window_actors (screen));

  while (l)
    {
      MetaWindowActor *window_actor = l->data;
      MetaWindow *window = meta_window_actor_get_meta_window (window_actor);
      MetaWorkspace   *workspace;
      ActorPrivate    *apriv	    = get_actor_private (window_actor);
      ClutterActor    *actor	    = CLUTTER_ACTOR (window_actor);
      gint             win_workspace;

      workspace = meta_window_get_workspace (window);
      win_workspace = meta_workspace_index (workspace);

      if (win_workspace == to || win_workspace == from)
        {
          apriv->orig_parent = clutter_actor_get_parent (actor);

          clutter_actor_reparent (actor,
				  win_workspace == to ? workspace1 : workspace0);
          clutter_actor_show_all (actor);
          clutter_actor_raise_top (actor);
        }
      else if (win_workspace < 0)
        {
          /* Sticky window */
          apriv->orig_parent = NULL;
        }
      else
        {
          /* Window on some other desktop */
          clutter_actor_hide (actor);
          apriv->orig_parent = NULL;
        }

      l = l->prev;
    }

  priv->desktop1 = workspace0;
  priv->desktop2 = workspace1;

  animation = clutter_actor_animate (workspace0, CLUTTER_EASE_IN_SINE,
                                     SWITCH_TIMEOUT,
                                     "scale-x", 1.0,
                                     "scale-y", 1.0,
                                     NULL);
  priv->tml_switch_workspace1 = clutter_animation_get_timeline (animation);
  g_signal_connect (priv->tml_switch_workspace1,
                    "completed",
                    G_CALLBACK (on_switch_workspace_effect_complete),
                    plugin);

  animation = clutter_actor_animate (workspace1, CLUTTER_EASE_IN_SINE,
                                     SWITCH_TIMEOUT,
                                     "scale-x", 0.0,
                                     "scale-y", 0.0,
                                     NULL);
  priv->tml_switch_workspace2 = clutter_animation_get_timeline (animation);
}
Example #10
0
static void
grab_screenshot (ClutterActor *stage,
                 _screenshot_data *screenshot_data)
{
  MetaScreen *screen = shell_global_get_screen (screenshot_data->screenshot->global);
  MetaCursorTracker *tracker;
  int width, height;
  GSimpleAsyncResult *result;
  GSettings *settings;

  meta_screen_get_size (screen, &width, &height);

  do_grab_screenshot (screenshot_data, 0, 0, width, height);

  if (meta_screen_get_n_monitors (screen) > 1)
    {
      cairo_region_t *screen_region = cairo_region_create ();
      cairo_region_t *stage_region;
      MetaRectangle monitor_rect;
      cairo_rectangle_int_t stage_rect;
      int i;
      cairo_t *cr;

      for (i = meta_screen_get_n_monitors (screen) - 1; i >= 0; i--)
        {
          meta_screen_get_monitor_geometry (screen, i, &monitor_rect);
          cairo_region_union_rectangle (screen_region, (const cairo_rectangle_int_t *) &monitor_rect);
        }

      stage_rect.x = 0;
      stage_rect.y = 0;
      stage_rect.width = width;
      stage_rect.height = height;

      stage_region = cairo_region_create_rectangle ((const cairo_rectangle_int_t *) &stage_rect);
      cairo_region_xor (stage_region, screen_region);
      cairo_region_destroy (screen_region);

      cr = cairo_create (screenshot_data->image);

      for (i = 0; i < cairo_region_num_rectangles (stage_region); i++)
        {
          cairo_rectangle_int_t rect;
          cairo_region_get_rectangle (stage_region, i, &rect);
          cairo_rectangle (cr, (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height);
          cairo_fill (cr);
        }

      cairo_destroy (cr);
      cairo_region_destroy (stage_region);
    }

  screenshot_data->screenshot_area.x = 0;
  screenshot_data->screenshot_area.y = 0;
  screenshot_data->screenshot_area.width = width;
  screenshot_data->screenshot_area.height = height;

  settings = g_settings_new (A11Y_APPS_SCHEMA);
  if (screenshot_data->include_cursor &&
      !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
    {
      tracker = meta_cursor_tracker_get_for_screen (screen);
      _draw_cursor_image (tracker, screenshot_data->image, screenshot_data->screenshot_area);
    }
  g_object_unref (settings);

  g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot_data);

  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_screenshot);
  g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
  g_object_unref (result);
}
Example #11
0
static void _add_app(MetaSwitcher* self, MetaWindow* app, gint* x, gint* y)
{
    MetaSwitcherPrivate* priv = self->priv;

    if (!priv->icons)
        priv->icons = g_hash_table_new(NULL, NULL);

    // container
    ClutterActor* actor = clutter_actor_new();
    WindowPrivate* win_priv = get_window_private(actor);
    win_priv->window = app;
    win_priv->highlight = FALSE;
    g_hash_table_insert(priv->icons, app, actor);

    gint w = APP_ACTOR_WIDTH, h = APP_ACTOR_HEIGHT, screen_width, screen_height;
    /* TODO: @sonald scale app actor width */
    MetaScreen *screen = meta_plugin_get_screen(priv->plugin);
    meta_screen_get_size(screen, &screen_width, &screen_height);
    if (priv->apps->len)
        w = (screen_width - priv->apps->len * APP_ICON_PADDING) / priv->apps->len;

    if (w > APP_ACTOR_WIDTH)
        w = APP_ACTOR_WIDTH;

    // add children
    ClutterContent* canvas = clutter_canvas_new();
    g_signal_connect(canvas, "draw", G_CALLBACK(on_icon_background_draw), actor);
    clutter_canvas_set_size(CLUTTER_CANVAS(canvas), w, h);

    ClutterActor* bg = clutter_actor_new();
    clutter_actor_set_name(bg, "bg");
    clutter_actor_set_content(bg, canvas);
    g_object_unref(canvas);

    clutter_actor_set_size(bg, w, h);
    g_object_set(bg, "x-expand", TRUE, "y-expand", TRUE, "x-align", CLUTTER_ACTOR_ALIGN_FILL,
            "y-align", CLUTTER_ACTOR_ALIGN_FILL, NULL);
    clutter_actor_add_child(actor, bg);

    ClutterActor* icon = load_icon_for_window(self, app);
    if (icon) clutter_actor_add_child(actor, icon);

    ClutterActor* label = clutter_text_new();
    clutter_actor_add_child(actor, label);
    clutter_text_set_text(CLUTTER_TEXT(label), meta_window_get_title(app));
    clutter_text_set_font_name(CLUTTER_TEXT(label), "Sans 10");
    ClutterColor clr = {0xff, 0xff, 0xff, 0xff};
    clutter_text_set_color(CLUTTER_TEXT(label), &clr);
    clutter_text_set_ellipsize(CLUTTER_TEXT(label), PANGO_ELLIPSIZE_END);
    g_object_set(label, "x-align", CLUTTER_ACTOR_ALIGN_CENTER, "y-align", CLUTTER_ACTOR_ALIGN_CENTER, NULL);

    gfloat pref_width = clutter_actor_get_width(label);
    if (pref_width > w - 10) {
        pref_width = w - 10;
        clutter_actor_set_width(label, pref_width);
    }
    /* TODO: @sonald adjust app title position */
    clutter_actor_set_position(label, (w - pref_width) / 2, APP_ICON_SIZE + 2);

    g_debug("%s: size: %d, %d", __func__, w, h);
    clutter_actor_show(actor);

    clutter_actor_add_child(priv->top, actor);

    *x += w;
}
/*
 * This is the Metacity entry point for the effect.
 */
void
mnb_switch_zones_effect (MetaPlugin         *plugin,
                         gint                from,
                         gint                to,
                         MetaMotionDirection direction)
{
  GList *w;
  gint width, height;
  MetaScreen *screen;
  ClutterActor *window_group;

  if (running++)
    {
      /*
       * We have been called while the effect is already in progress; we need to
       * mutter know that we completed the previous run.
       */
      if (--running < 0)
        {
          g_warning (G_STRLOC ": error in running effect accounting!");
          running = 0;
        }

      meta_plugin_switch_workspace_completed (plugin);
    }

  if ((from == to) && !zones_preview)
    {
      if (--running < 0)
        {
          g_warning (G_STRLOC ": error in running effect accounting!");
          running = 0;
        }

      meta_plugin_switch_workspace_completed (plugin);

      return;
    }

  screen = meta_plugin_get_screen (plugin);

  if (!zones_preview)
    {
      ClutterActor *stage;

      /* Construct the zones preview actor */
      zones_preview = mnb_zones_preview_new ();
      g_object_set (G_OBJECT (zones_preview),
                    "workspace", (gdouble)from,
                    NULL);

      /* Add it to the stage */
      stage = meta_get_stage_for_screen (screen);
      clutter_container_add_actor (CLUTTER_CONTAINER (stage), zones_preview);

      /* Attach to completed signal */
      g_signal_connect (zones_preview, "switch-completed",
                        G_CALLBACK (mnb_switch_zones_completed_cb), plugin);
    }

  meta_screen_get_size (screen, &width, &height);
  g_object_set (G_OBJECT (zones_preview),
                "workspace-width", (guint)width,
                "workspace-height", (guint)height,
                NULL);

  mnb_zones_preview_clear (MNB_ZONES_PREVIEW (zones_preview));
  mnb_zones_preview_set_n_workspaces (MNB_ZONES_PREVIEW (zones_preview),
                                      meta_screen_get_n_workspaces (screen));

  /* Add windows to zone preview actor */
  for (w = meta_get_window_actors (screen); w; w = w->next)
    {
      MetaWindowActor *window_actor = w->data;
      gint workspace = meta_window_actor_get_workspace (window_actor);
      MetaWindow *window = meta_window_actor_get_meta_window (window_actor);
      MetaWindowType type = meta_window_get_window_type (window);

      /*
       * Only show regular windows that are not sticky (getting stacking order
       * right for sticky windows would be really hard, and since they appear
       * on each workspace, they do not help in identifying which workspace
       * it is).
       */
      if ((workspace < 0) ||
          meta_window_actor_is_override_redirect (window_actor) ||
          (type != META_WINDOW_NORMAL))
        continue;

      mnb_zones_preview_add_window (MNB_ZONES_PREVIEW (zones_preview), window_actor);
    }

  /* Make sure it's on top */
  window_group = meta_get_window_group_for_screen (screen);
  clutter_actor_raise (zones_preview, window_group);

  /* Initiate animation */
  mnb_zones_preview_change_workspace (MNB_ZONES_PREVIEW (zones_preview), to);
}
Example #13
0
void
meta_compositor_manage (MetaCompositor *compositor)
{
  MetaDisplay *display = compositor->display;
  Display *xdisplay = display->xdisplay;
  MetaScreen *screen = display->screen;
  Window xwin = 0;
  gint width, height;

  meta_screen_set_cm_selection (display->screen);

  if (meta_is_wayland_compositor ())
    {
      MetaWaylandCompositor *wayland_compositor = meta_wayland_compositor_get_default ();

      compositor->stage = meta_stage_new ();

      wayland_compositor->stage = compositor->stage;

      meta_screen_get_size (screen, &width, &height);
      clutter_actor_set_size (compositor->stage, width, height);
      clutter_actor_show (compositor->stage);
    }
  else
    {
      compositor->stage = clutter_stage_new ();

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

      xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));

      XResizeWindow (xdisplay, xwin, width, height);

        {
          MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
          Display *backend_xdisplay = meta_backend_x11_get_xdisplay (backend);
          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);
          XISelectEvents (backend_xdisplay, xwin, &mask, 1);
        }
    }

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

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

  compositor->window_group = meta_window_group_new (screen);
  compositor->top_window_group = meta_window_group_new (screen);

  clutter_actor_add_child (compositor->stage, compositor->window_group);
  clutter_actor_add_child (compositor->stage, compositor->top_window_group);

  if (meta_is_wayland_compositor ())
    {
      /* 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. */
      compositor->output = None;
    }
  else
    {
      compositor->output = screen->composite_overlay_window;

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

      meta_empty_stage_input_region (screen);

      /* Make sure there isn't any left-over output shape on the
       * overlay window by setting the whole screen to be an
       * output region.
       *
       * 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.
       */
      XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None);

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

  redirect_windows (display->screen);

  compositor->plugin_mgr = meta_plugin_manager_new (compositor);
}
Example #14
0
void
meta_compositor_manage_screen (MetaCompositor *compositor,
                               MetaScreen     *screen)
{
    MetaCompScreen *info;
    MetaDisplay    *display       = meta_screen_get_display (screen);
    Display        *xdisplay      = meta_display_get_xdisplay (display);
    int             screen_number = meta_screen_get_screen_number (screen);
    Window          xroot         = meta_screen_get_xroot (screen);
    Window          xwin;
    gint            width, height;
    XWindowAttributes attr;
    long            event_mask;
    guint           n_retries;
    guint           max_retries;

    /* Check if the screen is already managed */
    if (meta_screen_get_compositor_data (screen))
        return;

    if (meta_get_replace_current_wm ())
        max_retries = 5;
    else
        max_retries = 1;

    n_retries = 0;

    /* Some compositors (like old versions of Muffin) 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.
     */
    while (TRUE)
    {
        meta_error_trap_push_with_return (display);
        XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
        XSync (xdisplay, FALSE);

        if (!meta_error_trap_pop_with_return (display))
            break;

        if (n_retries == max_retries)
        {
            /* 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);
        }

        n_retries++;
        g_usleep (G_USEC_PER_SEC);
    }

    info = g_new0 (MetaCompScreen, 1);
    /*
     * We use an empty input region for Clutter as a default because that allows
     * the user to interact with all the windows displayed on the screen.
     * We have to initialize info->pending_input_region to an empty region explicitly,
     * because None value is used to mean that the whole screen is an input region.
     */
    info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);

    info->screen = screen;

    meta_screen_set_compositor_data (screen, info);

    info->output = None;
    info->windows = NULL;

    meta_screen_set_cm_selection (screen);

    info->stage = clutter_stage_new ();

    meta_screen_get_size (screen, &width, &height);
    clutter_actor_realize (info->stage);

    xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));

    XResizeWindow (xdisplay, xwin, width, height);

    event_mask = FocusChangeMask |
                 ExposureMask |
                 EnterWindowMask | LeaveWindowMask |
                 PointerMotionMask |
                 PropertyChangeMask |
                 ButtonPressMask | ButtonReleaseMask |
                 KeyPressMask | KeyReleaseMask |
                 StructureNotifyMask;

    if (XGetWindowAttributes (xdisplay, xwin, &attr))
    {
        event_mask |= attr.your_event_mask;
    }

    XSelectInput (xdisplay, xwin, event_mask);

    info->window_group = meta_window_group_new (screen);
    info->background_actor = meta_background_actor_new_for_screen (screen);
    info->bottom_window_group = clutter_group_new();
    info->overlay_group = clutter_group_new ();
    info->top_window_group = meta_window_group_new (screen);
    info->hidden_group = clutter_group_new ();

    clutter_container_add (CLUTTER_CONTAINER (info->window_group),
                           info->background_actor,
                           NULL);

    clutter_container_add (CLUTTER_CONTAINER (info->stage),
                           info->window_group,
                           info->overlay_group,
                           info->hidden_group,
                           NULL);

    clutter_actor_hide (info->hidden_group);

    info->plugin_mgr =
        meta_plugin_manager_get (screen);
    meta_plugin_manager_initialize (info->plugin_mgr);

    /*
     * Delay the creation of the overlay window as long as we can, to avoid
     * blanking out the screen. This means that during the plugin loading, the
     * overlay window is not accessible; if the plugin needs to access it
     * directly, it should hook into the "show" signal on stage, and do
     * its stuff there.
     */
    info->output = get_output_window (screen);
    XReparentWindow (xdisplay, xwin, info->output, 0, 0);

    /* Make sure there isn't any left-over output shape on the
     * overlay window by setting the whole screen to be an
     * output region.
     *
     * 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.
     */
    XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);

    do_set_stage_input_region (screen, info->pending_input_region);
    if (info->pending_input_region != None)
    {
        XFixesDestroyRegion (xdisplay, info->pending_input_region);
        info->pending_input_region = None;
    }

    clutter_actor_show (info->overlay_group);
    clutter_actor_show (info->stage);
}