예제 #1
0
static void calculate_places(MosesOverview* self)
{
    MosesOverviewPrivate* priv = self->priv;
    GPtrArray* clones = priv->clones;
    if (priv->clones->len) {
        g_ptr_array_sort(clones, window_compare);

        // get the area used by the expo algorithms together
        MetaScreen* screen = meta_plugin_get_screen(priv->plugin);

        MetaRectangle geom;
        int focused_monitor = meta_screen_get_current_monitor(screen);
        meta_screen_get_monitor_geometry(screen, focused_monitor, &geom);

        int HEAD_SIZE = TOP_GAP;
        g_object_get(priv->ov_head, "height", &HEAD_SIZE, NULL);
        g_debug("%s ov height: %d", __func__, HEAD_SIZE);
        MetaRectangle area = {(int)floorf (geom.x + BORDER),
                              (int)floorf (geom.y + TOP_GAP + HEAD_SIZE),
                              (int)floorf (geom.width - BORDER * 2),
                              (int)floorf (geom.height - BOTTOM_GAP - TOP_GAP - HEAD_SIZE)};

        natural_placement(self, area);

    } else {
        //NOTE: I can not set ready flag here because a conflict of super-e key release
        g_timeout_add(500, (GSourceFunc)on_ready_timeout, self);
    }
    clutter_actor_show(overview_head_get_content(priv->ov_head));
}
예제 #2
0
static void overview_animated_destroy(MosesOverview* self, MosesOverviewQuitReason reason, gboolean animate)
{
    MosesOverviewPrivate* priv = self->priv;

    gboolean just_destroy = !animate;
    if (reason == MOSES_OV_REASON_ACTIVATE_WINDOW && !priv->selected_actor) {
        just_destroy = TRUE;
    } else if (reason == MOSES_OV_REASON_ACTIVATE_WORKSPACE && !priv->selected_workspace) {
        just_destroy = TRUE;
    } else if (reason == MOSES_OV_REASON_NORMAL) {
        just_destroy = TRUE;
    }

    if (just_destroy) {
        clutter_actor_destroy(CLUTTER_ACTOR(self));
        return;
    }

    gfloat x, y, w, h;
    ClutterActor* target = NULL;

    if (reason == MOSES_OV_REASON_ACTIVATE_WINDOW) {
        target = self->priv->selected_actor;

        ClutterActor* orig = clutter_clone_get_source(CLUTTER_CLONE(target));
        clutter_actor_get_position(orig, &x, &y);
        clutter_actor_get_size(orig, &w, &h);
        g_signal_handlers_disconnect_by_func(target, on_effect_complete, self);

    } else if (reason == MOSES_OV_REASON_ACTIVATE_WORKSPACE) {
        g_assert(priv->selected_actor == NULL);

        MetaScreen* screen = meta_plugin_get_screen(priv->plugin);
        target = overview_head_get_actor_for_workspace(priv->ov_head, priv->selected_workspace);

        MetaRectangle geom;
        int focused_monitor = meta_screen_get_current_monitor(screen);
        meta_screen_get_monitor_geometry(screen, focused_monitor, &geom);
        x = geom.x, y = geom.y, w = geom.width, h = geom.height;
    }

    if (target) {
        clutter_actor_remove_all_transitions(target);
        clutter_actor_set_child_above_sibling(clutter_actor_get_parent(target), target, NULL);

        clutter_actor_save_easing_state(target);
        clutter_actor_set_easing_mode(target, CLUTTER_LINEAR);
        clutter_actor_set_easing_duration(target, 150);

        clutter_actor_set_position(target, x, y);
        clutter_actor_set_scale(target, w / clutter_actor_get_width(target),
                h / clutter_actor_get_height(target));
        clutter_actor_restore_easing_state(target);
        g_object_connect(target, "signal::transitions-completed",
                G_CALLBACK(on_restore_position_effect_complete), self, NULL);
    }
}
예제 #3
0
void moses_overview_show(MosesOverview* self, gboolean all_windows)
{
    MosesOverviewPrivate* priv = self->priv;

    MetaRectangle geom;
    MetaScreen* screen = meta_plugin_get_screen(priv->plugin);
    int focused_monitor = meta_screen_get_current_monitor(screen);
    meta_screen_get_monitor_geometry(screen, focused_monitor, &geom);

    // FIXME: overview is as big as the current monitor,
    // need to take care multiple monitors
    ClutterActor* stage = meta_get_stage_for_screen(screen);
    ClutterActor* top = CLUTTER_ACTOR(self);
    clutter_actor_set_size(top, geom.width, geom.height);
    clutter_actor_insert_child_above(stage, top, NULL);

    moses_overview_setup(self);
    priv->previous_focused = clutter_stage_get_key_focus(CLUTTER_STAGE(stage));

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

    meta_disable_unredirect_for_screen(screen);

    clutter_actor_show(top);
    clutter_stage_set_key_focus(CLUTTER_STAGE(stage), top);
    clutter_actor_grab_key_focus(top);

    priv->modaled = TRUE;
    g_idle_add((GSourceFunc)on_idle, self);

    return;

_end:
    clutter_actor_destroy(CLUTTER_ACTOR(self));
}
예제 #4
0
파일: place.c 프로젝트: kelsieflynn/mutter
static void
find_next_cascade (MetaWindow *window,
                   /* visible windows on relevant workspaces */
                   GList      *windows,
                   int         x,
                   int         y,
                   int        *new_x,
                   int        *new_y)
{
  GList *tmp;
  GList *sorted;
  int cascade_x, cascade_y;
  MetaRectangle titlebar_rect;
  int x_threshold, y_threshold;
  MetaRectangle frame_rect;
  int window_width, window_height;
  int cascade_stage;
  MetaRectangle work_area;
  int current;

  sorted = g_list_copy (windows);
  sorted = g_list_sort (sorted, northwestcmp);

  /* This is a "fuzzy" cascade algorithm.
   * For each window in the list, we find where we'd cascade a
   * new window after it. If a window is already nearly at that
   * position, we move on.
   */

  /* arbitrary-ish threshold, honors user attempts to
   * manually cascade.
   */
#define CASCADE_FUZZ 15
  meta_window_get_titlebar_rect (window, &titlebar_rect);
  x_threshold = MAX (titlebar_rect.x, CASCADE_FUZZ);
  y_threshold = MAX (titlebar_rect.y, CASCADE_FUZZ);

  /* Find furthest-SE origin of all workspaces.
   * cascade_x, cascade_y are the target position
   * of NW corner of window frame.
   */

  current = meta_screen_get_current_monitor (window->screen);
  meta_window_get_work_area_for_monitor (window, current, &work_area);

  cascade_x = MAX (0, work_area.x);
  cascade_y = MAX (0, work_area.y);

  /* Find first cascade position that's not used. */

  meta_window_get_frame_rect (window, &frame_rect);
  window_width = frame_rect.width;
  window_height = frame_rect.height;

  cascade_stage = 0;
  tmp = sorted;
  while (tmp != NULL)
    {
      MetaWindow *w;
      MetaRectangle w_frame_rect;
      int wx, wy;

      w = tmp->data;

      /* we want frame position, not window position */
      meta_window_get_frame_rect (w, &w_frame_rect);
      wx = w_frame_rect.x;
      wy = w_frame_rect.y;

      if (ABS (wx - cascade_x) < x_threshold &&
          ABS (wy - cascade_y) < y_threshold)
        {
          meta_window_get_titlebar_rect (w, &titlebar_rect);

          /* Cascade the window evenly by the titlebar height; this isn't a typo. */
          cascade_x = wx + titlebar_rect.height;
          cascade_y = wy + titlebar_rect.height;

          /* If we go off the screen, start over with a new cascade */
	  if (((cascade_x + window_width) >
               (work_area.x + work_area.width)) ||
              ((cascade_y + window_height) >
	       (work_area.y + work_area.height)))
	    {
	      cascade_x = MAX (0, work_area.x);
	      cascade_y = MAX (0, work_area.y);

#define CASCADE_INTERVAL 50 /* space between top-left corners of cascades */
              cascade_stage += 1;
	      cascade_x += CASCADE_INTERVAL * cascade_stage;

	      /* start over with a new cascade translated to the right, unless
               * we are out of space
               */
              if ((cascade_x + window_width) <
                  (work_area.x + work_area.width))
                {
                  tmp = sorted;
                  continue;
                }
              else
                {
                  /* All out of space, this cascade_x won't work */
                  cascade_x = MAX (0, work_area.x);
                  break;
                }
	    }
        }
      else
        {
          /* Keep searching for a further-down-the-diagonal window. */
        }

      tmp = tmp->next;
    }

  /* cascade_x and cascade_y will match the last window in the list
   * that was "in the way" (in the approximate cascade diagonal)
   */

  g_list_free (sorted);

  *new_x = cascade_x;
  *new_y = cascade_y;
}
예제 #5
0
파일: place.c 프로젝트: zZzEnergozZz/muffin
static void
find_next_cascade (MetaWindow *window,
                   MetaFrameBorders *borders,
                   /* visible windows on relevant workspaces */
                   GList      *windows,
                   int         x,
                   int         y,
                   int        *new_x,
                   int        *new_y)
{
  GList *tmp;
  GList *sorted;
  int cascade_x, cascade_y;
  int x_threshold, y_threshold;
  int window_width, window_height;
  int cascade_stage;
  MetaRectangle work_area;
  const MetaMonitorInfo* current;
  
  sorted = g_list_copy (windows);
  sorted = g_list_sort (sorted, northwestcmp);

  /* This is a "fuzzy" cascade algorithm. 
   * For each window in the list, we find where we'd cascade a
   * new window after it. If a window is already nearly at that
   * position, we move on.
   */
  
  /* arbitrary-ish threshold, honors user attempts to
   * manually cascade.
   */
#define CASCADE_FUZZ 15
  if (borders)
    {
      x_threshold = MAX (borders->visible.left, CASCADE_FUZZ);
      y_threshold = MAX (borders->visible.top, CASCADE_FUZZ);
    }
  else
    {
      x_threshold = CASCADE_FUZZ;
      y_threshold = CASCADE_FUZZ;
    }
  
  /* Find furthest-SE origin of all workspaces.
   * cascade_x, cascade_y are the target position
   * of NW corner of window frame.
   */

  current = meta_screen_get_current_monitor (window->screen);
  meta_window_get_work_area_for_monitor (window, current->number, &work_area);

  cascade_x = MAX (0, work_area.x);
  cascade_y = MAX (0, work_area.y);
  
  /* Find first cascade position that's not used. */
  
  window_width = window->frame ? window->frame->rect.width : window->rect.width;
  window_height = window->frame ? window->frame->rect.height : window->rect.height;
  
  cascade_stage = 0;
  tmp = sorted;
  while (tmp != NULL)
    {
      MetaWindow *w;
      int wx, wy;
      
      w = tmp->data;

      /* we want frame position, not window position */
      if (w->frame)
        {
          wx = w->frame->rect.x;
          wy = w->frame->rect.y;
        }
      else
        {
          wx = w->rect.x;
          wy = w->rect.y;
        }
      
      if (ABS (wx - cascade_x) < x_threshold &&
          ABS (wy - cascade_y) < y_threshold)
        {
          /* This window is "in the way", move to next cascade
           * point. The new window frame should go at the origin
           * of the client window we're stacking above.
           */
          meta_window_get_position (w, &wx, &wy);
          cascade_x = wx;
          cascade_y = wy;
          
          /* If we go off the screen, start over with a new cascade */
	  if (((cascade_x + window_width) >
               (work_area.x + work_area.width)) ||
              ((cascade_y + window_height) >
	       (work_area.y + work_area.height)))
	    {
	      cascade_x = MAX (0, work_area.x);
	      cascade_y = MAX (0, work_area.y);
              
#define CASCADE_INTERVAL 50 /* space between top-left corners of cascades */
              cascade_stage += 1;
	      cascade_x += CASCADE_INTERVAL * cascade_stage;
              
	      /* start over with a new cascade translated to the right, unless
               * we are out of space
               */
              if ((cascade_x + window_width) <
                  (work_area.x + work_area.width))
                {
                  tmp = sorted;
                  continue;
                }
              else
                {
                  /* All out of space, this cascade_x won't work */
                  cascade_x = MAX (0, work_area.x);
                  break;
                }
	    }
        }
      else
        {
          /* Keep searching for a further-down-the-diagonal window. */
        }
        
      tmp = tmp->next;
    }

  /* cascade_x and cascade_y will match the last window in the list
   * that was "in the way" (in the approximate cascade diagonal)
   */
  
  g_list_free (sorted);

  /* Convert coords to position of window, not position of frame. */
  if (borders == NULL)
    {
      *new_x = cascade_x;
      *new_y = cascade_y;
    }
  else
    {
      *new_x = cascade_x + borders->visible.left;
      *new_y = cascade_y + borders->visible.top;
    }
}
예제 #6
0
파일: place.c 프로젝트: zZzEnergozZz/muffin
LOCAL_SYMBOL void
meta_window_place (MetaWindow        *window,
                   MetaFrameBorders  *borders,
                   int                x,
                   int                y,
                   int               *new_x,
                   int               *new_y)
{
  GList *windows;
  const MetaMonitorInfo *xi;

  /* frame member variables should NEVER be used in here, only
   * MetaFrameBorders. But remember borders == 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;
  
  if (meta_window_is_override_redirect(window)) {
    goto done_no_constraints;
  }
  
  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:
    /* 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:
      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:
	/* 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:
          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, borders, &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 (borders)
            y += borders->visible.top;

          meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n",
                      window->desc);
          
          avoid_being_obscured_as_second_modal_dialog (window, borders, &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 monitor */
      int w, h;

      /* Warning, this function is a round trip! */
      xi = meta_screen_get_current_monitor (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 monitor %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, META_LIST_DEFAULT);

    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_monitor (window->screen);
  
  /* "Origin" placement algorithm */
  x = xi->rect.x;
  y = xi->rect.y;

  if (find_first_fit (window, borders, 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_monitor (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 (x == xi->rect.x && y == xi->rect.y)  
    find_next_cascade (window, borders, 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 (!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, borders, 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, borders, focus_window, x, y, &x, &y);
    }
  
 done:
  g_list_free (windows);
  
 done_no_constraints:

  *new_x = x;
  *new_y = y;
}