summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElijah Newren <newren@gmail.com>2005-10-05 01:09:13 +0000
committerElijah Newren <newren@src.gnome.org>2005-10-05 01:09:13 +0000
commit0f40c492d4c36ff7818df51fc8cb534a6c3c224d (patch)
treeb80f1981ea49da9d2c1286dc21322d77b6de7135
parent330c9e4403af702fa9dee8c64d1658fa79e2a5c0 (diff)
downloadmetacity-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--ChangeLog25
-rw-r--r--constraints-ideas.txt4
-rw-r--r--src/boxes.c278
-rw-r--r--src/boxes.h18
-rw-r--r--src/constraints.c104
5 files changed, 368 insertions, 61 deletions
diff --git a/ChangeLog b/ChangeLog
index b0a41aab..befc15e9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);