summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElijah Newren <newren@gmail.com>2005-09-19 06:52:56 +0000
committerElijah Newren <newren@src.gnome.org>2005-09-19 06:52:56 +0000
commit6f1ab510df997dbb6a1e691ba3e721d6e545f29f (patch)
treeacb9793b9e9db90803eb5bb56f08cc327717d855
parentfdcea4c6927712d54e01f342922eb323d5363457 (diff)
downloadmetacity-6f1ab510df997dbb6a1e691ba3e721d6e545f29f.tar.gz
Add some basic ideas/problems that I recently thought of so I don't forget
2005-09-19 Elijah Newren <newren@gmail.com> * constraints-ideas.txt: Add some basic ideas/problems that I recently thought of so I don't forget them, add the bug(s) Davyd wanted fixed so I don't forget to cover it too. * src/constraints.c: (setup_constraint_info): It's info->resize_gravity, not info->gravity (resize_with_gravity): declare it earlier, make the order of width and height consistent with all the meta_window*resize* functions in window.c (constrain_maximization, constrain_fullscreen): try to exit before doing any computations if possible to speed up the code in general, fix a cut-and-paste bug by s/maximized/fullscreen/ (constrain_size_increments, constrain_size_limits, constrain_aspect_ratio): implement these, though constraints-ideas.txt discusses some problems that arose that need to be addressed
-rw-r--r--ChangeLog28
-rw-r--r--constraints-ideas.txt34
-rw-r--r--src/constraints.c252
3 files changed, 307 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 3c73ada9..ed809824 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,30 @@
-2005-09-18 Elijah Newren <Newren@gmail.com>
+2005-09-19 Elijah Newren <newren@gmail.com>
+
+ * constraints-ideas.txt:
+
+ Add some basic ideas/problems that I recently thought of so I
+ don't forget them, add the bug(s) Davyd wanted fixed so I don't
+ forget to cover it too.
+
+ * src/constraints.c:
+
+ (setup_constraint_info): It's info->resize_gravity, not
+ info->gravity
+
+ (resize_with_gravity): declare it earlier, make the order of width
+ and height consistent with all the meta_window*resize* functions
+ in window.c
+
+ (constrain_maximization, constrain_fullscreen): try to exit before
+ doing any computations if possible to speed up the code in
+ general, fix a cut-and-paste bug by s/maximized/fullscreen/
+
+ (constrain_size_increments, constrain_size_limits,
+ constrain_aspect_ratio): implement these, though
+ constraints-ideas.txt discusses some problems that arose that need
+ to be addressed
+
+2005-09-18 Elijah Newren <newren@gmail.com>
* src/boxes.[hc]:
diff --git a/constraints-ideas.txt b/constraints-ideas.txt
index 226d5a28..794b1232 100644
--- a/constraints-ideas.txt
+++ b/constraints-ideas.txt
@@ -1,3 +1,36 @@
+Short-term TODO list/reminders:
+
+ - My aspect ratio resizing may still not work because perhaps
+ closest-in-area should trump whenever one of the two is very far
+ away in area (Think about grabbing the SE corner with the mouse,
+ resizing way to the right, not letting go of the left mouse
+ button, letting constraints catch up, then moving the mouse up
+ slightly to shrink the window: That results in a big height
+ reduction (since mouse position and window didn't align well), and
+ a corresponding massive width reduction since the shrinking window
+ stuff rules out the bigger of the two aspects). Maybe
+ closest-in-area should ust always trump--except for some extra
+ slop for keyboard resizing?.
+
+ - My attempts to do all contraints in terms of the outer window are
+ mislead--most are actually relative to the inner window.
+ Comparisons:
+ constraint window
+ size_increments inner
+ size_limits inner
+ maximization outer
+ fullscreen inner
+ aspect_ratio inner
+ onscreen outer
+
+ - Dang, I started writing this list too late -- I know I had
+ something else in mind too.
+
+Extra window.h flags:
+ onscreen (136307)
+ vert_maximized, horiz_maximized (113601)
+ on_single_xinerama (unfiled)
+
Bugs to fix:
unfiled - constraints.c is overly complicated
unfiled - constraints.c is not robust when all constraints cannot be met
@@ -7,6 +40,7 @@ Bugs to fix:
even-number-of-pixels in resize)
unfiled - get_outermost_onscreen_positions is decoration-unaware
unfiled - constraints.c documentation is difficult to understand
+ unfiled - should try to keep windows on a single xinerama
109553 - gravity w/ simultaneous move & resize doesn't work
113601 - maximize vert and horiz should toggle & be constrained
122196 - windows show up under vertical panels
diff --git a/src/constraints.c b/src/constraints.c
index 2060d4d0..f3ac87b0 100644
--- a/src/constraints.c
+++ b/src/constraints.c
@@ -292,6 +292,10 @@ static void extend_by_frame (MetaRectangle *rect,
const MetaFrameGeometry *fgeom);
static void unextend_by_frame (MetaRectangle *rect,
const MetaFrameGeometry *fgeom);
+static void resize_with_gravity (MetaRectangle *rect,
+ int gravity,
+ int new_width,
+ int new_height);
inline void get_size_limits (const MetaWindow *window,
const MetaFrameGeometry *fgeom,
MetaRectangle *min_size,
@@ -410,7 +414,7 @@ setup_constraint_info (ConstraintInfo *info,
info->is_user_action = (flags & META_USER_MOVE_RESIZE);
- info->gravity = resize_gravity;
+ info->resize_gravity = resize_gravity;
/* We need to get a pseduo_gravity for user resize operations (so
* that user resize followed by min size hints don't end up moving
* window--see bug 312007).
@@ -439,7 +443,7 @@ setup_constraint_info (ConstraintInfo *info,
else if (orig->y + orig->height == new->y + new->height)
pseduo_gravity = SouthEastGravity;
}
- info->gravity = pseudo_gravity;
+ info->resize_gravity = pseudo_gravity;
}
meta_window_get_work_area_current_xinerama (window, &info->work_area_xinerama);
@@ -543,8 +547,8 @@ unextend_by_frame (MetaRectangle *rect,
static void
resize_with_gravity (MetaRectangle *rect,
int gravity,
- int new_height,
- int new_width)
+ int new_width,
+ int new_height)
{
/* Do the gravity adjustment */
@@ -738,12 +742,14 @@ constrain_maximization (MetaWindow *window,
return TRUE;
/* Determine whether constraint applies; exit if it doesn't */
+ if (!window->maximized)
+ return TRUE;
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);
gboolean too_small = !meta_rectangle_could_fit_rect (max_size, work_area);
- if (!window->maximized || too_big || too_small)
+ if (too_big || too_small)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is */
@@ -767,13 +773,15 @@ constrain_fullscreen (MetaWindow *window,
return TRUE;
/* Determine whether constraint applies; exit if it doesn't */
+ if (!window->fullscreen)
+ return TRUE;
MetaRectangle min_size, max_size;
MetaRectangle xinerama = info->entire_xinerama;
extend_by_frame (&xinerama, info->fgeom);
get_size_limits (window, info->fgeom, &min_size, &max_size);
gboolean too_big = !meta_rectangle_could_fit_rect (xinerama, min_size);
gboolean too_small = !meta_rectangle_could_fit_rect (max_size, xinerama);
- if (!window->maximized || too_big || too_small)
+ if (too_big || too_small)
return TRUE;
/* Determine whether constraint is already satisfied; exit if it is */
@@ -784,6 +792,7 @@ constrain_fullscreen (MetaWindow *window,
/*** Enforce constraint ***/
info->current = info->xinerama;
+ return TRUE;
}
#if 0
@@ -828,3 +837,234 @@ constrain_clamp_size (MetaWindow *window,
return TRUE;
}
#endif
+
+static gboolean
+constrain_size_increments (MetaWindow *window,
+ ConstraintInfo *info,
+ ConstraintPriority priority,
+ gboolean check_only);
+{
+ if (priority > PRIORITY_SIZE_HINTS_INCREMENTS)
+ return TRUE;
+
+ /* Determine whether constraint applies; exit if it doesn't */
+ if (window->maximized || window->fullscreen ||
+ info->action_type == ACTION_MOVE)
+ return TRUE;
+
+ /* Determine whether constraint is already satisfied; exit if it is */
+ int bh, hi, bw, wi, extra_height, extra_width;
+ bh = window->size_hints.base_height;
+ hi = window->size_hints.height_increment;
+ bw = window->size_hints.base_width;
+ wi = window->size_hints.width_increment;
+ extra_height = (info->current.height - bh) % hi;
+ extra_width = (info->current.widht - bw) % wi;
+ gboolean constraint_already_satisfied =
+ (extra_height == 0 && extra_width == 0);
+
+ if (check_only || constraint_already_satisfied)
+ return constraint_already_satisfied;
+
+ /*** Enforce constraint ***/
+ /* Shrink to base + N * inc */
+ resize_with_gravity (info->current,
+ info->resize_gravity,
+ info->current.width - extra_width,
+ info->current.height - extra_height);
+ return TRUE;
+}
+
+static gboolean
+constrain_size_limits (MetaWindow *window,
+ ConstraintInfo *info,
+ ConstraintPriority priority,
+ gboolean check_only);
+{
+ if (priority > PRIORITY_SIZE_HINTS_LIMITS)
+ return TRUE;
+
+ /* Determine whether constraint applies; exit if it doesn't.
+ *
+ * Note: The old code didn't apply this constraint for fullscreen or
+ * maximized windows--but that seems odd to me. *shrug*
+ */
+ MetaRectangle min_size, max_size;
+ get_size_limits (window, info->fgeom, &min_size, &max_size);
+ gboolean limits_are_inconsistent =
+ min_size.width > max_size.width || min_size.height > max_size.height;
+ if (limits_are_inconsistent || info->action_type == ACTION_MOVE)
+ return TRUE;
+
+ /* Determine whether constraint is already satisfied; exit if it is */
+ gboolean too_big = !meta_rectangle_could_fit_rect (info->current, min_size);
+ gboolean too_small = !meta_rectangle_could_fit_rect (max_size, info->current);
+ gboolean constraint_already_satisfied = !too_big && !too_small;
+ if (check_only || constraint_already_satisfied)
+ return constraint_already_satisfied;
+
+ /*** Enforce constraint ***/
+ int new_width = MIN (max_size.width,
+ MAX (min_size.width, info->current.width));
+ int new_height = MIN (max_size.height,
+ MAX (min_size.height, info->current.height));
+ resize_with_gravity (info->current,
+ info->resize_gravity,
+ new_width,
+ new_height);
+ return TRUE;
+}
+
+static gboolean
+constrain_aspect_ratio (MetaWindow *window,
+ ConstraintInfo *info,
+ ConstraintPriority priority,
+ gboolean check_only)
+{
+ if (priority > PRIORITY_ASPECT_RATIO)
+ return TRUE;
+
+ /* Determine whether constraint applies; exit if it doesn't.
+ int min_ax, min_ay, max_ax, max_ay;
+ min_ax = window->size_hints.min_aspect.x;
+ min_ay = window->size_hints.min_aspect.y;
+ max_ax = window->size_hints.max_aspect.x;
+ max_ay = window->size_hints.max_aspect.y;
+ gboolean constraints_are_inconsistent =
+ min_ax / ((double)min_ay) > max_ax / ((double)max_ay);
+ if (constraints_are_inconsistent || window->maximized || window->fullscreen ||
+ info->action_type == ACTION_MOVE)
+ return TRUE;
+
+ /* Determine whether constraint is already satisfied; exit if it is */
+ int slop_allowed_for_min, slop_allowed_for_max;
+ slop_allowed_for_min = (min_ax % min_ay == 0) ? 0 : 1;
+ slop_allowed_for_max = (max_ax % max_ay == 0) ? 0 : 1;
+ /* min_ax width max_ax
+ * Need: ------ <= ------ <= ------
+ * min_ay height max_ay
+ gboolean constraint_already_satisfied =
+ info->current.width >=
+ (info->current.height * min_ax / min_ay) - slop_allowed_for_min &&
+ info->current.width <=
+ (info->current.height * max_ax / max_ay) + slop_allowed_for_max;
+ if (check_only || constraint_already_satisfied)
+ return constraint_already_satisfied;
+
+ /*** Enforce constraint ***/
+#if 0
+ if (info->current.width == info->orig.width)
+ {
+ /* User changed height; change width to match */
+ int min_width, max_width, new_width;
+ min_width = info->current.height * min_ax / min_ay;
+ max_width = info->current.height * max_ax / max_ay;
+ new_width = MIN (max_width, MAX (min_width, info->current.width));
+ resize_with_gravity (info->current,
+ info->resize_gravity,
+ new_width,
+ info->current.height);
+ }
+ else if (info->current.height == info->orig.height)
+ {
+ /* User changed width; change height to match */
+ int min_height, max_height, new_height;
+ min_height = info->current.width * min_ay / min_ax;
+ max_height = info->current.width * max_ay / max_ax;
+ new_height = MIN (max_height, MAX (min_height, info->current.height));
+ resize_with_gravity (info->current,
+ info->resize_gravity,
+ info->current.width,
+ new_height);
+ }
+#endif
+
+ /* Pseduo-code:
+ *
+ * 1) Find new rect, A, based on keeping height fixed
+ * 2) Find new rect, B, based on keeping width fixed
+ * 3) If info->current is strictly larger than info->orig
+ * (i.e. could contain it), then discard either of A and B
+ * that represent an decrease of area relative to info->orig
+ * 4) If info->current is strictly smaller than info->orig
+ * (i.e. could be contained in it), then discard either of A and
+ * B that represent an increase of area relative to info->orig
+ * 5) If both A and B remain (possible in the cases of the user
+ * changing both width and height simultaneously), choose the one
+ * which is closer in area to info->orig.
+
+ MetaRectangle A, B;
+ int min_size, max_size, new_size;
+
+ /* Find new rect A */
+ A = B = info->current;
+ min_size = info->current.height * min_ax / min_ay;
+ max_size = info->current.height * max_ax / max_ay;
+ new_size = MIN (max_size, MAX (min_size, info->current.width));
+ A.width = new_size;
+
+ /* Find new rect B */
+ B = info->current;
+ min_size = info->current.width * min_ay / min_ax;
+ max_size = info->current.width * max_ay / max_ax;
+ new_size = MIN (max_size, MAX (min_size, info->current.height));
+ B.height = new_size;
+
+ gboolean a_valid, b_valid;
+ int ref_area, a_area, b_area;
+ a_valid = b_valid = true;
+ ref_area = meta_rectangle_area (info->orig);
+ a_area = meta_rectangle_area (&A);
+ b_area = meta_rectangle_area (&B);
+
+ /* Discard too-small rects if we're increasing in size */
+ if (meta_rectangle_could_fit_rect (info->current, info->orig))
+ {
+ if (a_area < ref_area)
+ a_valid = FALSE;
+
+ if (b_area < ref_area)
+ b_valid = FALSE;
+ }
+
+ /* Discard too-large rects if we're decreasing in size */
+ if (meta_rectangle_could_fit_rect (info->orig, info->current))
+ {
+ if (a_area > ref_area)
+ a_valid = FALSE;
+
+ if (b_area > ref_area)
+ b_valid = FALSE;
+ }
+
+ /* If both are still valid, use the one closer in area to info->orig */
+ if (a_valid && b_valid)
+ {
+ if (abs (a_area - ref_area) < abs (b_area - ref_area))
+ b_valid = FALSE;
+ else
+ a_valid = FALSE;
+ }
+
+ if (!a_valid && !b_valid)
+ /* This should only be possible for initial placement; we just
+ * punt and pick one */
+ resize_with_gravity (info->current,
+ info->resize_gravity,
+ A.width,
+ A.height);
+ else if (!b_valid)
+ resize_with_gravity (info->current,
+ info->resize_gravity,
+ A.width,
+ A.height);
+ else if (!a_valid)
+ resize_with_gravity (info->current,
+ info->resize_gravity,
+ A.width,
+ A.height);
+ else
+ g_error ("Was this programmed by monkeys?!?\n");
+
+ return TRUE;
+}