Add a constrain_titlebar_visible constraint; should fix both bug 333328

2006-08-07  Elijah Newren  <newren gmail com>

	Add a constrain_titlebar_visible constraint; should fix both bug
	333328 and bug 345522.  Not perfect (minor annoying snap pulling
	windows back onscreen, plus an ugly hack almost as bad as the old
	one), but tarballs are due in less than half an hour.  ;-)

	* src/boxes.[ch] (meta_rectangle_overlaps_with_region):
	new function

	* src/constraints.c (constrain_titlebar_visible): new function,
	  (enum ConstraintPriority, array all_constraints,
	  update_onscreen_requirements): various small changes to
	  accomodate the new function

	* src/edge-resistance.c: remove the infinite edge resistance,
	which was a big hack of a way to workaround the lack of a
	titlebar_visible constraint

	* src/window.[ch] (MetaWindow): new require_titlebar_visible
	bitfield, (meta_window_new_with_attrs): initialized here
This commit is contained in:
Elijah Newren 2006-08-07 23:34:55 +00:00 committed by Elijah Newren
parent acc6c97997
commit 57bedc42a4
7 changed files with 176 additions and 34 deletions

View File

@ -1,3 +1,25 @@
2006-08-07 Elijah Newren <newren gmail com>
Add a constrain_titlebar_visible constraint; should fix both bug
333328 and bug 345522. Not perfect (minor annoying snap pulling
windows back onscreen, plus an ugly hack almost as bad as the old
one), but tarballs are due in less than half an hour. ;-)
* src/boxes.[ch] (meta_rectangle_overlaps_with_region):
new function
* src/constraints.c (constrain_titlebar_visible): new function,
(enum ConstraintPriority, array all_constraints,
update_onscreen_requirements): various small changes to
accomodate the new function
* src/edge-resistance.c: remove the infinite edge resistance,
which was a big hack of a way to workaround the lack of a
titlebar_visible constraint
* src/window.[ch] (MetaWindow): new require_titlebar_visible
bitfield, (meta_window_new_with_attrs): initialized here
2006-08-07 Elijah Newren <newren gmail com> 2006-08-07 Elijah Newren <newren gmail com>
* src/frames.c (meta_frames_button_press_event): Patch from Chris * src/frames.c (meta_frames_button_press_event): Patch from Chris

View File

@ -705,6 +705,25 @@ meta_rectangle_contained_in_region (const GList *spanning_rects,
return contained; return contained;
} }
gboolean
meta_rectangle_overlaps_with_region (const GList *spanning_rects,
const MetaRectangle *rect)
{
const GList *temp;
gboolean overlaps;
temp = spanning_rects;
overlaps = FALSE;
while (!overlaps && temp != NULL)
{
overlaps = overlaps || meta_rectangle_overlap (temp->data, rect);
temp = temp->next;
}
return overlaps;
}
void void
meta_rectangle_clamp_to_fit_into_region (const GList *spanning_rects, meta_rectangle_clamp_to_fit_into_region (const GList *spanning_rects,
FixedDirections fixed_directions, FixedDirections fixed_directions,

View File

@ -183,6 +183,9 @@ gboolean meta_rectangle_could_fit_in_region (
gboolean meta_rectangle_contained_in_region ( gboolean meta_rectangle_contained_in_region (
const GList *spanning_rects, const GList *spanning_rects,
const MetaRectangle *rect); const MetaRectangle *rect);
gboolean meta_rectangle_overlaps_with_region (
const GList *spanning_rects,
const MetaRectangle *rect);
/* Make the rectangle small enough to fit into one of the spanning_rects, /* Make the rectangle small enough to fit into one of the spanning_rects,
* but make it no smaller than min_size. * but make it no smaller than min_size.

View File

@ -97,6 +97,7 @@ typedef enum
PRIORITY_MAXIMIZATION = 2, PRIORITY_MAXIMIZATION = 2,
PRIORITY_FULLSCREEN = 2, PRIORITY_FULLSCREEN = 2,
PRIORITY_SIZE_HINTS_LIMITS = 3, PRIORITY_SIZE_HINTS_LIMITS = 3,
PRIORITY_TITLEBAR_VISIBLE = 4,
PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA = 4, PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA = 4,
PRIORITY_MAXIMUM = 4 // Dummy value used for loop end = max(all priorities) PRIORITY_MAXIMUM = 4 // Dummy value used for loop end = max(all priorities)
} ConstraintPriority; } ConstraintPriority;
@ -165,6 +166,10 @@ static gboolean constrain_fully_onscreen (MetaWindow *window,
ConstraintInfo *info, ConstraintInfo *info,
ConstraintPriority priority, ConstraintPriority priority,
gboolean check_only); gboolean check_only);
static gboolean constrain_titlebar_visible (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only);
static gboolean constrain_partially_onscreen (MetaWindow *window, static gboolean constrain_partially_onscreen (MetaWindow *window,
ConstraintInfo *info, ConstraintInfo *info,
ConstraintPriority priority, ConstraintPriority priority,
@ -209,6 +214,7 @@ static const Constraint all_constraints[] = {
{constrain_aspect_ratio, "constrain_aspect_ratio"}, {constrain_aspect_ratio, "constrain_aspect_ratio"},
{constrain_to_single_xinerama, "constrain_to_single_xinerama"}, {constrain_to_single_xinerama, "constrain_to_single_xinerama"},
{constrain_fully_onscreen, "constrain_fully_onscreen"}, {constrain_fully_onscreen, "constrain_fully_onscreen"},
{constrain_titlebar_visible, "constrain_titlebar_visible"},
{constrain_partially_onscreen, "constrain_partially_onscreen"}, {constrain_partially_onscreen, "constrain_partially_onscreen"},
{NULL, NULL} {NULL, NULL}
}; };
@ -536,23 +542,23 @@ update_onscreen_requirements (MetaWindow *window,
window->type == META_WINDOW_DOCK) window->type == META_WINDOW_DOCK)
return; return;
/* USABILITY NOTE: Naturally, I only want the require_fully_onscreen and /* USABILITY NOTE: Naturally, I only want the require_fully_onscreen,
* require_on_single_xinerama flags to *become false* due to user * require_on_single_xinerama, and require_titlebar_visible flags to
* interactions (which is allowed since certain constraints are ignored * *become false* due to user interactions (which is allowed since
* for user interactions regardless of the setting of these flags). * certain constraints are ignored for user interactions regardless of
* However, whether to make these flags *become true* due to just an * the setting of these flags). However, whether to make these flags
* application interaction is a little trickier. It's possible that * *become true* due to just an application interaction is a little
* users may find not doing that strange since two application * trickier. It's possible that users may find not doing that strange
* interactions that resize in opposite ways don't necessarily end up * since two application interactions that resize in opposite ways don't
* cancelling--but it may also be strange for the user to have an * necessarily end up cancelling--but it may also be strange for the user
* application resize the window so that it's onscreen, the user forgets * to have an application resize the window so that it's onscreen, the
* about it, and then later the app is able to resize itself off the * user forgets about it, and then later the app is able to resize itself
* screen. Anyway, for now, I'm think the latter is the more problematic * off the screen. Anyway, for now, I think the latter is the more
* case but this may need to be revisited. * problematic case but this may need to be revisited.
*/ */
/* The require onscreen/on-single-xinerama stuff is relative to the /* The require onscreen/on-single-xinerama and titlebar_visible
* outer window, not the inner * stuff is relative to the outer window, not the inner
*/ */
extend_by_frame (&info->current, info->fgeom); extend_by_frame (&info->current, info->fgeom);
@ -582,6 +588,26 @@ update_onscreen_requirements (MetaWindow *window,
window->desc, window->desc,
window->require_on_single_xinerama ? "TRUE" : "FALSE"); window->require_on_single_xinerama ? "TRUE" : "FALSE");
/* Update whether we want future constraint runs to require the
* titlebar to be visible.
*/
if (window->frame && window->decorated)
{
MetaRectangle titlebar_rect;
titlebar_rect = info->current;
titlebar_rect.height = info->fgeom->top_height;
old = window->require_titlebar_visible;
window->require_titlebar_visible =
meta_rectangle_overlaps_with_region (info->usable_screen_region,
&titlebar_rect);
if (old ^ window->require_titlebar_visible)
meta_topic (META_DEBUG_GEOMETRY,
"require_titlebar_visible for %s toggled to %s\n",
window->desc,
window->require_titlebar_visible ? "TRUE" : "FALSE");
}
/* Don't forget to restore the position of the window */ /* Don't forget to restore the position of the window */
unextend_by_frame (&info->current, info->fgeom); unextend_by_frame (&info->current, info->fgeom);
} }
@ -1053,6 +1079,93 @@ constrain_fully_onscreen (MetaWindow *window,
check_only); check_only);
} }
static gboolean
constrain_titlebar_visible (MetaWindow *window,
ConstraintInfo *info,
ConstraintPriority priority,
gboolean check_only)
{
gboolean unconstrained_user_action;
gboolean retval;
int bottom_amount;
int horiz_amount_offscreen, vert_amount_offscreen;
int horiz_amount_onscreen, vert_amount_onscreen;
if (priority > PRIORITY_TITLEBAR_VISIBLE)
return TRUE;
/* Allow the titlebar beyond the top of the screen only if the user wasn't
* clicking on the titlebar to start the move.
* FIXME: This is kind of a hack; nearly as ugly as the old infinite edge
* resistance.
*/
unconstrained_user_action =
info->is_user_action &&
window->display->grab_anchor_root_y >= window->display->grab_initial_window_pos.y;
/* Exit early if we know the constraint won't apply--note that this constraint
* is only meant for normal windows (e.g. we don't want docks to be shoved
* "onscreen" by their own strut).
*/
if (window->type == META_WINDOW_DESKTOP ||
window->type == META_WINDOW_DOCK ||
!window->require_titlebar_visible ||
!window->decorated ||
unconstrained_user_action)
return TRUE;
/* Determine how much offscreen things are allowed. We first need to
* figure out how much must remain on the screen. For that, we use 25%
* window width/height but clamp to the range of (10,75) pixels. This is
* somewhat of a seat of my pants random guess at what might look good.
* Then, the amount that is allowed off is just the window size minus
* this amount (but no less than 0 for tiny windows).
*/
horiz_amount_onscreen = info->current.width / 4;
vert_amount_onscreen = info->current.height / 4;
horiz_amount_onscreen = CLAMP (horiz_amount_onscreen, 10, 75);
vert_amount_onscreen = CLAMP (vert_amount_onscreen, 10, 75);
horiz_amount_offscreen = info->current.width - horiz_amount_onscreen;
vert_amount_offscreen = info->current.height - vert_amount_onscreen;
horiz_amount_offscreen = MAX (horiz_amount_offscreen, 0);
vert_amount_offscreen = MAX (vert_amount_offscreen, 0);
/* Allow the titlebar to touch the bottom panel; If there is no titlebar,
* require vert_amount to remain on the screen.
*/
if (window->frame)
{
bottom_amount = info->current.height + info->fgeom->bottom_height;
vert_amount_onscreen = info->fgeom->top_height;
}
else
bottom_amount = vert_amount_offscreen;
/* Extend the region, have a helper function handle the constraint,
* then return the region to its original size.
*/
meta_rectangle_expand_region_conditionally (info->usable_screen_region,
horiz_amount_offscreen,
horiz_amount_offscreen,
0, /* Don't let titlebar off */
bottom_amount,
horiz_amount_onscreen,
vert_amount_onscreen);
retval =
do_screen_and_xinerama_relative_constraints (window,
info->usable_screen_region,
info,
check_only);
meta_rectangle_expand_region_conditionally (info->usable_screen_region,
-horiz_amount_offscreen,
-horiz_amount_offscreen,
0, /* Don't let titlebar off */
-bottom_amount,
horiz_amount_onscreen,
vert_amount_onscreen);
return retval;
}
static gboolean static gboolean
constrain_partially_onscreen (MetaWindow *window, constrain_partially_onscreen (MetaWindow *window,
ConstraintInfo *info, ConstraintInfo *info,

View File

@ -44,7 +44,6 @@ struct ResistanceDataForAnEdge
GSourceFunc timeout_func; GSourceFunc timeout_func;
MetaWindow *window; MetaWindow *window;
int keyboard_buildup; int keyboard_buildup;
gboolean allow_past_screen_edge;
}; };
typedef struct ResistanceDataForAnEdge ResistanceDataForAnEdge; typedef struct ResistanceDataForAnEdge ResistanceDataForAnEdge;
@ -397,18 +396,6 @@ apply_edge_resistance (MetaWindow *window,
{ {
int threshold; int threshold;
/* INFINITE RESISTANCE for screen edges under certain cases; If
* the edge is relevant and we're moving towards it and it's a
* screen edge and infinite resistance has been requested for
* this particular grab op then don't allow movement past it.
*/
if (edge->edge_type == META_EDGE_SCREEN &&
!resistance_data->allow_past_screen_edge &&
movement_towards_edge (edge->side_type, increment))
{
return compare;
}
/* TIMEOUT RESISTANCE: If the edge is relevant and we're moving /* TIMEOUT RESISTANCE: If the edge is relevant and we're moving
* towards it, then we may want to have some kind of time delay * towards it, then we may want to have some kind of time delay
* before the user can move past this edge. * before the user can move past this edge.
@ -913,12 +900,6 @@ initialize_grab_edge_resistance_data (MetaDisplay *display)
edge_data->right_data.keyboard_buildup = 0; edge_data->right_data.keyboard_buildup = 0;
edge_data->top_data.keyboard_buildup = 0; edge_data->top_data.keyboard_buildup = 0;
edge_data->bottom_data.keyboard_buildup = 0; edge_data->bottom_data.keyboard_buildup = 0;
edge_data->left_data.allow_past_screen_edge = TRUE;
edge_data->right_data.allow_past_screen_edge = TRUE;
edge_data->bottom_data.allow_past_screen_edge = TRUE;
edge_data->top_data.allow_past_screen_edge =
display->grab_anchor_root_y >= display->grab_initial_window_pos.y;
} }
void void

View File

@ -448,6 +448,7 @@ meta_window_new_with_attrs (MetaDisplay *display,
window->fullscreen = FALSE; window->fullscreen = FALSE;
window->require_fully_onscreen = TRUE; window->require_fully_onscreen = TRUE;
window->require_on_single_xinerama = TRUE; window->require_on_single_xinerama = TRUE;
window->require_titlebar_visible = TRUE;
window->on_all_workspaces = FALSE; window->on_all_workspaces = FALSE;
window->shaded = FALSE; window->shaded = FALSE;
window->initially_iconic = FALSE; window->initially_iconic = FALSE;

View File

@ -138,6 +138,9 @@ struct _MetaWindow
/* Whether we're trying to constrain the window to be on a single xinerama */ /* Whether we're trying to constrain the window to be on a single xinerama */
guint require_on_single_xinerama : 1; guint require_on_single_xinerama : 1;
/* Whether we're trying to constrain the window's titlebar to be onscreen */
guint require_titlebar_visible : 1;
/* Whether we're sticky in the multi-workspace sense /* Whether we're sticky in the multi-workspace sense
* (vs. the not-scroll-with-viewport sense, we don't * (vs. the not-scroll-with-viewport sense, we don't
* have no stupid viewports) * have no stupid viewports)