Update placement policy for screen with multiple xineramas. Windows will
2003-04-05 Rob Adams <robadams@ucla.edu> Update placement policy for screen with multiple xineramas. Windows will be placed preferentially on the xinerama with the pointer, and progressively further away as needed to find a place where the window does not overlap other windows. * src/place.c (rect_fits_in_work_area): function fit_rect_in_xinerama greatly simplified to work with new placement policy. (find_first_fit): implement new first first placement scheme * src/screen.c (meta_screen_get_xinerama_neighbor): look for an xinerama in the xinerama list that is adjacent to the specified xinerama. (meta_screen_get_natural_xinerama_list): return a list of xineramas in the order to be preferred by the placement algorithm as determined by the current location of the pointer. * src/screen.h: add function prototypes and an enum used by meta_screen_get_xinerama_neighbor.
This commit is contained in:
parent
40ec58787f
commit
9bd17f4fae
22
ChangeLog
22
ChangeLog
@ -1,3 +1,25 @@
|
||||
2003-04-05 Rob Adams <robadams@ucla.edu>
|
||||
|
||||
Update placement policy for screen with multiple xineramas.
|
||||
Windows will be placed preferentially on the xinerama with the
|
||||
pointer, and progressively further away as needed to find a place
|
||||
where the window does not overlap other windows.
|
||||
|
||||
* src/place.c (rect_fits_in_work_area): function
|
||||
fit_rect_in_xinerama greatly simplified to work with new placement
|
||||
policy.
|
||||
(find_first_fit): implement new first first placement scheme
|
||||
|
||||
* src/screen.c (meta_screen_get_xinerama_neighbor): look for an
|
||||
xinerama in the xinerama list that is adjacent to the specified
|
||||
xinerama.
|
||||
(meta_screen_get_natural_xinerama_list): return a list of
|
||||
xineramas in the order to be preferred by the placement algorithm
|
||||
as determined by the current location of the pointer.
|
||||
|
||||
* src/screen.h: add function prototypes and an enum used by
|
||||
meta_screen_get_xinerama_neighbor.
|
||||
|
||||
2003-04-05 Rob Adams <robadams@ucla.edu>
|
||||
|
||||
* src/place.c (center_tile_rect_in_area): Fix a minor off-by-one
|
||||
|
266
src/place.c
266
src/place.c
@ -384,66 +384,13 @@ center_tile_rect_in_area (MetaRectangle *rect,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fit_rect_in_xinerama (MetaWindow *window,
|
||||
MetaRectangle *rect)
|
||||
rect_fits_in_work_area (MetaRectangle *work_area,
|
||||
MetaRectangle *rect)
|
||||
{
|
||||
int i;
|
||||
int best_index;
|
||||
int best_overlap;
|
||||
MetaScreen *screen;
|
||||
MetaRectangle work_area;
|
||||
const MetaXineramaScreenInfo *xsi;
|
||||
|
||||
screen = window->screen;
|
||||
|
||||
/* Find xinerama with best fit, then
|
||||
* shift rect to be entirely within it.
|
||||
*/
|
||||
best_overlap = -1;
|
||||
best_index = -1;
|
||||
|
||||
i = 0;
|
||||
while (i < screen->n_xinerama_infos)
|
||||
{
|
||||
MetaRectangle xinerama_rect;
|
||||
MetaRectangle intersect;
|
||||
int overlap;
|
||||
|
||||
xsi = &screen->xinerama_infos[i];
|
||||
|
||||
xinerama_rect.x = xsi->x_origin;
|
||||
xinerama_rect.y = xsi->y_origin;
|
||||
xinerama_rect.width = xsi->width;
|
||||
xinerama_rect.height = xsi->height;
|
||||
|
||||
if (meta_rectangle_intersect (rect, &xinerama_rect, &intersect))
|
||||
overlap = intersect.width * intersect.height;
|
||||
else
|
||||
overlap = 0;
|
||||
|
||||
if (overlap > best_overlap)
|
||||
{
|
||||
best_index = i;
|
||||
best_overlap = overlap;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
/* some overlap had to be better than -1 */
|
||||
g_assert (best_index >= 0);
|
||||
|
||||
meta_window_get_work_area_for_xinerama (window, best_index, &work_area);
|
||||
|
||||
if ((rect->x < work_area.x) || (rect->y < work_area.y) ||
|
||||
(rect->x >= work_area.x + work_area.width) ||
|
||||
(rect->y >= work_area.y + work_area.height))
|
||||
center_tile_rect_in_area (rect, &work_area);
|
||||
|
||||
/* Now return whether we are entirely within the work area */
|
||||
return
|
||||
((rect->x + rect->width) < (work_area.x + work_area.width)) &&
|
||||
((rect->y + rect->height) < (work_area.y + work_area.height));
|
||||
return ((rect->x >= work_area->x) &&
|
||||
(rect->y >= work_area->y) &&
|
||||
(rect->x + rect->width <= work_area->x + work_area->width) &&
|
||||
(rect->y + rect->height <= work_area->y + work_area->height));
|
||||
}
|
||||
|
||||
/* Find the leftmost, then topmost, empty area on the workspace
|
||||
@ -472,14 +419,26 @@ find_first_fit (MetaWindow *window,
|
||||
* existing window in each of those cases.
|
||||
*/
|
||||
int retval;
|
||||
GList *sorted;
|
||||
GList *below_sorted;
|
||||
GList *right_sorted;
|
||||
GList *tmp;
|
||||
MetaRectangle rect;
|
||||
MetaRectangle work_area;
|
||||
int i;
|
||||
int* xineramas_list;
|
||||
int n_xineramas;
|
||||
|
||||
retval = FALSE;
|
||||
sorted = NULL;
|
||||
|
||||
/* Below each window */
|
||||
below_sorted = g_list_copy (windows);
|
||||
below_sorted = g_list_sort (below_sorted, leftmost_cmp);
|
||||
below_sorted = g_list_sort (below_sorted, topmost_cmp);
|
||||
|
||||
/* To the right of each window */
|
||||
right_sorted = g_list_copy (windows);
|
||||
right_sorted = g_list_sort (right_sorted, topmost_cmp);
|
||||
right_sorted = g_list_sort (right_sorted, leftmost_cmp);
|
||||
|
||||
rect.width = window->rect.width;
|
||||
rect.height = window->rect.height;
|
||||
@ -490,110 +449,29 @@ find_first_fit (MetaWindow *window,
|
||||
rect.height += fgeom->top_height + fgeom->bottom_height;
|
||||
}
|
||||
|
||||
/* Try center-tiling on first xinerama */
|
||||
/* FIXME should use xinerama with mouse pointer
|
||||
* (or better, xinerama where window was launched
|
||||
* determined via startup notification)
|
||||
*/
|
||||
meta_window_get_work_area_for_xinerama (window, 0, &work_area);
|
||||
|
||||
center_tile_rect_in_area (&rect, &work_area);
|
||||
|
||||
if (fit_rect_in_xinerama (window, &rect) &&
|
||||
!rectangle_overlaps_some_window (&rect, windows))
|
||||
meta_screen_get_natural_xinerama_list (window->screen,
|
||||
&xineramas_list,
|
||||
&n_xineramas);
|
||||
for (i = 0; i < n_xineramas; i++)
|
||||
{
|
||||
*new_x = rect.x;
|
||||
*new_y = rect.y;
|
||||
if (fgeom)
|
||||
{
|
||||
*new_x += fgeom->left_width;
|
||||
*new_y += fgeom->top_height;
|
||||
}
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
sorted = g_list_copy (windows);
|
||||
|
||||
/* Below each window */
|
||||
sorted = g_list_sort (sorted, leftmost_cmp);
|
||||
sorted = g_list_sort (sorted, topmost_cmp);
|
||||
|
||||
tmp = sorted;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
MetaRectangle outer_rect;
|
||||
|
||||
meta_window_get_outer_rect (w, &outer_rect);
|
||||
|
||||
rect.x = outer_rect.x;
|
||||
rect.y = outer_rect.y + outer_rect.height;
|
||||
|
||||
if (fit_rect_in_xinerama (window, &rect) &&
|
||||
!rectangle_overlaps_some_window (&rect, sorted))
|
||||
{
|
||||
*new_x = rect.x;
|
||||
*new_y = rect.y;
|
||||
if (fgeom)
|
||||
{
|
||||
*new_x += fgeom->left_width;
|
||||
*new_y += fgeom->top_height;
|
||||
}
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
meta_topic (META_DEBUG_XINERAMA,
|
||||
"Natural xinerama %d is %d,%d %dx%d\n",
|
||||
i,
|
||||
window->screen->xinerama_infos[xineramas_list[i]].x_origin,
|
||||
window->screen->xinerama_infos[xineramas_list[i]].y_origin,
|
||||
window->screen->xinerama_infos[xineramas_list[i]].width,
|
||||
window->screen->xinerama_infos[xineramas_list[i]].height);
|
||||
}
|
||||
|
||||
/* To the right of each window */
|
||||
sorted = g_list_sort (sorted, topmost_cmp);
|
||||
sorted = g_list_sort (sorted, leftmost_cmp);
|
||||
|
||||
tmp = sorted;
|
||||
while (tmp != NULL)
|
||||
/* try each xinerama in the natural ordering in turn */
|
||||
i = 0;
|
||||
while (i < n_xineramas)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
MetaRectangle outer_rect;
|
||||
|
||||
meta_window_get_outer_rect (w, &outer_rect);
|
||||
|
||||
rect.x = outer_rect.x + outer_rect.width;
|
||||
rect.y = outer_rect.y;
|
||||
|
||||
if (fit_rect_in_xinerama (window, &rect) &&
|
||||
!rectangle_overlaps_some_window (&rect, sorted))
|
||||
{
|
||||
*new_x = rect.x;
|
||||
*new_y = rect.y;
|
||||
if (fgeom)
|
||||
{
|
||||
*new_x += fgeom->left_width;
|
||||
*new_y += fgeom->top_height;
|
||||
}
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
/* Try center-tile on each Xinerama screen which isn't the first */
|
||||
i = 1;
|
||||
while (i < window->screen->n_xinerama_infos)
|
||||
{
|
||||
meta_window_get_work_area_for_xinerama (window, i, &work_area);
|
||||
meta_window_get_work_area_for_xinerama (window, xineramas_list[i], &work_area);
|
||||
|
||||
center_tile_rect_in_area (&rect, &work_area);
|
||||
|
||||
if (fit_rect_in_xinerama (window, &rect) &&
|
||||
if (rect_fits_in_work_area (&work_area, &rect) &&
|
||||
!rectangle_overlaps_some_window (&rect, windows))
|
||||
{
|
||||
*new_x = rect.x;
|
||||
@ -608,12 +486,77 @@ find_first_fit (MetaWindow *window,
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* try below each window */
|
||||
tmp = below_sorted;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
MetaRectangle outer_rect;
|
||||
|
||||
meta_window_get_outer_rect (w, &outer_rect);
|
||||
|
||||
rect.x = outer_rect.x;
|
||||
rect.y = outer_rect.y + outer_rect.height;
|
||||
|
||||
if (rect_fits_in_work_area (&work_area, &rect) &&
|
||||
!rectangle_overlaps_some_window (&rect, below_sorted))
|
||||
{
|
||||
*new_x = rect.x;
|
||||
*new_y = rect.y;
|
||||
if (fgeom)
|
||||
{
|
||||
*new_x += fgeom->left_width;
|
||||
*new_y += fgeom->top_height;
|
||||
}
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
/* try to the right of each window */
|
||||
tmp = right_sorted;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
MetaRectangle outer_rect;
|
||||
|
||||
meta_window_get_outer_rect (w, &outer_rect);
|
||||
|
||||
rect.x = outer_rect.x + outer_rect.width;
|
||||
rect.y = outer_rect.y;
|
||||
|
||||
if (rect_fits_in_work_area (&work_area, &rect) &&
|
||||
!rectangle_overlaps_some_window (&rect, right_sorted))
|
||||
{
|
||||
*new_x = rect.x;
|
||||
*new_y = rect.y;
|
||||
if (fgeom)
|
||||
{
|
||||
*new_x += fgeom->left_width;
|
||||
*new_y += fgeom->top_height;
|
||||
}
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
out:
|
||||
g_list_free (sorted);
|
||||
|
||||
g_free (xineramas_list);
|
||||
g_list_free (below_sorted);
|
||||
g_list_free (right_sorted);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -975,7 +918,9 @@ get_vertical_edges (MetaWindow *window,
|
||||
windows = get_windows_on_same_workspace (window, &n_windows);
|
||||
|
||||
i = 0;
|
||||
n_edges = n_windows * 2 + 4 + window->screen->n_xinerama_infos - 1; /* 4 = workspace/screen edges */
|
||||
/* 4 = workspace/screen edges */
|
||||
n_edges = n_windows * 2 + 4 + window->screen->n_xinerama_infos - 1;
|
||||
|
||||
edges = g_new (int, n_edges);
|
||||
|
||||
/* workspace/screen edges */
|
||||
@ -1236,7 +1181,6 @@ meta_window_find_next_horizontal_edge (MetaWindow *window,
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
meta_window_find_nearest_vertical_edge (MetaWindow *window,
|
||||
int x_pos)
|
||||
|
132
src/screen.c
132
src/screen.c
@ -1346,6 +1346,138 @@ meta_screen_get_xinerama_for_window (MetaScreen *screen,
|
||||
return meta_screen_get_xinerama_for_rect (screen, &window_rect);
|
||||
}
|
||||
|
||||
const MetaXineramaScreenInfo*
|
||||
meta_screen_get_xinerama_neighbor (MetaScreen *screen,
|
||||
int which_xinerama,
|
||||
MetaScreenDirection direction)
|
||||
{
|
||||
MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
|
||||
MetaXineramaScreenInfo* current;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < screen->n_xinerama_infos; i++)
|
||||
{
|
||||
current = screen->xinerama_infos + i;
|
||||
|
||||
if (((direction == META_SCREEN_RIGHT) &&
|
||||
(current->x_origin == input->x_origin + input->width) &&
|
||||
(current->y_origin >= input->y_origin) &&
|
||||
(current->y_origin <= input->y_origin+input->height)) ||
|
||||
((direction == META_SCREEN_LEFT) &&
|
||||
(input->x_origin == current->x_origin + current->width) &&
|
||||
(current->y_origin >= input->y_origin) &&
|
||||
(current->y_origin <= input->y_origin + input->height)) ||
|
||||
((direction == META_SCREEN_UP) &&
|
||||
(input->y_origin == current->y_origin + current->height) &&
|
||||
(current->x_origin >= input->x_origin) &&
|
||||
(current->x_origin <= input->x_origin + input->width)) ||
|
||||
((direction == META_SCREEN_DOWN) &&
|
||||
(current->y_origin == input->y_origin + input->height) &&
|
||||
(current->x_origin >= input->x_origin) &&
|
||||
(current->x_origin <= input->x_origin + input->width)))
|
||||
{
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_get_natural_xinerama_list (MetaScreen *screen,
|
||||
int** xineramas_list,
|
||||
int* n_xineramas)
|
||||
{
|
||||
const MetaXineramaScreenInfo* current;
|
||||
const MetaXineramaScreenInfo* tmp;
|
||||
GQueue* xinerama_queue;
|
||||
int* visited;
|
||||
int cur = 0;
|
||||
int i;
|
||||
|
||||
*n_xineramas = screen->n_xinerama_infos;
|
||||
*xineramas_list = g_new (int, screen->n_xinerama_infos);
|
||||
|
||||
/* we calculate a natural ordering by which to choose xineramas for
|
||||
* window placement. We start at the current xinerama, and perform
|
||||
* a breadth-first search of the xineramas starting from that
|
||||
* xinerama. We choose preferentially left, then right, then down,
|
||||
* then up. The visitation order produced by this traversal is the
|
||||
* natural xinerama ordering.
|
||||
*/
|
||||
|
||||
visited = g_new (int, screen->n_xinerama_infos);
|
||||
for (i = 0; i < screen->n_xinerama_infos; i++)
|
||||
{
|
||||
visited[i] = FALSE;
|
||||
}
|
||||
|
||||
current = meta_screen_get_current_xinerama (screen);
|
||||
xinerama_queue = g_queue_new ();
|
||||
g_queue_push_tail (xinerama_queue, (gpointer) current);
|
||||
visited[current->number] = TRUE;
|
||||
|
||||
while (!g_queue_is_empty (xinerama_queue))
|
||||
{
|
||||
current = (const MetaXineramaScreenInfo*)
|
||||
g_queue_pop_head (xinerama_queue);
|
||||
|
||||
(*xineramas_list)[cur++] = current->number;
|
||||
|
||||
/* enqueue each of the directions */
|
||||
tmp = meta_screen_get_xinerama_neighbor (screen,
|
||||
current->number,
|
||||
META_SCREEN_LEFT);
|
||||
if (tmp && !visited[tmp->number])
|
||||
{
|
||||
g_queue_push_tail (xinerama_queue,
|
||||
(MetaXineramaScreenInfo*) tmp);
|
||||
visited[tmp->number] = TRUE;
|
||||
}
|
||||
tmp = meta_screen_get_xinerama_neighbor (screen,
|
||||
current->number,
|
||||
META_SCREEN_RIGHT);
|
||||
if (tmp && !visited[tmp->number])
|
||||
{
|
||||
g_queue_push_tail (xinerama_queue,
|
||||
(MetaXineramaScreenInfo*) tmp);
|
||||
visited[tmp->number] = TRUE;
|
||||
}
|
||||
tmp = meta_screen_get_xinerama_neighbor (screen,
|
||||
current->number,
|
||||
META_SCREEN_UP);
|
||||
if (tmp && !visited[tmp->number])
|
||||
{
|
||||
g_queue_push_tail (xinerama_queue,
|
||||
(MetaXineramaScreenInfo*) tmp);
|
||||
visited[tmp->number] = TRUE;
|
||||
}
|
||||
tmp = meta_screen_get_xinerama_neighbor (screen,
|
||||
current->number,
|
||||
META_SCREEN_DOWN);
|
||||
if (tmp && !visited[tmp->number])
|
||||
{
|
||||
g_queue_push_tail (xinerama_queue,
|
||||
(MetaXineramaScreenInfo*) tmp);
|
||||
visited[tmp->number] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* in case we somehow missed some set of xineramas, go through the
|
||||
* visited list and add in any xineramas that were missed
|
||||
*/
|
||||
for (i = 0; i < screen->n_xinerama_infos; i++)
|
||||
{
|
||||
if (visited[i] == FALSE)
|
||||
{
|
||||
(*xineramas_list)[cur++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (visited);
|
||||
g_queue_free (xinerama_queue);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_screen_window_intersects_xinerama (MetaScreen *screen,
|
||||
MetaWindow *window,
|
||||
|
20
src/screen.h
20
src/screen.h
@ -48,6 +48,14 @@ typedef enum
|
||||
META_SCREEN_BOTTOMRIGHT
|
||||
} MetaScreenCorner;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_SCREEN_UP,
|
||||
META_SCREEN_DOWN,
|
||||
META_SCREEN_LEFT,
|
||||
META_SCREEN_RIGHT
|
||||
} MetaScreenDirection;
|
||||
|
||||
struct _MetaScreen
|
||||
{
|
||||
MetaDisplay *display;
|
||||
@ -140,10 +148,16 @@ const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_rect (MetaScreen
|
||||
const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen *screen,
|
||||
MetaWindow *window);
|
||||
|
||||
gboolean meta_screen_window_intersects_xinerama (MetaScreen *screen,
|
||||
MetaWindow *window,
|
||||
int which_xinerama);
|
||||
|
||||
gboolean meta_screen_window_intersects_xinerama (MetaScreen *screen,
|
||||
MetaWindow *window,
|
||||
int which_xinerama);
|
||||
const MetaXineramaScreenInfo* meta_screen_get_xinerama_neighbor (MetaScreen *screen,
|
||||
int which_xinerama,
|
||||
MetaScreenDirection dir);
|
||||
void meta_screen_get_natural_xinerama_list (MetaScreen *screen,
|
||||
int** xineramas_list,
|
||||
int* n_xineramas);
|
||||
|
||||
void meta_screen_update_workspace_layout (MetaScreen *screen);
|
||||
void meta_screen_update_workspace_names (MetaScreen *screen);
|
||||
|
Loading…
Reference in New Issue
Block a user