Example #1
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,
                /* visible windows on relevant workspaces */
                GList      *windows,
		int         monitor,
                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);

  meta_window_get_frame_rect (window, &rect);

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

  meta_window_get_work_area_for_monitor (window, monitor, &work_area);

  center_tile_rect_in_area (&rect, &work_area);

  if (meta_rectangle_contains_rect (&work_area, &rect) &&
      !rectangle_overlaps_some_window (&rect, windows))
    {
      *new_x = rect.x;
      *new_y = rect.y;

      retval = TRUE;

      goto out;
    }

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

      meta_window_get_frame_rect (w, &frame_rect);

      rect.x = frame_rect.x;
      rect.y = frame_rect.y + frame_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;

          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 frame_rect;

      meta_window_get_frame_rect (w, &frame_rect);

      rect.x = frame_rect.x + frame_rect.width;
      rect.y = frame_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;

          retval = TRUE;

          goto out;
        }

      tmp = tmp->next;
    }

 out:
  g_list_free (below_sorted);
  g_list_free (right_sorted);
  return retval;
}
Example #2
0
static void
test_merge_regions ()
{
  /* logarithmically distributed random number of struts (range?)
   * logarithmically distributed random size of struts (up to screen size???)
   * uniformly distributed location of center of struts (within screen)
   * merge all regions that are possible
   * print stats on problem setup
   *   number of (non-completely-occluded?) struts 
   *   percentage of screen covered
   *   length of resulting non-minimal spanning set
   *   length of resulting minimal spanning set
   * print stats on merged regions:
   *   number boxes merged
   *   number of those merges that were of the form A contains B
   *   number of those merges that were of the form A partially contains B
   *   number of those merges that were of the form A is adjacent to B
   */

  GList* region;
  GList* compare;
  int num_contains, num_merged, num_part_contains, num_adjacent;

  num_contains = num_merged = num_part_contains = num_adjacent = 0;
  compare = region = get_screen_region (2);
  g_assert (region);

  printf ("Merging stats:\n");
  printf ("  Length of initial list: %d\n", g_list_length (region));
#ifdef PRINT_DEBUG
  char rect1[RECT_LENGTH], rect2[RECT_LENGTH];
  char region_list[(RECT_LENGTH + 2) * g_list_length (region)];
  meta_rectangle_region_to_string (region, ", ", region_list);
  printf ("  Initial rectangles: %s\n", region_list);
#endif

  while (compare && compare->next)
    {
      MetaRectangle *a = compare->data;
      GList *other = compare->next;

      g_assert (a->width > 0 && a->height > 0);

      while (other)
        {
          MetaRectangle *b = other->data;
          GList *delete_me = NULL;

          g_assert (b->width > 0 && b->height > 0);

#ifdef PRINT_DEBUG
          printf ("    -- Comparing %s to %s --\n",
                  meta_rectangle_to_string (a, rect1),
                  meta_rectangle_to_string (b, rect2));
#endif

          /* If a contains b, just remove b */
          if (meta_rectangle_contains_rect (a, b))
            {
              delete_me = other;
              num_contains++;
              num_merged++;
            }
          /* If b contains a, just remove a */
          else if (meta_rectangle_contains_rect (a, b))
            {
              delete_me = compare;
              num_contains++;
              num_merged++;
            }
          /* If a and b might be mergeable horizontally */
          else if (a->y == b->y && a->height == b->height)
            {
              /* If a and b overlap */
              if (meta_rectangle_overlap (a, b))
                {
                  int new_x = MIN (a->x, b->x);
                  a->width = MAX (a->x + a->width, b->x + b->width) - new_x;
                  a->x = new_x;
                  delete_me = other;
                  num_part_contains++;
                  num_merged++;
                }
              /* If a and b are adjacent */
              else if (a->x + a->width == b->x || a->x == b->x + b->width)
                {
                  int new_x = MIN (a->x, b->x);
                  a->width = MAX (a->x + a->width, b->x + b->width) - new_x;
                  a->x = new_x;
                  delete_me = other;
                  num_adjacent++;
                  num_merged++;
                }
            }
          /* If a and b might be mergeable vertically */
          else if (a->x == b->x && a->width == b->width)
            {
              /* If a and b overlap */
              if (meta_rectangle_overlap (a, b))
                {
                  int new_y = MIN (a->y, b->y);
                  a->height = MAX (a->y + a->height, b->y + b->height) - new_y;
                  a->y = new_y;
                  delete_me = other;
                  num_part_contains++;
                  num_merged++;
                }
              /* If a and b are adjacent */
              else if (a->y + a->height == b->y || a->y == b->y + b->height)
                {
                  int new_y = MIN (a->y, b->y);
                  a->height = MAX (a->y + a->height, b->y + b->height) - new_y;
                  a->y = new_y;
                  delete_me = other;
                  num_adjacent++;
                  num_merged++;
                }
            }

          other = other->next;

          /* Delete any rectangle in the list that is no longer wanted */
          if (delete_me != NULL)
            {
#ifdef PRINT_DEBUG
              MetaRectangle *bla = delete_me->data;
              printf ("    Deleting rect %s\n",
                      meta_rectangle_to_string (bla, rect1));
#endif

              /* Deleting the rect we're compare others to is a little tricker */
              if (compare == delete_me)
                {
                  compare = compare->next;
                  other = compare->next;
                  a = compare->data;
                }

              /* Okay, we can free it now */
              g_free (delete_me->data);
              region = g_list_delete_link (region, delete_me);
            }

#ifdef PRINT_DEBUG
          char region_list[(RECT_LENGTH + 2) * g_list_length (region)];
          meta_rectangle_region_to_string (region, ", ", region_list);
          printf ("      After comparison, new list is: %s\n", region_list);
#endif
        }

      compare = compare->next;
    }

  printf ("  Num rectangles contained in others          : %d\n", 
          num_contains);
  printf ("  Num rectangles partially contained in others: %d\n", 
          num_part_contains);
  printf ("  Num rectangles adjacent to others           : %d\n", 
          num_adjacent);
  printf ("  Num rectangles merged with others           : %d\n",
          num_merged);
#ifdef PRINT_DEBUG
  char region_list2[(RECT_LENGTH + 2) * g_list_length (region)];
  meta_rectangle_region_to_string (region, ", ", region_list2);
  printf ("  Final rectangles: %s\n", region_list2);
#endif

  meta_rectangle_free_spanning_set (region);
  region = NULL;

  printf ("%s passed.\n", G_STRFUNC);
}