Avoid new windows being obscured by the focus window (and thus possibly

2005-02-11  Elijah Newren  <newren@gmail.com>

	Avoid new windows being obscured by the focus window (and thus
	possibly lost).  Fixes #166524.

	* src/place.c: new MetaWindowDirection enum,
	(find_most_freespace): new function to find where there is the
	most space available around the focused window,
	(meta_window_place): if a window is denied focus and the window
	overlaps the focused window, retry the first-fit algorithm only
	paying attention to the focus window position and if that fails
	just find the location on the screen with the most space
	available.

	* src/window.h: (struct MetaWindow): new
	denied_focus_and_not_transient bitfield

	* src/window.c: (meta_window_new_with_attrs): initialize
	denied_focus_and_not_transient, (meta_window_show): set and unset
	the denied_focus_and_not_transient field appropriately
This commit is contained in:
Elijah Newren 2005-02-11 19:20:44 +00:00 committed by Elijah Newren
parent f8c41ca016
commit d31a0829be
4 changed files with 160 additions and 1 deletions

View File

@ -1,3 +1,24 @@
2005-02-11 Elijah Newren <newren@gmail.com>
Avoid new windows being obscured by the focus window (and thus
possibly lost). Fixes #166524.
* src/place.c: new MetaWindowDirection enum,
(find_most_freespace): new function to find where there is the
most space available around the focused window,
(meta_window_place): if a window is denied focus and the window
overlaps the focused window, retry the first-fit algorithm only
paying attention to the focus window position and if that fails
just find the location on the screen with the most space
available.
* src/window.h: (struct MetaWindow): new
denied_focus_and_not_transient bitfield
* src/window.c: (meta_window_new_with_attrs): initialize
denied_focus_and_not_transient, (meta_window_show): set and unset
the denied_focus_and_not_transient field appropriately
2005-02-08 Aidan Delaney <adelaney@cs.may.ie> 2005-02-08 Aidan Delaney <adelaney@cs.may.ie>
Removed useless function call. #166730 Removed useless function call. #166730

View File

@ -30,6 +30,14 @@
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
typedef enum
{
META_LEFT,
META_RIGHT,
META_TOP,
META_BOTTOM
} MetaWindowDirection;
static gint static gint
northwestcmp (gconstpointer a, gconstpointer b) northwestcmp (gconstpointer a, gconstpointer b)
{ {
@ -224,6 +232,80 @@ find_next_cascade (MetaWindow *window,
} }
} }
static void
find_most_freespace (MetaWindow *window,
MetaFrameGeometry *fgeom,
/* visible windows on relevant workspaces */
MetaWindow *focus_window,
int x,
int y,
int *new_x,
int *new_y)
{
MetaWindowDirection side;
int max_area;
int max_width, max_height, left, right, top, bottom;
int frame_size_left, frame_size_top;
MetaRectangle work_area;
MetaRectangle avoid;
MetaRectangle outer;
frame_size_left = fgeom ? fgeom->left_width : 0;
frame_size_top = fgeom ? fgeom->top_height : 0;
meta_window_get_work_area_current_xinerama (focus_window, &work_area);
meta_window_get_outer_rect (focus_window, &avoid);
meta_window_get_outer_rect (window, &outer);
/* Find the areas of choosing the various sides of the focus window */
max_width = MIN (avoid.width, outer.width);
max_height = MIN (avoid.height, outer.height);
left = MIN (avoid.x, outer.width);
right = MIN (work_area.width - (avoid.x + avoid.width), outer.width);
top = MIN (avoid.y, outer.height);
bottom = MIN (work_area.height - (avoid.y + avoid.height), outer.height);
/* Find out which side of the focus_window can show the most of the window */
side = META_LEFT;
max_area = left*max_height;
if (right*max_height > max_area)
{
side = META_RIGHT;
max_area = right*max_height;
}
if (top*max_width > max_area)
{
side = META_TOP;
max_area = top*max_width;
}
if (bottom*max_width > max_area)
side = META_BOTTOM;
/* Place the window on the relevant side; convert coord to position of window,
* not position of frame.
*/
switch (side)
{
case META_LEFT:
*new_x = work_area.x + frame_size_left;
*new_y = avoid.y + frame_size_top;
break;
case META_RIGHT:
*new_x = work_area.x + work_area.width - outer.width + frame_size_left;
*new_y = avoid.y + frame_size_top;
break;
case META_TOP:
*new_x = avoid.x + frame_size_left;
*new_y = work_area.y + frame_size_top;
break;
case META_BOTTOM:
*new_x = avoid.x + frame_size_left;
*new_y = work_area.y + work_area.height - outer.height + frame_size_top;
break;
}
}
static int static int
intcmp (const void* a, const void* b) intcmp (const void* a, const void* b)
{ {
@ -774,7 +856,7 @@ meta_window_place (MetaWindow *window,
if (find_first_fit (window, fgeom, windows, if (find_first_fit (window, fgeom, windows,
xineramas_list, n_xineramas, xineramas_list, n_xineramas,
x, y, &x, &y)) x, y, &x, &y))
goto done; goto done_check_denied_focus;
/* This is a special-case origin-cascade so that windows that are /* This is a special-case origin-cascade so that windows that are
* too large to fit onto a workspace (and which will be * too large to fit onto a workspace (and which will be
@ -841,6 +923,51 @@ meta_window_place (MetaWindow *window,
window->maximize_after_placement = TRUE; window->maximize_after_placement = TRUE;
} }
} }
done_check_denied_focus:
/* If the window is being denied focus and isn't a transient of the
* focus window, we do NOT want it to overlap with the focus window
* if at all possible. This is guaranteed to only be called if the
* focus_window is non-NULL, and we try to avoid that window.
*/
if (window->denied_focus_and_not_transient)
{
gboolean found_fit;
MetaWindow *focus_window;
MetaRectangle overlap;
focus_window = window->display->focus_window;
g_assert (focus_window != NULL);
/* No need to do anything if the window doesn't overlap at all */
found_fit = !meta_rectangle_intersect (&window->rect,
&focus_window->rect,
&overlap);
/* Try to do a first fit again, this time only taking into account the
* focus window.
*/
if (!found_fit)
{
GList *focus_window_list;
focus_window_list = g_list_prepend (NULL, focus_window);
/* Reset x and y ("origin" placement algorithm) */
x = xi->x_origin;
y = xi->y_origin;
found_fit = find_first_fit (window, fgeom, focus_window_list,
xineramas_list, n_xineramas,
x, y, &x, &y);
g_list_free (focus_window_list);
}
/* If that still didn't work, just place it where we can see as much
* as possible.
*/
if (!found_fit)
find_most_freespace (window, fgeom, focus_window, x, y, &x, &y);
}
done: done:
g_free (xineramas_list); g_free (xineramas_list);

View File

@ -444,6 +444,7 @@ meta_window_new_with_attrs (MetaDisplay *display,
meta_topic (META_DEBUG_PLACEMENT, meta_topic (META_DEBUG_PLACEMENT,
"Not placing window 0x%lx since it's already mapped\n", "Not placing window 0x%lx since it's already mapped\n",
xwindow); xwindow);
window->denied_focus_and_not_transient = FALSE;
window->unmanaging = FALSE; window->unmanaging = FALSE;
window->calc_showing_queued = FALSE; window->calc_showing_queued = FALSE;
window->move_resize_queued = FALSE; window->move_resize_queued = FALSE;
@ -1678,6 +1679,8 @@ meta_window_show (MetaWindow *window)
{ {
meta_window_stack_just_below (window, window->display->focus_window); meta_window_stack_just_below (window, window->display->focus_window);
ensure_mru_position_after (window, window->display->focus_window); ensure_mru_position_after (window, window->display->focus_window);
if (!window->placed)
window->denied_focus_and_not_transient = TRUE;
} }
} }
@ -1701,6 +1704,11 @@ meta_window_show (MetaWindow *window)
*/ */
window->placed = TRUE; window->placed = TRUE;
did_placement = TRUE; did_placement = TRUE;
/* Don't want to accidentally reuse the fact that we had been denied
* focus in any future constraints unless we're denied focus again.
*/
window->denied_focus_and_not_transient = FALSE;
} }
/* Shaded means the frame is mapped but the window is not */ /* Shaded means the frame is mapped but the window is not */

View File

@ -207,6 +207,9 @@ struct _MetaWindow
/* Have we placed this window? */ /* Have we placed this window? */
guint placed : 1; guint placed : 1;
/* Is this not a transient of the focus window which is being denied focus? */
guint denied_focus_and_not_transient : 1;
/* Has this window not ever been shown yet? */ /* Has this window not ever been shown yet? */
guint showing_for_first_time : 1; guint showing_for_first_time : 1;