Пример #1
0
static void
test_intersect ()
{
  MetaRectangle a = {100, 200,  50,  40};
  MetaRectangle b = {  0,  50, 110, 152};
  MetaRectangle c = {  0,   0,  10,  10};
  MetaRectangle d = {100, 100,  50,  50};
  MetaRectangle b_intersect_d = {100, 100, 10, 50};
  MetaRectangle temp;
  MetaRectangle temp2;

  meta_rectangle_intersect (&a, &b, &temp);
  temp2 = meta_rect (100, 200, 10, 2);
  g_assert (meta_rectangle_equal (&temp, &temp2));
  g_assert (meta_rectangle_area (&temp) == 20);

  meta_rectangle_intersect (&a, &c, &temp);
  g_assert (meta_rectangle_area (&temp) == 0);

  meta_rectangle_intersect (&a, &d, &temp);
  g_assert (meta_rectangle_area (&temp) == 0);

  meta_rectangle_intersect (&b, &d, &b);
  g_assert (meta_rectangle_equal (&b, &b_intersect_d));

  printf ("%s passed.\n", G_STRFUNC);
}
Пример #2
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;
}
Пример #3
0
static gboolean
window_overlaps_focus_window (MetaWindow *window)
{
  MetaWindow *focus_window;
  MetaRectangle window_frame, focus_frame, overlap;

  focus_window = window->display->focus_window;
  if (focus_window == NULL)
    return FALSE;

  meta_window_get_frame_rect (window, &window_frame);
  meta_window_get_frame_rect (focus_window, &focus_frame);

  return meta_rectangle_intersect (&window_frame,
                                   &focus_frame,
                                   &overlap);
}
Пример #4
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;
}
Пример #5
0
static void
avoid_being_obscured_as_second_modal_dialog (MetaWindow *window,
                                             MetaFrameGeometry *fgeom,
                                             int        *x,
                                             int        *y)
{
  /* We can't center this dialog if it was denied focus and it
   * overlaps with the focus window and this dialog is modal and this
   * dialog is in the same app as the focus window (*phew*...please
   * don't make me say that ten times fast). See bug 307875 comment 11
   * and 12 for details, but basically it means this is probably a
   * second modal dialog for some app while the focus window is the
   * first modal dialog.  We should probably make them simultaneously
   * visible in general, but it becomes mandatory to do so due to
   * buggy apps (e.g. those using gtk+ *sigh*) because in those cases
   * this second modal dialog also happens to be modal to the first
   * dialog in addition to the main window, while it has only let us
   * know about the modal-to-the-main-window part.
   */

  MetaWindow *focus_window;
  MetaRectangle overlap;

  focus_window = window->display->focus_window;

  if (window->denied_focus_and_not_transient &&
      window->wm_state_modal && /* FIXME: Maybe do this for all transients? */
      meta_window_same_application (window, focus_window) &&
      meta_rectangle_intersect (&window->rect,
                                &focus_window->rect,
                                &overlap))
    {
      find_most_freespace (window, fgeom, focus_window, *x, *y, x, y);
      meta_topic (META_DEBUG_PLACEMENT,
                  "Dialog window %s was denied focus but may be modal "
                  "to the focus window; had to move it to avoid the "
                  "focus window\n",
                  window->desc);
    }
}
Пример #6
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;
}