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