diff options
author | Elijah Newren <newren@gmail.com> | 2005-10-05 01:09:13 +0000 |
---|---|---|
committer | Elijah Newren <newren@src.gnome.org> | 2005-10-05 01:09:13 +0000 |
commit | 0f40c492d4c36ff7818df51fc8cb534a6c3c224d (patch) | |
tree | b80f1981ea49da9d2c1286dc21322d77b6de7135 | |
parent | 330c9e4403af702fa9dee8c64d1658fa79e2a5c0 (diff) | |
download | metacity-0f40c492d4c36ff7818df51fc8cb534a6c3c224d.tar.gz |
Finally got the onscreen constraint written, minus the need for setting
2005-10-04 Elijah Newren <newren@gmail.com>
Finally got the onscreen constraint written, minus the need for
setting the require_fully_onscreen flag.
* constraints-ideas.txt: minor clarification; mark one section as
done
* src/boxes.[ch]
(meta_rectangle_get_minimal_spanning_set_for_region): clarify what
the region is in the comments,
(meta_rectangle_could_be_contained_in_region,
meta_rectangle_contained_in_region,
meta_rectangle_clamp_to_fit_into_region,
meta_rectangle_clip_to_region, meta_rectangle_shove_into_region):
new functions
* src/constraints.c (do_screen_and_xinerama_relative_constraints):
re-write in terms of
meta_rectangle_could_be_contained_in_region(),
meta_rectangle_contained_in_region(),
meta_rectangle_clamp_to_fit_into_region(),
meta_rectangle_clip_to_region(), and
meta_rectangle_shove_into_region()
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | constraints-ideas.txt | 4 | ||||
-rw-r--r-- | src/boxes.c | 278 | ||||
-rw-r--r-- | src/boxes.h | 18 | ||||
-rw-r--r-- | src/constraints.c | 104 |
5 files changed, 368 insertions, 61 deletions
@@ -1,3 +1,28 @@ +2005-10-04 Elijah Newren <newren@gmail.com> + + Finally got the onscreen constraint written, minus the need for + setting the require_fully_onscreen flag. + + * constraints-ideas.txt: minor clarification; mark one section as + done + + * src/boxes.[ch] + (meta_rectangle_get_minimal_spanning_set_for_region): clarify what + the region is in the comments, + (meta_rectangle_could_be_contained_in_region, + meta_rectangle_contained_in_region, + meta_rectangle_clamp_to_fit_into_region, + meta_rectangle_clip_to_region, meta_rectangle_shove_into_region): + new functions + + * src/constraints.c (do_screen_and_xinerama_relative_constraints): + re-write in terms of + meta_rectangle_could_be_contained_in_region(), + meta_rectangle_contained_in_region(), + meta_rectangle_clamp_to_fit_into_region(), + meta_rectangle_clip_to_region(), and + meta_rectangle_shove_into_region() + 2005-10-01 Elijah Newren <newren@gmail.com> * constraints-ideas.txt: Small updates to some bug numbers diff --git a/constraints-ideas.txt b/constraints-ideas.txt index f285ffda..5608f8d8 100644 --- a/constraints-ideas.txt +++ b/constraints-ideas.txt @@ -35,8 +35,8 @@ Short-term TODO list/reminders: - Uni-directional: All sides but the given direction are fixed - Bi-directional: The two other sides are fixed - App resize -- acts like move as far as side fixing - - Move & resize -- no sides are fixed - - Regardless of clipping or shoving; there needs to be a good way to + - Move & resize -- unsure, perhaps no sides are fixed? + X Regardless of clipping or shoving; there needs to be a good way to pick the best of the (maximally) covering rects into which to clip or shove. - User resize (clip-into): diff --git a/src/boxes.c b/src/boxes.c index 24820158..12da9eaa 100644 --- a/src/boxes.c +++ b/src/boxes.c @@ -157,9 +157,9 @@ compare_rect_areas (gconstpointer a, gconstpointer b) /* This function is trying to find a "minimal spanning set (of rectangles)" * for a given region. * - * The region is given by basic_rect with all the rectangles in the - * all_struts list removed, and then expanded by the given number of pixels - * in each direction. + * The region is given by taking basic_rect, then removing the areas + * covered by all the rectangles in the all_struts list, and then expanding + * the resulting region by the given number of pixels in each direction. * * A "minimal spanning set (of rectangles)" is the best name I could come * up with for the concept I had in mind. Basically, for a given region, I @@ -277,6 +277,278 @@ meta_rectangle_get_minimal_spanning_set_for_region (MetaRectangle *basic_rect, return ret; } +gboolean +meta_rectangle_could_be_contained_in_region (const GList *spanning_rects, + const MetaRectangle *rect) +{ + const GList *temp; + gboolean could_be_contained; + + contained = TRUE; + while (could_be_contained && temp != NULL) + { + could_be_contained = + could_be_contained && meta_rectangle_could_fit_rect (temp->data, rect); + temp = temp->next; + } + + return could_be_contained; +} + +gboolean +meta_rectangle_contained_in_region (const GList *spanning_rects, + const MetaRectangle *rect) +{ + const GList *temp; + gboolean contained; + + contained = TRUE; + while (contained && temp != NULL) + { + contained = contained && meta_rectangle_contains_rect (temp->data, rect); + temp = temp->next; + } + + return contained; +} + +void +meta_rectangle_clamp_to_fit_into_region (const GList *spanning_rects, + FixedDirections fixed_directions, + MetaRectangle *rect, + const MetaRectangle *min_size) +{ + GList *temp; + const MetaRectangle *best_rect = NULL; + int best_overlap = 0; + + /* First, find best rectangle from spanning_rects to which we can clamp + * rect to fit into. + */ + temp = spanning_rects; + while (temp) + { + int factor = 1; + MetaRectangle *compare = temp->data; + int maximal_overlap_amount_for_compare; + + /* If x is fixed and the entire width of rect doesn't fit in compare, set + * factor to 0. + */ + if ((fixed_directions & FIXED_DIRECTION_X) && + (compare->x > rect->x || + compare_rect->x + compare_rect->width < rect->x + rect->width)) + factor = 0; + + /* If y is fixed and the entire height of rect doesn't fit in compare, set + * factor to 0. + */ + if ((fixed_directions & FIXED_DIRECTION_Y) && + (compare->y > rect->y || + compare_rect->y + compare_rect->height < rect->y + rect->height)) + factor = 0; + + /* If compare can't hold the min_size window, set factor to 0 */ + if (compare_rect->width < min_size->width || + compare_rect->height < min_size->height) + factor = 0; + + /* Determine maximal overlap amount */ + maximal_overlap_amount_for_compare = + MIN (rect->width, compare_rect->width) * + MIN (rect->height, compare_rect->height); + maximal_overlap_amount_for_compare *= factor; + + /* See if this is the best rect so far */ + if (maximal_overlap_amount_for_compare > best_overlap) + { + best_rect = compare_rect; + best_overlap = maximal_overlap_amount_for_compare; + } + + temp = temp->next; + } + + /* Clamp rect appropriately */ + if (best_rect == NULL) + meta_warning ("No rect whose size to clamp to found!\n"); + else + { + rect->width = MIN (rect->width, best_rect->width); + rect->height = MIN (rect->height, best_rect->height); + } +} + +gboolean +meta_rectangle_clip_to_region (const GList *spanning_rects, + FixedDirections fixed_directions, + MetaRectangle *rect) +{ + GList *temp; + const MetaRectangle *best_rect = NULL; + int best_overlap = 0; + + /* First, find best rectangle from spanning_rects to which we will clip + * rect into. + */ + temp = spanning_rects; + while (temp) + { + int factor = 1; + MetaRectangle *compare = temp->data; + MetaRectangle overlap; + int maximal_overlap_amount_for_compare; + + /* If x is fixed and the entire width of rect doesn't fit in compare, set + * factor to 0. + */ + if ((fixed_directions & FIXED_DIRECTION_X) && + (compare->x > rect->x || + compare_rect->x + compare_rect->width < rect->x + rect->width)) + factor = 0; + + /* If y is fixed and the entire height of rect doesn't fit in compare, set + * factor to 0. + */ + if ((fixed_directions & FIXED_DIRECTION_Y) && + (compare->y > rect->y || + compare_rect->y + compare_rect->height < rect->y + rect->height)) + factor = 0; + + /* Determine maximal overlap amount */ + meta_rectangle_intersect (rect, compare_rect, &overlap); + maximal_overlap_amount_for_compare = meta_rectangle_area (&overlap); + maximal_overlap_amount_for_compare *= factor; + + /* See if this is the best rect so far */ + if (maximal_overlap_amount_for_compare > best_overlap) + { + best_rect = compare_rect; + best_overlap = maximal_overlap_amount_for_compare; + } + + temp = temp->next; + } + + /* Clip rect appropriately */ + if (best_rect == NULL) + meta_warning ("No rect to shove into found!\n"); + else + { + /* Extra precaution with checking fixed direction shouldn't be needed + * due to logic above, but it shouldn't hurt either. + */ + if (!(fixed_directions & FIXED_DIRECTION_X)) + { + /* Clip the left, if needed */ + rect->x = MAX (rect->x, best_rect->x); + + /* Clip the right, if needed */ + rect->width = MIN (rect->width, + (best_rect->x + best_rect->width) - rect->x); + } + + /* Extra precaution with checking fixed direction shouldn't be needed + * due to logic above, but it shouldn't hurt either. + */ + if (!(fixed_directions & FIXED_DIRECTION_Y)) + { + /* Clip the top, if needed */ + rect->y = MAX (rect->y, best_rect->y); + + /* Clip the bottom, if needed */ + rect->height = MIN (rect->height, + (best_rect->y + best_rect->height) - rect->y); + } + } +} + +gboolean +meta_rectangle_shove_into_region (const GList *spanning_rects, + FixedDirections fixed_directions, + MetaRectangle *rect) +{ + GList *temp; + const MetaRectangle *best_rect = NULL; + int best_overlap = 0; + + /* First, find best rectangle from spanning_rects to which we will shove + * rect into. + */ + temp = spanning_rects; + while (temp) + { + int factor = 1; + MetaRectangle *compare = temp->data; + int maximal_overlap_amount_for_compare; + + /* If x is fixed and the entire width of rect doesn't fit in compare, set + * factor to 0. + */ + if ((fixed_directions & FIXED_DIRECTION_X) && + (compare->x > rect->x || + compare_rect->x + compare_rect->width < rect->x + rect->width)) + factor = 0; + + /* If y is fixed and the entire height of rect doesn't fit in compare, set + * factor to 0. + */ + if ((fixed_directions & FIXED_DIRECTION_Y) && + (compare->y > rect->y || + compare_rect->y + compare_rect->height < rect->y + rect->height)) + factor = 0; + + /* Determine maximal overlap amount */ + maximal_overlap_amount_for_compare = + MIN (rect->width, compare_rect->width) * + MIN (rect->height, compare_rect->height); + maximal_overlap_amount_for_compare *= factor; + + /* See if this is the best rect so far */ + if (maximal_overlap_amount_for_compare > best_overlap) + { + best_rect = compare_rect; + best_overlap = maximal_overlap_amount_for_compare; + } + + temp = temp->next; + } + + /* Shove rect appropriately */ + if (best_rect == NULL) + meta_warning ("No rect to shove into found!\n"); + else + { + /* Extra precaution with checking fixed direction shouldn't be needed + * due to logic above, but it shouldn't hurt either. + */ + if (!(fixed_directions & FIXED_DIRECTION_X)) + { + /* Shove to the right, if needed */ + if (best_rect->x > rect->x) + rect->x = best_rect->x; + + /* Shove to the left, if needed */ + if (best_rect->x + best_rect->width < rect->x + rect->width) + rect->x = (best_rect->x + best_rect->width) - rect->width; + } + + /* Extra precaution with checking fixed direction shouldn't be needed + * due to logic above, but it shouldn't hurt either. + */ + if (!(fixed_directions & FIXED_DIRECTION_Y)) + { + /* Shove down, if needed */ + if (best_rect->y > rect->y) + rect->y = best_rect->y; + + /* Shove up, if needed */ + if (best_rect->y + best_rect->height < rect->y + rect->height) + rect->y = (best_rect->y + best_rect->height) - rect->height; + } + } +} + #if 0 #if 0 gboolean diff --git a/src/boxes.h b/src/boxes.h index f5773c33..986eb6b6 100644 --- a/src/boxes.h +++ b/src/boxes.h @@ -64,6 +64,24 @@ GList* meta_rectangle_get_minimal_spanning_set_for_region ( const int right_expand, const int top_expand, const int bottom_expand); +gboolean meta_rectangle_could_be_contained_in_region ( + const GList *spanning_rects, + const MetaRectangle *rect); +gboolean meta_rectangle_contained_in_region ( + const GList *spanning_rects, + const MetaRectangle *rect); +void meta_rectangle_clamp_to_fit_into_region ( + const GList *spanning_rects, + FixedDirections fixed_directions, + MetaRectangle *rect, + const MetaRectangle *min_size); +gboolean meta_rectangle_clip_to_region (const GList *spanning_rects, + FixedDirections fixed_directions, + MetaRectangle *rect); +gboolean meta_rectangle_shove_into_region( + const GList *spanning_rects, + FixedDirections fixed_directions, + MetaRectangle *rect); #if 0 May not be needed--depends on if constrain_clamp_size remains... diff --git a/src/constraints.c b/src/constraints.c index b2e9137c..2eb947d9 100644 --- a/src/constraints.c +++ b/src/constraints.c @@ -489,8 +489,8 @@ setup_constraint_info (ConstraintInfo *info, * * Note that fixed directions might (though I haven't thought it * completely through) give an impossible to fulfill constraint; if they - * do, then they will get temporarily thrown out with the constraint - * tried again. + * do, then we could temporarily throw them out and retry the constraint + * again. * * Now, some nasty details: * @@ -1048,77 +1048,68 @@ constrain_aspect_ratio (MetaWindow *window, return TRUE; } -#if 0 static gboolean -do_screen_and_xinerama_relative_constraints (MetaWindow *window, - ConstraintInfo *info, - gboolean check_only) +do_screen_and_xinerama_relative_constraints ( + MetaWindow *window, + GList *region_spanning_rectangles, + ConstraintInfo *info, + gboolean check_only) { - FIXME: I'm assuming totally onscreen, but using it for each of - totally_onscreen, partially_onscreen, and on_single_xinerama... - /* */ - - MetaRectangle outermost_positions; - get_outermost_onscreen_positions (window, info->current, &outermost_positions); - /* Determine whether constraint applies; exit if it doesn't */ - MetaRectangle min_size, max_size; - MetaRectangle work_area = info->work_area_xinerama; - get_size_limits (window, info->fgeom, &min_size, &max_size); - gboolean too_big = - !meta_rectangle_could_fit_rect (work_area, min_size) || - !meta_rectangle_could_fit_rect (outermost_positions, min_size); - if (too_big) + MetaRectangle how_far_it_can_be_smushed, min_size, max_size; + how_far_it_can_be_smushed = info->current; + get_size_limits (window, info->fgeom, TRUE, &min_size, &max_size); + if (info->action_type != ACTION_MOVE) + { + if (!(info->fixed_directions & FIXED_DIRECTION_X)) + how_far_it_can_be_smushed.width = min_size.width; + + if (!(info->fixed_directions & FIXED_DIRECTION_Y)) + how_far_it_can_be_smushed.height = min_size.height; + } + if (!meta_rectangle_could_be_contained_in_region (region_spanning_rectangles, + how_far_it_can_be_smushed)) return TRUE; /* Determine whether constraint is already satisfied; exit if it is */ - gboolean constraint_already_satisfied = - meta_rectangle_contains_rect (work_area, info->current) || - meta_rectangle_contains_rect (outermost_positions, info->current); - if (check_only || constraint_already_satisfied) - return constraint_already_satisfied; + constraint_satisfied = + meta_rectangle_contained_in_region (region_spanning_rectangles, + info->current); + if (constraint_satisfied || check_only) + return constraint_satisfied; + + /* Enforce constraint */ - /* Enforce constraints */ - /* First, make sure it can fit... */ - if (!meta_rectangle_could_fit_rect (work_area, info->current) && - !meta_rectangle_could_fit_rect (outermost_positions, info->current)) + /* Clamp rectangle size for user move+resize, app move+resize, and + * app resize + */ + if (info->action_type == ACTION_MOVE_AND_RESIZE || + (info->is_user_action && info->action_type == ACTION_RESIZE)) { - /* We have to force it to fit into either work_area or - * outermost_positions, and we'd rather force it into the bigger one - * so as to shrink the window as little as possible. - */ - if (meta_rectangle_area (work_area) > - meta_rectangle_area (outermost_positions)) - { - info->current.width = MIN (info->current.width, work_area.width); - info->current.height = MIN (info->current.height, work_area.height); - } - else - { - int max_width = outermost_positions.width; - int max_height = outermost_positions.height; - info->current.width = MIN (info->current.width, max_width); - info->current.height = MIN (info->current.height, max_height); - } + meta_rectangle_clamp_to_fit_into_region (region_spanning_rectangles, + info->fixed_directions, + &info->current, + min_size); } - /* Now, either shove the rectangle onto the screen or clip it to the - * screen, as appropriate. - */ + if (info->is_user_action && info->action_type == ACTION_RESIZE) + /* For user resize, clip to the relevant region */ + meta_rectangle_clip_to_region (region_spanning_rectangles, + info->fixed_directions, + &info->current); + else + /* For everything else, shove the rectangle into the relevant region */ + meta_rectangle_shove_into_region (region_spanning_rectangles, + info->fixed_directions, + &info->current); - Try doing relative to both work_area and outermost_positions, then ???? determinedoing both; then determine which causes - MetaRectangle *relevant_rect; - if (meta_rectangle_contains_rect (work_area, info->orig)) - relevant_rect = - return TRUE; } -#endif - static GSList* get_all_workspace_struts (const MetaWorkspace *workspace) { + GList *all_struts; all_struts = g_slist_concat (g_slist_copy (workspace->left_struts), NULL); all_struts = g_slist_concat (g_slist_copy (workspace->right_struts), @@ -1168,6 +1159,7 @@ constrain_fully_onscreen (MetaWindow *window, info, check_only); + /* Free up the data we allocated */ g_slist_free (all_struts); g_list_foreach (fully_onscreen_region, g_free, NULL); g_list_free (fully_onscreen_region); |