Revamp placement policy for windows that are maximized when they are

2003-06-09  Rob Adams  <robadams@ucla.edu>

	Revamp placement policy for windows that are maximized when they
	are mapped, including windows that set a hint to be maximized or
	windows that are auto-maximized using our heuristic.  See #111902.

	* src/window.h: add new flag maximize_after_placement and new
	function meta_window_maximize_internal.

	* src/window.c (meta_window_new): initialize
	maximize_after_placement to FALSE and remove the automaximize
	heuristic.
	(meta_window_maximize_internal): new function accepts a saved_rect
	argument to be used as the new saved_rect for the window, and does
	not queue a move_resize.
	(meta_window_maximize): re-implement using
	meta_window_maximize_internal.
	(update_net_wm_state): If a window has a maximize hint set on
	startup set maximize_after_placement to TRUE

	* src/constraints.c (meta_window_constrain): Update the xinerama
	information in the ConstraintInfo after placing the window, and
	maximize the window after placement if
	window->maximize_after_placement

	* src/place.c (find_first_fit): take a natural xinerama list as an
	argument instead of generating it here
	(constrain_placement): remove function, since it is no longer
	needed
	(meta_window_place): generate the natural xinerama list here and
	pass it into find_first_fit.  If find_first_fit fails, use the
	list to find empty xineramas where we can place windows that may
	be maximized later.  This makes maximized windows follow the
	correct placement policy.  Move the automaximize heuristic here.
This commit is contained in:
Rob Adams 2003-06-09 23:49:02 +00:00 committed by Rob Adams
parent 3f6bad087d
commit 010e620a34
5 changed files with 172 additions and 107 deletions

View File

@ -1,3 +1,38 @@
2003-06-09 Rob Adams <robadams@ucla.edu>
Revamp placement policy for windows that are maximized when they
are mapped, including windows that set a hint to be maximized or
windows that are auto-maximized using our heuristic. See #111902.
* src/window.h: add new flag maximize_after_placement and new
function meta_window_maximize_internal.
* src/window.c (meta_window_new): initialize
maximize_after_placement to FALSE and remove the automaximize
heuristic.
(meta_window_maximize_internal): new function accepts a saved_rect
argument to be used as the new saved_rect for the window, and does
not queue a move_resize.
(meta_window_maximize): re-implement using
meta_window_maximize_internal.
(update_net_wm_state): If a window has a maximize hint set on
startup set maximize_after_placement to TRUE
* src/constraints.c (meta_window_constrain): Update the xinerama
information in the ConstraintInfo after placing the window, and
maximize the window after placement if
window->maximize_after_placement
* src/place.c (find_first_fit): take a natural xinerama list as an
argument instead of generating it here
(constrain_placement): remove function, since it is no longer
needed
(meta_window_place): generate the natural xinerama list here and
pass it into find_first_fit. If find_first_fit fails, use the
list to find empty xineramas where we can place windows that may
be maximized later. This makes maximized windows follow the
correct placement policy. Move the automaximize heuristic here.
2003-06-09 Rob Adams <robadams@ucla.edu>
* src/metacity-dialog.c (warn_about_no_sm_support): install an

View File

@ -1119,20 +1119,38 @@ meta_window_constrain (MetaWindow *window,
!window->maximized &&
!window->fullscreen)
{
int x, y;
MetaRectangle placed_rect = current;
meta_window_place (window, orig_fgeom, current.x, current.y,
&x, &y);
&placed_rect.x, &placed_rect.y);
/* placing the window may have changed the xinerama. Find the
* new xinerama and update the ConstraintInfo
*/
info.xinerama = meta_screen_get_xinerama_for_rect (window->screen,
&placed_rect);
meta_window_get_work_area_for_xinerama (window,
info.xinerama->number,
&info.work_area_xinerama);
update_position_limits (window, &info);
constrain_move (window, &info, &current,
x - current.x,
y - current.y,
placed_rect.x - current.x,
placed_rect.y - current.y,
new);
current = *new;
/* Ignore any non-placement movement */
x_move_delta = 0;
y_move_delta = 0;
}
if (window->maximize_after_placement &&
window->placed)
{
window->maximize_after_placement = FALSE;
meta_window_maximize_internal (window, new);
}
/* Maximization, fullscreen, etc. are defined as a move followed by

View File

@ -404,6 +404,8 @@ find_first_fit (MetaWindow *window,
MetaFrameGeometry *fgeom,
/* visible windows on relevant workspaces */
GList *windows,
int* xineramas_list,
int n_xineramas,
int x,
int y,
int *new_x,
@ -423,8 +425,6 @@ find_first_fit (MetaWindow *window,
MetaRectangle rect;
MetaRectangle work_area;
int i;
int* xineramas_list;
int n_xineramas;
retval = FALSE;
@ -447,9 +447,6 @@ find_first_fit (MetaWindow *window,
rect.height += fgeom->top_height + fgeom->bottom_height;
}
meta_screen_get_natural_xinerama_list (window->screen,
&xineramas_list,
&n_xineramas);
for (i = 0; i < n_xineramas; i++)
{
meta_topic (META_DEBUG_XINERAMA,
@ -552,68 +549,11 @@ find_first_fit (MetaWindow *window,
out:
g_free (xineramas_list);
g_list_free (below_sorted);
g_list_free (right_sorted);
return retval;
}
static void
constrain_placement (MetaWindow *window,
MetaFrameGeometry *fgeom,
int x,
int y,
int *new_x,
int *new_y)
{
/* The purpose of this function is to apply constraints that are not
* covered by window.c:constrain_position(), but should apply
* whenever we are _placing_ a window regardless of placement algorithm.
*/
MetaRectangle work_area;
int nw_x, nw_y;
int offscreen_w, offscreen_h;
MetaRectangle outer_rect;
meta_window_get_outer_rect (window, &outer_rect);
/* FIXME this is bogus because we get the current xinerama
* for the window based on its position, but we haven't
* placed it yet.
*/
meta_window_get_work_area_current_xinerama (window, &work_area);
nw_x = work_area.x;
nw_y = work_area.y;
if (window->frame)
{
nw_x += fgeom->left_width;
nw_y += fgeom->top_height;
}
/* Keep window from going off the bottom right, though we don't have
* this constraint once the window has been placed
*/
offscreen_w = (outer_rect.x + outer_rect.width) - (work_area.x + work_area.width);
if (offscreen_w > 0)
nw_x -= offscreen_w;
offscreen_h = (outer_rect.y + outer_rect.height) - (work_area.y + work_area.height);
if (offscreen_h > 0)
nw_y -= offscreen_h;
/* Keep window from going off left edge, though again we don't have
* this constraint once the window has been placed.
*/
if (x < nw_x)
x = nw_x;
if (y < nw_y)
y = nw_y;
*new_x = x;
*new_y = y;
}
void
meta_window_place (MetaWindow *window,
MetaFrameGeometry *fgeom,
@ -624,6 +564,10 @@ meta_window_place (MetaWindow *window,
{
GList *windows;
const MetaXineramaScreenInfo *xi;
int* xineramas_list = NULL;
int n_xineramas;
int i;
int placed_on = -1;
/* frame member variables should NEVER be used in here, only
* MetaFrameGeometry. But remember fgeom == NULL
@ -811,16 +755,87 @@ meta_window_place (MetaWindow *window,
x = xi->x_origin;
y = xi->y_origin;
if (find_first_fit (window, fgeom, windows, x, y, &x, &y))
meta_screen_get_natural_xinerama_list (window->screen,
&xineramas_list,
&n_xineramas);
if (find_first_fit (window, fgeom, windows,
xineramas_list, n_xineramas,
x, y, &x, &y))
goto done;
find_next_cascade (window, fgeom, windows, x, y, &x, &y);
/* This is a special-case origin-cascade so that windows that are
* too large to fit onto a workspace (and which will be
* automaximized later) will go onto an empty xinerama if one is
* available.
*/
if (window->has_maximize_func && window->decorated &&
!window->fullscreen)
{
if (window->frame)
{
x = fgeom->left_width;
y = fgeom->top_height;
}
else
{
x = 0;
y = 0;
}
for (i = 0; i < n_xineramas; i++)
{
MetaRectangle work_area;
meta_window_get_work_area_for_xinerama (window, xineramas_list[i], &work_area);
if (!rectangle_overlaps_some_window (&work_area, windows))
{
x += work_area.x;
y += work_area.y;
placed_on = i;
break;
}
}
}
/* if the window wasn't placed at the origin of an empty xinerama,
* cascade it onto the current xinerama
*/
if (placed_on == -1)
{
find_next_cascade (window, fgeom, windows, x, y, &x, &y);
placed_on = 0;
}
/* Maximize windows if they are too big for their work area (bit of
* a hack here). Assume undecorated windows probably don't intend to
* be maximized.
*/
if (window->has_maximize_func && window->decorated &&
!window->fullscreen)
{
MetaRectangle workarea;
MetaRectangle outer;
meta_window_get_work_area_for_xinerama (window,
xineramas_list[placed_on],
&workarea);
meta_window_get_outer_rect (window, &outer);
if (outer.width >= workarea.width &&
outer.height >= workarea.height)
{
outer.x = x;
outer.y = y;
meta_window_maximize_internal (window, &outer);
}
}
done:
g_free (xineramas_list);
g_list_free (windows);
constrain_placement (window, fgeom, x, y, &x, &y);
done_no_constraints:
*new_x = x;

View File

@ -417,6 +417,7 @@ meta_window_new (MetaDisplay *display,
window->user_has_move_resized = FALSE;
window->maximized = FALSE;
window->maximize_after_placement = FALSE;
window->fullscreen = FALSE;
window->on_all_workspaces = FALSE;
window->shaded = FALSE;
@ -695,28 +696,6 @@ meta_window_new (MetaDisplay *display,
}
}
/* Maximize windows if they are too big for their work
* area (bit of a hack here). Assume undecorated windows
* probably don't intend to be maximized.
*/
if (window->has_maximize_func && window->decorated &&
!window->fullscreen)
{
MetaRectangle workarea;
MetaRectangle outer;
if (!window->placed)
meta_warning ("Metacity issue: using position-based current xinerama prior to placement\n");
meta_window_get_work_area_current_xinerama (window, &workarea);
meta_window_get_outer_rect (window, &outer);
if (outer.width >= workarea.width &&
outer.height >= workarea.height)
meta_window_maximize (window);
}
/* Sync stack changes */
meta_stack_thaw (window->screen->stack);
@ -1840,30 +1819,45 @@ meta_window_save_rect (MetaWindow *window)
}
}
void
meta_window_maximize_internal (MetaWindow *window,
MetaRectangle *saved_rect)
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Maximizing %s\n", window->desc);
if (saved_rect != NULL)
window->saved_rect = *saved_rect;
else
meta_window_save_rect (window);
window->maximized = TRUE;
recalc_window_features (window);
set_net_wm_state (window);
}
void
meta_window_maximize (MetaWindow *window)
{
if (!window->maximized)
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Maximizing %s\n", window->desc);
if (window->shaded)
meta_window_unshade (window);
meta_window_save_rect (window);
window->maximized = TRUE;
/* if the window hasn't been placed yet, we'll maximize it then
*/
if (!window->placed)
{
window->maximize_after_placement = TRUE;
return;
}
meta_window_maximize_internal (window, NULL);
/* FIXME why did I put this here? */
meta_window_raise (window);
/* move_resize with new maximization constraints
*/
meta_window_queue_move_resize (window);
recalc_window_features (window);
set_net_wm_state (window);
}
}
@ -4309,9 +4303,9 @@ update_net_wm_state (MetaWindow *window)
if (atoms[i] == window->display->atom_net_wm_state_shaded)
window->shaded = TRUE;
else if (atoms[i] == window->display->atom_net_wm_state_maximized_horz)
window->maximized = TRUE;
window->maximize_after_placement = TRUE;
else if (atoms[i] == window->display->atom_net_wm_state_maximized_vert)
window->maximized = TRUE;
window->maximize_after_placement = TRUE;
else if (atoms[i] == window->display->atom_net_wm_state_modal)
window->wm_state_modal = TRUE;
else if (atoms[i] == window->display->atom_net_wm_state_skip_taskbar)

View File

@ -94,6 +94,7 @@ struct _MetaWindow
/* Whether we're maximized */
guint maximized : 1;
guint maximize_after_placement : 1;
/* Whether we're shaded */
guint shaded : 1;
@ -304,6 +305,8 @@ void meta_window_queue_calc_showing (MetaWindow *window);
void meta_window_minimize (MetaWindow *window);
void meta_window_unminimize (MetaWindow *window);
void meta_window_maximize (MetaWindow *window);
void meta_window_maximize_internal (MetaWindow *window,
MetaRectangle *saved_rect);
void meta_window_unmaximize (MetaWindow *window);
void meta_window_shade (MetaWindow *window);
void meta_window_unshade (MetaWindow *window);