From 010e620a344dd690df94f53bf212667b3547dc2b Mon Sep 17 00:00:00 2001 From: Rob Adams Date: Mon, 9 Jun 2003 23:49:02 +0000 Subject: [PATCH] Revamp placement policy for windows that are maximized when they are 2003-06-09 Rob Adams 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. --- ChangeLog | 35 +++++++++++ src/constraints.c | 26 ++++++-- src/place.c | 149 +++++++++++++++++++++++++--------------------- src/window.c | 66 ++++++++++---------- src/window.h | 3 + 5 files changed, 172 insertions(+), 107 deletions(-) diff --git a/ChangeLog b/ChangeLog index d2f619173..80b5c0673 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2003-06-09 Rob Adams + + 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 * src/metacity-dialog.c (warn_about_no_sm_support): install an diff --git a/src/constraints.c b/src/constraints.c index 7913a8c10..bc658a24f 100644 --- a/src/constraints.c +++ b/src/constraints.c @@ -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, ¤t, - 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 diff --git a/src/place.c b/src/place.c index 4e1a7dde3..df4800160 100644 --- a/src/place.c +++ b/src/place.c @@ -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; diff --git a/src/window.c b/src/window.c index ddba6a07f..31af946ba 100644 --- a/src/window.c +++ b/src/window.c @@ -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) diff --git a/src/window.h b/src/window.h index 2b6a8fa0c..f9353d1ec 100644 --- a/src/window.h +++ b/src/window.h @@ -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);