diff options
author | Elijah Newren <newren@gmail.com> | 2005-09-19 06:52:56 +0000 |
---|---|---|
committer | Elijah Newren <newren@src.gnome.org> | 2005-09-19 06:52:56 +0000 |
commit | 6f1ab510df997dbb6a1e691ba3e721d6e545f29f (patch) | |
tree | acb9793b9e9db90803eb5bb56f08cc327717d855 | |
parent | fdcea4c6927712d54e01f342922eb323d5363457 (diff) | |
download | metacity-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-- | ChangeLog | 28 | ||||
-rw-r--r-- | constraints-ideas.txt | 34 | ||||
-rw-r--r-- | src/constraints.c | 252 |
3 files changed, 307 insertions, 7 deletions
@@ -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; +} |