void
mnb_zones_preview_add_window (MnbZonesPreview *preview,
                              MetaWindow    *window)
{
  ClutterActor *clone;
  ClutterActor *group;
  MetaRectangle rect;
  MetaWorkspace *workspace;

  /* TODO: Determine if we need to add a weak reference on the window
   *       in case it gets destroyed during the animation.
   *       I'd have thought that the clone's reference on the texture
   *       would be enough that this wouldn't be necessary.
   *
   * We do; while the clone's reference is enough to keep the texture about,
   * it is not enough to make it possible to map the clone once the texture
   * has been unparented.
   */
  workspace = meta_window_get_workspace (window);
  group = mnb_zones_preview_get_workspace_group (preview, meta_workspace_index(workspace));

  clone = clutter_clone_new (CLUTTER_ACTOR(window));

  g_signal_connect (window, "destroy",
                    G_CALLBACK (mnb_zones_preview_mcw_destroy_cb),
                    clone);
  g_signal_connect (clone, "destroy",
                    G_CALLBACK (mnb_zones_preview_clone_destroy_cb),
                    window);

  meta_window_get_outer_rect (window, &rect);
  clutter_actor_set_position (clone, rect.x, rect.y);

  clutter_actor_add_child (CLUTTER_ACTOR (group), clone);
}
//borrowed from gtk
static gint get_monitor_at_window(MetaWindow* window)
{
    gint num_monitors, i, area = 0, screen_num = -1;
    GdkRectangle win_rect;

    GdkScreen* screen = gdk_screen_get_default();

    meta_window_get_outer_rect(window, (MetaRectangle*)&win_rect);
    num_monitors = gdk_screen_get_n_monitors (screen);

    for (i=0; i<num_monitors; i++) {
        GdkRectangle tmp_monitor, intersect;

        gdk_screen_get_monitor_geometry (screen, i, &tmp_monitor);
        gdk_rectangle_intersect (&win_rect, &tmp_monitor, &intersect);

        if (intersect.width * intersect.height > area) { 
            area = intersect.width * intersect.height;
            screen_num = i;
        }
    }
    if (screen_num >= 0)
        return screen_num;
    else
        return get_nearest_monitor (screen,
                win_rect.x + win_rect.width / 2,
                win_rect.y + win_rect.height / 2);
}
static MetaDeepinClonedWidget* _clone_window(DeepinWorkspaceOverview* self, 
        MetaWindow* window)
{
    DeepinWorkspaceOverviewPrivate* priv = self->priv;
    GtkWidget* widget = meta_deepin_cloned_widget_new(window, TRUE);
    gtk_widget_set_sensitive(widget, TRUE);

    ClonedPrivateInfo* info = clone_get_info(widget);

    info->monitor = get_monitor_at_window(window);
    g_assert(info->monitor < priv->monitors->len);
    MonitorData* md = g_ptr_array_index(priv->monitors, info->monitor);
    g_ptr_array_add(md->clones, widget);

    MetaRectangle r;
    meta_window_get_outer_rect(window, &r);
    meta_deepin_cloned_widget_set_size(
            META_DEEPIN_CLONED_WIDGET(widget), r.width, r.height);
    meta_deepin_cloned_widget_set_render_frame(
            META_DEEPIN_CLONED_WIDGET(widget), TRUE);

    //it doesn't matter where we put it, since we'll move it very soon.
    deepin_fixed_put(DEEPIN_FIXED(self), widget, 0, 0);

    g_object_connect(G_OBJECT(widget),
            "signal::enter-notify-event", on_deepin_cloned_widget_entered, self,
            "signal::leave-notify-event", on_deepin_cloned_widget_leaved, self,
            "signal::motion-notify-event", on_deepin_cloned_widget_motion, self,
            "signal::button-release-event", on_deepin_cloned_widget_released, self,
            NULL);

    return META_DEEPIN_CLONED_WIDGET(widget);
}
Пример #4
0
/**
 * shell_global_get_focus_monitor:
 * @global: the #ShellGlobal
 *
 * Gets the bounding box of the monitor containing the window that
 * currently contains the keyboard focus.
 *
 * Return value: the bounding box of the focus monitor
 */
GdkRectangle *
shell_global_get_focus_monitor (ShellGlobal  *global)
{
  MetaScreen *screen = shell_global_get_screen (global);
  MetaDisplay *display = meta_screen_get_display (screen);
  MetaWindow *focus = meta_display_get_focus_window (display);
  MetaRectangle rect, wrect;
  int nmonitors, i;

  if (focus)
    {
      meta_window_get_outer_rect (focus, &wrect);
      nmonitors = meta_screen_get_n_monitors (screen);

      /* Find the monitor that the top-left corner of @focus is on. */
      for (i = 0; i < nmonitors; i++)
        {
          meta_screen_get_monitor_geometry (screen, i, &rect);

          if (rect.x <= wrect.x && rect.y <= wrect.y &&
              rect.x + rect.width > wrect.x &&
              rect.y + rect.height > wrect.y)
            return g_boxed_copy (GDK_TYPE_RECTANGLE, &rect);
        }
    }

  meta_screen_get_monitor_geometry (screen, 0, &rect);
  return g_boxed_copy (GDK_TYPE_RECTANGLE, &rect);
}
Пример #5
0
static gboolean
window_contains_point (MetaWindow *window,
                       int         root_x,
                       int         root_y)
{
  MetaRectangle rect;

  meta_window_get_outer_rect (window, &rect);

  return POINT_IN_RECT (root_x, root_y, rect);
}
Пример #6
0
static gboolean
rectangle_overlaps_some_window (MetaRectangle *rect,
                                GList         *windows)
{
  GList *tmp;
  MetaRectangle dest;
  
  tmp = windows;
  while (tmp != NULL)
    {
      MetaWindow *other = tmp->data;
      MetaRectangle other_rect;      

      switch (other->type)
        {
        case META_WINDOW_DOCK:
        case META_WINDOW_SPLASHSCREEN:
        case META_WINDOW_DESKTOP:
        case META_WINDOW_DIALOG:
        case META_WINDOW_MODAL_DIALOG:
	/* override redirect window types: */
	case META_WINDOW_DROPDOWN_MENU:
	case META_WINDOW_POPUP_MENU:
	case META_WINDOW_TOOLTIP:
	case META_WINDOW_NOTIFICATION:
	case META_WINDOW_COMBO:
	case META_WINDOW_DND:
	case META_WINDOW_OVERRIDE_OTHER:
          break;

        case META_WINDOW_NORMAL:
        case META_WINDOW_UTILITY:
        case META_WINDOW_TOOLBAR:
        case META_WINDOW_MENU:
          if (!meta_window_is_override_redirect(other)) {
            meta_window_get_outer_rect (other, &other_rect);
            
            if (meta_rectangle_intersect (rect, &other_rect, &dest))
              return TRUE;
          }
          break;
        }
      
      tmp = tmp->next;
    }

  return FALSE;
}
Пример #7
0
static gboolean
rectangle_overlaps_some_window (MetaRectangle *rect,
                                GList         *windows)
{
  GList *tmp;
  MetaRectangle dest;

  tmp = windows;
  while (tmp != NULL)
    {
      MetaWindow *other = tmp->data;
      MetaRectangle other_rect;

      switch (other->type)
        {
        case META_WINDOW_DOCK:
        case META_WINDOW_SPLASHSCREEN:
        case META_WINDOW_DESKTOP:
        case META_WINDOW_DIALOG:
        case META_WINDOW_MODAL_DIALOG:
          break;

        case META_WINDOW_NORMAL:
        case META_WINDOW_UTILITY:
        case META_WINDOW_TOOLBAR:
        case META_WINDOW_MENU:
          meta_window_get_outer_rect (other, &other_rect);

          if (meta_rectangle_intersect (rect, &other_rect, &dest))
            return TRUE;
          break;

        default:
          break;
        }

      tmp = tmp->next;
    }

  return FALSE;
}
Пример #8
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);
    }
}
Пример #9
0
static void
meta_window_group_paint (ClutterActor *actor)
{
  cairo_region_t *clip_region;
  cairo_region_t *unobscured_region;
  ClutterActorIter iter;
  ClutterActor *child;
  cairo_rectangle_int_t visible_rect, clip_rect;
  int paint_x_offset, paint_y_offset;
  int paint_x_origin, paint_y_origin;
  int actor_x_origin, actor_y_origin;

  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
  MetaCompositor *compositor = window_group->screen->display->compositor;
  ClutterActor *stage = CLUTTER_STAGE (compositor->stage);

  /* Start off by treating all windows as completely unobscured, so damage anywhere
   * in a window queues redraws, but confine it more below. */
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_next (&iter, &child))
    {
      if (META_IS_WINDOW_ACTOR (child))
        {
          MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
          meta_window_actor_set_unobscured_region (window_actor, NULL);
        }
    }

  /* 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 (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) ||
      !meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin))
    {
      CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
      return;
    }

  paint_x_offset = paint_x_origin - actor_x_origin;
  paint_y_offset = paint_y_origin - actor_y_origin;

  visible_rect.x = visible_rect.y = 0;
  visible_rect.width = clutter_actor_get_width (stage);
  visible_rect.height = clutter_actor_get_height (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 (stage, &clip_rect);

  clip_region = cairo_region_create_rectangle (&clip_rect);

  cairo_region_translate (clip_region, -paint_x_offset, -paint_y_offset);

  gboolean has_unredirected_window = compositor->unredirected_window != NULL;
  if (has_unredirected_window)
    {
      cairo_rectangle_int_t unredirected_rect;
      MetaWindow *window = meta_window_actor_get_meta_window (compositor->unredirected_window);

      meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
      cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
      cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
    }

  meta_window_group_cull_out (window_group,
                              CLUTTER_ACTOR (compositor->unredirected_window),
                              has_unredirected_window,
                              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_window_group_reset_culling (window_group);
}
Пример #10
0
static void
meta_window_group_paint (ClutterActor *actor)
{
  cairo_region_t *visible_region;
  ClutterActor *stage;
  cairo_rectangle_int_t visible_rect;
  GList *children, *l;
  int paint_x_origin, paint_y_origin;
  int actor_x_origin, actor_y_origin;
  int paint_x_offset, paint_y_offset;

  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
  MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);

  /* 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 (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) ||
      !meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin))
    {
      CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
      return;
    }

  paint_x_offset = paint_x_origin - actor_x_origin;
  paint_y_offset = paint_y_origin - actor_y_origin;

  /* We walk the list from top to bottom (opposite of painting order),
   * and subtract the opaque area of each window out of the visible
   * region that we pass to the windows below.
   */
  children = clutter_actor_get_children (actor);
  children = g_list_reverse (children);

  /* 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. */
  stage = clutter_actor_get_stage (actor);
  clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
                                        &visible_rect);

  visible_region = cairo_region_create_rectangle (&visible_rect);

  if (info->unredirected_window != NULL)
    {
      cairo_rectangle_int_t unredirected_rect;
      MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);

      meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
      cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
    }

  for (l = children; l; l = l->next)
    {
      if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
        continue;

      if (l->data == info->unredirected_window)
        continue;

      /* If an actor has effects applied, then that can change the area
       * it paints and the opacity, so we no longer can figure out what
       * portion of the actor is obscured and what portion of the screen
       * it obscures, so we skip the actor.
       *
       * This has a secondary beneficial effect: if a ClutterOffscreenEffect
       * is applied to an actor, then our clipped redraws interfere with the
       * caching of the FBO - even if we only need to draw a small portion
       * of the window right now, ClutterOffscreenEffect may use other portions
       * of the FBO later. So, skipping actors with effects applied also
       * prevents these bugs.
       *
       * Theoretically, we should check clutter_actor_get_offscreen_redirect()
       * as well for the same reason, but omitted for simplicity in the
       * hopes that no-one will do that.
       */
      if (clutter_actor_has_effects (l->data))
        continue;

      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          int x, y;

          if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
            continue;

          x += paint_x_offset;
          y += paint_y_offset;

          /* Temporarily move to the coordinate system of the actor */
          cairo_region_translate (visible_region, - x, - y);

          meta_window_actor_set_visible_region (window_actor, visible_region);

          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
            {
              cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
              if (obscured_region)
                cairo_region_subtract (visible_region, obscured_region);
            }

          meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
          cairo_region_translate (visible_region, x, y);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data) ||
               META_IS_BACKGROUND_GROUP (l->data))
        {
          ClutterActor *background_actor = l->data;
          int x, y;

          if (!meta_actor_is_untransformed (CLUTTER_ACTOR (background_actor), &x, &y))
            continue;

          x += paint_x_offset;
          y += paint_y_offset;

          cairo_region_translate (visible_region, - x, - y);

          if (META_IS_BACKGROUND_GROUP (background_actor))
            meta_background_group_set_visible_region (META_BACKGROUND_GROUP (background_actor), visible_region);
          else
            meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (background_actor), visible_region);
          cairo_region_translate (visible_region, x, y);
        }
    }

  cairo_region_destroy (visible_region);

  CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);

  /* Now that we are done painting, unset the visible regions (they will
   * mess up painting clones of our actors)
   */
  for (l = children; l; l = l->next)
    {
      if (META_IS_WINDOW_ACTOR (l->data))
        {
          MetaWindowActor *window_actor = l->data;
          meta_window_actor_reset_visible_regions (window_actor);
        }
      else if (META_IS_BACKGROUND_ACTOR (l->data))
        {
          MetaBackgroundActor *background_actor = l->data;
          meta_background_actor_set_visible_region (background_actor, NULL);
        }
    }

  g_list_free (children);
}
//TODO: response to screen-changed?
void deepin_workspace_overview_populate(DeepinWorkspaceOverview* self,
        MetaWorkspace* ws)
{
    DeepinWorkspaceOverviewPrivate* priv = self->priv;
    priv->workspace = ws;

    GdkScreen* screen = gdk_screen_get_default();
    priv->primary = gdk_screen_get_primary_monitor(screen);
    gint n_monitors = gdk_screen_get_n_monitors(screen);
    priv->monitors = g_ptr_array_new_full(n_monitors, monitor_data_destroy);
    for (int i = 0; i < n_monitors; i++) {
        MonitorData* md = monitor_data_new();
        g_ptr_array_add(priv->monitors, md);
        md->monitor = i;
        md->clones = g_ptr_array_new();
        gdk_screen_get_monitor_geometry(screen, i, (GdkRectangle*)&md->mon_rect);

        /**
         * gdk_screen_get_monitor_workarea fails to honor struts, so I have to use xinerama
         * to get correct workarea
         */

        const MetaXineramaScreenInfo* xinerama = meta_screen_get_xinerama_for_rect(ws->screen, &md->mon_rect);
        meta_workspace_get_work_area_for_xinerama(ws, xinerama->number, (GdkRectangle*)&md->mon_workarea);
    }

    GList* ls = meta_stack_list_windows(ws->screen->stack,
            priv->all_window_mode? NULL: ws);
    GList* l = ls;
    while (l) {
        MetaWindow* win = (MetaWindow*)l->data;
        if (win->type == META_WINDOW_NORMAL) {
            if (priv->present_xids && g_hash_table_size(priv->present_xids)) {
                if (g_hash_table_contains(priv->present_xids, GINT_TO_POINTER(win->xwindow))) {
                    _clone_window(self, win);
                }
            } else {
                _clone_window(self, win);
            }
        }

        l = l->next;
    }
    g_list_free(ls);

    {
        priv->close_button = gtk_event_box_new();
        gtk_event_box_set_above_child(GTK_EVENT_BOX(priv->close_button), FALSE);
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(priv->close_button), FALSE);

        GtkWidget* image = gtk_image_new_from_file(METACITY_PKGDATADIR "/close.png");
        gtk_container_add(GTK_CONTAINER(priv->close_button), image);

        deepin_fixed_put(DEEPIN_FIXED(self), priv->close_button, 0, 0);
        gtk_widget_set_opacity(self->priv->close_button, 0.0);

        g_object_connect(G_OBJECT(priv->close_button), 
                "signal::leave-notify-event", on_close_button_leaved, self,
                "signal::button-release-event", on_close_button_clicked, self,
                NULL);
    }


    priv->dock_height = 0;
    MetaWindow *desktop_win = NULL, *dock_win = NULL;

    GList* windows = priv->workspace->mru_list;
    while (windows != NULL) {
        MetaWindow *w = (MetaWindow*)windows->data;
        if (w->type == META_WINDOW_DESKTOP) {
            desktop_win = w;
        }

        if (w->type == META_WINDOW_DOCK) {
            dock_win = w;
        }

        if (desktop_win && dock_win) break;
        windows = windows->next;
    }

    for (int i = 0; i < n_monitors; i++) {
        MonitorData* md = (MonitorData*)g_ptr_array_index(priv->monitors, i);
        if (i == priv->primary) {
            MetaRectangle r1 = {0, 0, 0, 0}, r2 = {0, 0, 0, 0};
            cairo_surface_t* aux1 = NULL, *aux2 = NULL;

            if (desktop_win) {
                meta_window_get_outer_rect(desktop_win, &r1);
                aux1 = deepin_window_surface_manager_get_surface(desktop_win, 1.0); 
                r1.x -= md->mon_rect.x;
                r1.y -= md->mon_rect.y;
                meta_verbose ("%s: desktop offset(%d, %d)\n", __func__, r1.x, r1.y);
            }

            if (dock_win) {
                meta_window_get_outer_rect(dock_win, &r2);
                aux2 = deepin_window_surface_manager_get_surface(dock_win, 1.0); 
                priv->dock_height = r2.height;
                r2.x -= md->mon_rect.x;
                r2.y -= md->mon_rect.y;
                meta_verbose ("%s: dock offset(%d, %d)\n", __func__, r2.x, r2.y);
            }
            md->desktop_surface = deepin_window_surface_manager_get_combined3(
                    deepin_background_cache_get_surface(md->monitor, 1.0), 
                    aux1, r1.x, r1.y,
                    aux2, r2.x, r2.y,
                    1.0);
        } else {
            md->desktop_surface = deepin_background_cache_get_surface(md->monitor, 1.0);
            cairo_surface_reference(md->desktop_surface);
        }
    }

    gtk_widget_queue_resize(GTK_WIDGET(self));
}
Пример #12
0
/**
 * shell_screenshot_screenshot_window:
 * @screenshot: the #ShellScreenshot
 * @include_frame: Whether to include the frame or not
 * @include_cursor: Whether to include the cursor or not
 * @filename: The filename for the screenshot
 * @callback: (scope async): function to call returning success or failure
 * of the async grabbing
 *
 * Takes a screenshot of the focused window (optionally omitting the frame)
 * in @filename as png image.
 *
 */
void
shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
                                    gboolean include_frame,
                                    gboolean include_cursor,
                                    const char *filename,
                                    ShellScreenshotCallback callback)
{
  GSimpleAsyncResult *result;
  GSettings *settings;

  _screenshot_data *screenshot_data = g_new0 (_screenshot_data, 1);

  MetaScreen *screen = shell_global_get_screen (screenshot->global);
  MetaCursorTracker *tracker;
  MetaDisplay *display = meta_screen_get_display (screen);
  MetaWindow *window = meta_display_get_focus_window (display);
  ClutterActor *window_actor;
  gfloat actor_x, actor_y;
  MetaShapedTexture *stex;
  MetaRectangle rect;
  cairo_rectangle_int_t clip;

  screenshot_data->screenshot = g_object_ref (screenshot);
  screenshot_data->filename = g_strdup (filename);
  screenshot_data->callback = callback;

  if (!window)
    {
      screenshot_data->filename_used = g_strdup ("");
      result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
      g_simple_async_result_set_op_res_gboolean (result, FALSE);
      g_simple_async_result_complete (result);
      g_object_unref (result);

      return;
    }

  window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
  clutter_actor_get_position (window_actor, &actor_x, &actor_y);

  if (include_frame || !meta_window_get_frame (window))
    {
      meta_window_get_outer_rect (window, &rect);

      screenshot_data->screenshot_area.x = rect.x;
      screenshot_data->screenshot_area.y = rect.y;

      clip.x = rect.x - (gint) actor_x;
      clip.y = rect.y - (gint) actor_y;
    }
  else
    {
      rect = *meta_window_get_rect (window);

      screenshot_data->screenshot_area.x = (gint) actor_x + rect.x;
      screenshot_data->screenshot_area.y = (gint) actor_y + rect.y;

      clip.x = rect.x;
      clip.y = rect.y;
    }

  clip.width = screenshot_data->screenshot_area.width = rect.width;
  clip.height = screenshot_data->screenshot_area.height = rect.height;

  stex = META_SHAPED_TEXTURE (meta_window_actor_get_texture (META_WINDOW_ACTOR (window_actor)));
  screenshot_data->image = meta_shaped_texture_get_image (stex, &clip);

  settings = g_settings_new (A11Y_APPS_SCHEMA);
  if (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);

  result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
  g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
  g_object_unref (result);
}
Пример #13
0
void
meta_window_place (MetaWindow        *window,
                   MetaFrameGeometry *fgeom,
                   int                x,
                   int                y,
                   int               *new_x,
                   int               *new_y)
{
  GList *windows;
  const MetaXineramaScreenInfo *xi;

  /* frame member variables should NEVER be used in here, only
   * MetaFrameGeometry. But remember fgeom == NULL
   * for undecorated windows. Also, this function should
   * NEVER have side effects other than computing the
   * placement coordinates.
   */
  
  meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc);

  windows = NULL;
  
  switch (window->type)
    {
      /* Run placement algorithm on these. */
    case META_WINDOW_NORMAL:
    case META_WINDOW_DIALOG:
    case META_WINDOW_MODAL_DIALOG:
    case META_WINDOW_SPLASHSCREEN:
      break;
          
      /* Assume the app knows best how to place these, no placement
       * algorithm ever (other than "leave them as-is")
       */
    case META_WINDOW_DESKTOP:
    case META_WINDOW_DOCK:
    case META_WINDOW_TOOLBAR:
    case META_WINDOW_MENU:
    case META_WINDOW_UTILITY:
      goto done_no_constraints;
    }
  
  if (meta_prefs_get_disable_workarounds ())
    {
      switch (window->type)
        {
          /* Only accept USPosition on normal windows because the app is full
           * of shit claiming the user set -geometry for a dialog or dock
           */
        case META_WINDOW_NORMAL:
          if (window->size_hints.flags & USPosition)
            {
              /* don't constrain with placement algorithm */
              meta_topic (META_DEBUG_PLACEMENT,
                          "Honoring USPosition for %s instead of using placement algorithm\n", window->desc);

              goto done;
            }
          break;

          /* Ignore even USPosition on dialogs, splashscreen */
        case META_WINDOW_DIALOG:
        case META_WINDOW_MODAL_DIALOG:
        case META_WINDOW_SPLASHSCREEN:
          break;
          
          /* Assume the app knows best how to place these. */
        case META_WINDOW_DESKTOP:
        case META_WINDOW_DOCK:
        case META_WINDOW_TOOLBAR:
        case META_WINDOW_MENU:
        case META_WINDOW_UTILITY:
          if (window->size_hints.flags & PPosition)
            {
              meta_topic (META_DEBUG_PLACEMENT,
                          "Not placing non-normal non-dialog window with PPosition set\n");
              goto done_no_constraints;
            }
          break;
        }
    }
  else
    {
      /* workarounds enabled */
      
      if ((window->size_hints.flags & PPosition) ||
          (window->size_hints.flags & USPosition))
        {
          meta_topic (META_DEBUG_PLACEMENT,
                      "Not placing window with PPosition or USPosition set\n");
          avoid_being_obscured_as_second_modal_dialog (window, fgeom, &x, &y);
          goto done_no_constraints;
        }
    }
  
  if ((window->type == META_WINDOW_DIALOG ||
       window->type == META_WINDOW_MODAL_DIALOG) &&
      window->xtransient_for != None)
    {
      /* Center horizontally, at top of parent vertically */

      MetaWindow *parent;
          
      parent =
        meta_display_lookup_x_window (window->display,
                                      window->xtransient_for);

      if (parent)
        {
          int w;

          meta_window_get_position (parent, &x, &y);
          w = parent->rect.width;

          /* center of parent */
          x = x + w / 2;
          /* center of child over center of parent */
          x -= window->rect.width / 2;

          /* "visually" center window over parent, leaving twice as
           * much space below as on top.
           */
          y += (parent->rect.height - window->rect.height)/3;

          /* put top of child's frame, not top of child's client */
          if (fgeom)
            y += fgeom->top_height;

          meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n",
                      window->desc);
          
          avoid_being_obscured_as_second_modal_dialog (window, fgeom, &x, &y);

          goto done;
        }
    }
  
  /* FIXME UTILITY with transient set should be stacked up
   * on the sides of the parent window or something.
   */
  
  if (window->type == META_WINDOW_DIALOG ||
      window->type == META_WINDOW_MODAL_DIALOG ||
      window->type == META_WINDOW_SPLASHSCREEN)
    {
      /* Center on current xinerama (i.e. on current monitor) */
      int w, h;

      /* Warning, this function is a round trip! */
      xi = meta_screen_get_current_xinerama (window->screen);

      w = xi->rect.width;
      h = xi->rect.height;

      x = (w - window->rect.width) / 2;
      y = (h - window->rect.height) / 2;

      x += xi->rect.x;
      y += xi->rect.y;
      
      meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d xinerama %d\n",
                  window->desc, window->screen->number, xi->number);

      goto done_check_denied_focus;
    }
  
  /* Find windows that matter (not minimized, on same workspace
   * as placed window, may be shaded - if shaded we pretend it isn't
   * for placement purposes)
   */
  {
    GSList *all_windows;
    GSList *tmp;
    
    all_windows = meta_display_list_windows (window->display);

    tmp = all_windows;
    while (tmp != NULL)
      {
        MetaWindow *w = tmp->data;

        if (meta_window_showing_on_its_workspace (w) &&
            w != window && 
            (window->workspace == w->workspace ||
             window->on_all_workspaces || w->on_all_workspaces))
          windows = g_list_prepend (windows, w);

        tmp = tmp->next;
      }

    g_slist_free (all_windows);
  }

  /* Warning, this is a round trip! */
  xi = meta_screen_get_current_xinerama (window->screen);
  
  /* "Origin" placement algorithm */
  x = xi->rect.x;
  y = xi->rect.y;

  if (find_first_fit (window, fgeom, windows,
                      xi->number,
                      x, y, &x, &y))
    goto done_check_denied_focus;

  /* Maximize windows if they are too big for their work area (bit of
   * a hack here). Assume undecorated windows probably don't intend to
   * be maximized.  
   */
  if (window->has_maximize_func && window->decorated &&
      !window->fullscreen)
    {
      MetaRectangle workarea;
      MetaRectangle outer;

      meta_window_get_work_area_for_xinerama (window,
                                              xi->number,
                                              &workarea);      
      meta_window_get_outer_rect (window, &outer);
      
      /* If the window is bigger than the screen, then automaximize.  Do NOT
       * auto-maximize the directions independently.  See #419810.
       */
      if (outer.width >= workarea.width && outer.height >= workarea.height)
        {
          window->maximize_horizontally_after_placement = TRUE;
          window->maximize_vertically_after_placement = TRUE;
        }
    }

  /* If no placement has been done, revert to cascade to avoid 
   * fully overlapping window (e.g. starting multiple terminals)
   * */
  if (!meta_prefs_get_center_new_windows() && (x == xi->rect.x && y == xi->rect.y))
    find_next_cascade (window, fgeom, windows, x, y, &x, &y);

 done_check_denied_focus:
  /* If the window is being denied focus and isn't a transient of the
   * focus window, we do NOT want it to overlap with the focus window
   * if at all possible.  This is guaranteed to only be called if the
   * focus_window is non-NULL, and we try to avoid that window.
   */
  if (window->denied_focus_and_not_transient)
    {
      gboolean       found_fit;
      MetaWindow    *focus_window;
      MetaRectangle  overlap;

      focus_window = window->display->focus_window;
      g_assert (focus_window != NULL);

      /* No need to do anything if the window doesn't overlap at all */
      found_fit = !meta_rectangle_intersect (&window->rect,
                                             &focus_window->rect,
                                             &overlap);

      /* Try to do a first fit again, this time only taking into account the
       * focus window.
       */
      if (!meta_prefs_get_center_new_windows() && !found_fit)
        {
          GList *focus_window_list;
          focus_window_list = g_list_prepend (NULL, focus_window);

          /* Reset x and y ("origin" placement algorithm) */
          x = xi->rect.x;
          y = xi->rect.y;

          found_fit = find_first_fit (window, fgeom, focus_window_list,
                                      xi->number,
                                      x, y, &x, &y);
          g_list_free (focus_window_list);
	}

      /* If that still didn't work, just place it where we can see as much
       * as possible.
       */
      if (!found_fit)
        find_most_freespace (window, fgeom, focus_window, x, y, &x, &y);
    }
  
 done:
  g_list_free (windows);
  
 done_no_constraints:

  *new_x = x;
  *new_y = y;
}
Пример #14
0
/* Find the leftmost, then topmost, empty area on the workspace
 * that can contain the new window.
 *
 * Cool feature to have: if we can't fit the current window size,
 * try shrinking the window (within geometry constraints). But
 * beware windows such as Emacs with no sane minimum size, we
 * don't want to create a 1x1 Emacs.
 */
static gboolean
find_first_fit (MetaWindow *window,
                MetaFrameGeometry *fgeom,
                /* visible windows on relevant workspaces */
                GList      *windows,
		int         xinerama,
                int         x,
                int         y,
                int        *new_x,
                int        *new_y)
{
  /* This algorithm is limited - it just brute-force tries
   * to fit the window in a small number of locations that are aligned
   * with existing windows. It tries to place the window on
   * the bottom of each existing window, and then to the right
   * of each existing window, aligned with the left/top of the
   * existing window in each of those cases.
   */  
  int retval;
  GList *below_sorted;
  GList *right_sorted;
  GList *tmp;
  MetaRectangle rect;
  MetaRectangle work_area;
  
  retval = FALSE;

  /* Below each window */
  below_sorted = g_list_copy (windows);
  below_sorted = g_list_sort (below_sorted, leftmost_cmp);
  below_sorted = g_list_sort (below_sorted, topmost_cmp);  

  /* To the right of each window */
  right_sorted = g_list_copy (windows);
  right_sorted = g_list_sort (right_sorted, topmost_cmp);
  right_sorted = g_list_sort (right_sorted, leftmost_cmp);
  
  rect.width = window->rect.width;
  rect.height = window->rect.height;
  
  if (fgeom)
    {
      rect.width += fgeom->left_width + fgeom->right_width;
      rect.height += fgeom->top_height + fgeom->bottom_height;
    }

#ifdef WITH_VERBOSE_MODE
    {
      char xinerama_location_string[RECT_LENGTH];
      meta_rectangle_to_string (&window->screen->xinerama_infos[xinerama].rect,
                                xinerama_location_string);
      meta_topic (META_DEBUG_XINERAMA,
		  "Natural xinerama is %s\n",
		  xinerama_location_string);
    }
#endif

    meta_window_get_work_area_for_xinerama (window, xinerama, &work_area);

    if (meta_prefs_get_center_new_windows ())
      center_rect_in_area (&rect, &work_area);
    else
      center_tile_rect_in_area (&rect, &work_area);

    if (meta_rectangle_contains_rect (&work_area, &rect) &&
        (meta_prefs_get_center_new_windows () ||
         !rectangle_overlaps_some_window (&rect, windows)))
      {
        *new_x = rect.x;
        *new_y = rect.y;
        if (fgeom)
          {
            *new_x += fgeom->left_width;
            *new_y += fgeom->top_height;
          }
    
        retval = TRUE;
       
        goto out;
      }

    /* try below each window */
    tmp = below_sorted;
    while (tmp != NULL)
      {
        MetaWindow *w = tmp->data;
        MetaRectangle outer_rect;

        meta_window_get_outer_rect (w, &outer_rect);
      
        rect.x = outer_rect.x;
        rect.y = outer_rect.y + outer_rect.height;
      
        if (meta_rectangle_contains_rect (&work_area, &rect) &&
            !rectangle_overlaps_some_window (&rect, below_sorted))
          {
            *new_x = rect.x;
            *new_y = rect.y;
            if (fgeom)
              {
                *new_x += fgeom->left_width;
                *new_y += fgeom->top_height;
              }
          
            retval = TRUE;
          
            goto out;
          }

        tmp = tmp->next;
      }

    /* try to the right of each window */
    tmp = right_sorted;
    while (tmp != NULL)
      {
        MetaWindow *w = tmp->data;
        MetaRectangle outer_rect;
   
        meta_window_get_outer_rect (w, &outer_rect);
     
        rect.x = outer_rect.x + outer_rect.width;
        rect.y = outer_rect.y;
   
        if (meta_rectangle_contains_rect (&work_area, &rect) &&
            !rectangle_overlaps_some_window (&rect, right_sorted))
          {
            *new_x = rect.x;
            *new_y = rect.y;
            if (fgeom)
              {
                *new_x += fgeom->left_width;
                *new_y += fgeom->top_height;
              }
        
            retval = TRUE;
       
            goto out;
          }

        tmp = tmp->next;
      }
      
 out:

  g_list_free (below_sorted);
  g_list_free (right_sorted);
  return retval;
}
Пример #15
0
static void
find_most_freespace (MetaWindow *window,
                     MetaFrameGeometry *fgeom,
                     /* visible windows on relevant workspaces */
                     MetaWindow *focus_window,
                     int         x,
                     int         y,
                     int        *new_x,
                     int        *new_y)
{
  MetaWindowDirection side;
  int max_area;
  int max_width, max_height, left, right, top, bottom;
  int left_space, right_space, top_space, bottom_space;
  int frame_size_left, frame_size_top;
  MetaRectangle work_area;
  MetaRectangle avoid;
  MetaRectangle outer;

  frame_size_left = fgeom ? fgeom->left_width : 0;
  frame_size_top  = fgeom ? fgeom->top_height : 0;

  meta_window_get_work_area_current_xinerama (focus_window, &work_area);
  meta_window_get_outer_rect (focus_window, &avoid);
  meta_window_get_outer_rect (window, &outer);

  /* Find the areas of choosing the various sides of the focus window */
  max_width  = MIN (avoid.width, outer.width);
  max_height = MIN (avoid.height, outer.height);
  left_space   = avoid.x - work_area.x;
  right_space  = work_area.width - (avoid.x + avoid.width - work_area.x);
  top_space    = avoid.y - work_area.y;
  bottom_space = work_area.height - (avoid.y + avoid.height - work_area.y);
  left   = MIN (left_space,   outer.width);
  right  = MIN (right_space,  outer.width);
  top    = MIN (top_space,    outer.height);
  bottom = MIN (bottom_space, outer.height);

  /* Find out which side of the focus_window can show the most of the window */
  side = META_LEFT;
  max_area = left*max_height;
  if (right*max_height > max_area)
    {
      side = META_RIGHT;
      max_area = right*max_height;
    }
  if (top*max_width > max_area)
    {
      side = META_TOP;
      max_area = top*max_width;
    }
  if (bottom*max_width > max_area)
    {
      side = META_BOTTOM;
      max_area = bottom*max_width;
    }

  /* Give up if there's no where to put it (i.e. focus window is maximized) */
  if (max_area == 0)
    return;

  /* Place the window on the relevant side; if the whole window fits,
   * make it adjacent to the focus window; if not, make sure the
   * window doesn't go off the edge of the screen.
   */
  switch (side)
    {
    case META_LEFT:
      *new_y = avoid.y + frame_size_top;
      if (left_space > outer.width)
        *new_x = avoid.x - outer.width + frame_size_left;
      else
        *new_x = work_area.x + frame_size_left;
      break;
    case META_RIGHT:
      *new_y = avoid.y + frame_size_top;
      if (right_space > outer.width)
        *new_x = avoid.x + avoid.width + frame_size_left;
      else
        *new_x = work_area.x + work_area.width - outer.width + frame_size_left;
      break;
    case META_TOP:
      *new_x = avoid.x + frame_size_left;
      if (top_space > outer.height)
        *new_y = avoid.y - outer.height + frame_size_top;
      else
        *new_y = work_area.y + frame_size_top;
      break;
    case META_BOTTOM:
      *new_x = avoid.x + frame_size_left;
      if (bottom_space > outer.height)
        *new_y = avoid.y + avoid.height + frame_size_top;
      else
        *new_y = work_area.y + work_area.height - outer.height + frame_size_top;
      break;
    }
}