summaryrefslogtreecommitdiff
path: root/src/place.c
diff options
context:
space:
mode:
authorElijah Newren <newren@gmail.com>2005-02-11 19:20:44 +0000
committerElijah Newren <newren@src.gnome.org>2005-02-11 19:20:44 +0000
commitd31a0829be1e40760ec1e829a36b36135aa082c1 (patch)
treef43894e386e5dac7478dfb0bef175765960dbcfe /src/place.c
parentf8c41ca0168661ee1819ea6e54171cda4aa768b7 (diff)
downloadmetacity-d31a0829be1e40760ec1e829a36b36135aa082c1.tar.gz
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
Diffstat (limited to 'src/place.c')
-rw-r--r--src/place.c129
1 files changed, 128 insertions, 1 deletions
diff --git a/src/place.c b/src/place.c
index e6f67a6f..ef0bf046 100644
--- a/src/place.c
+++ b/src/place.c
@@ -30,6 +30,14 @@
#include <math.h>
#include <stdlib.h>
+typedef enum
+{
+ META_LEFT,
+ META_RIGHT,
+ META_TOP,
+ META_BOTTOM
+} MetaWindowDirection;
+
static gint
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
intcmp (const void* a, const void* b)
{
@@ -774,7 +856,7 @@ meta_window_place (MetaWindow *window,
if (find_first_fit (window, fgeom, windows,
xineramas_list, n_xineramas,
x, y, &x, &y))
- goto done;
+ goto done_check_denied_focus;
/* This is a special-case origin-cascade so that windows that are
* 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;
}
}
+
+ 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:
g_free (xineramas_list);