mirror of
https://github.com/brl/mutter.git
synced 2024-12-26 04:42:14 +00:00
compositor: Mirror window placement in RTL environment
If RTL environment (such as Hebrew or Arabic) is detected, the usual new window placement algorithm is mirrored. New windows appear near the right side of the screen and cascading is built from the top-right corner of the screen. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1873 Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3009>
This commit is contained in:
parent
985d0dc3ab
commit
993c42e11f
126
src/core/place.c
126
src/core/place.c
@ -45,7 +45,8 @@ typedef enum
|
|||||||
} MetaWindowDirection;
|
} MetaWindowDirection;
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
northwestcmp (gconstpointer a, gconstpointer b)
|
northwest_cmp (gconstpointer a,
|
||||||
|
gconstpointer b)
|
||||||
{
|
{
|
||||||
MetaWindow *aw = (gpointer) a;
|
MetaWindow *aw = (gpointer) a;
|
||||||
MetaWindow *bw = (gpointer) b;
|
MetaWindow *bw = (gpointer) b;
|
||||||
@ -74,6 +75,39 @@ northwestcmp (gconstpointer a, gconstpointer b)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
northeast_cmp (gconstpointer a,
|
||||||
|
gconstpointer b,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MetaWindow *aw = (gpointer) a;
|
||||||
|
MetaWindow *bw = (gpointer) b;
|
||||||
|
MetaRectangle *area = user_data;
|
||||||
|
MetaRectangle a_frame;
|
||||||
|
MetaRectangle b_frame;
|
||||||
|
int from_origin_a;
|
||||||
|
int from_origin_b;
|
||||||
|
int ax, ay, bx, by;
|
||||||
|
|
||||||
|
meta_window_get_frame_rect (aw, &a_frame);
|
||||||
|
meta_window_get_frame_rect (bw, &b_frame);
|
||||||
|
ax = (area->x + area->width) - (a_frame.x + a_frame.width);
|
||||||
|
ay = a_frame.y;
|
||||||
|
bx = (area->x + area->width) - (b_frame.x + b_frame.width);
|
||||||
|
by = b_frame.y;
|
||||||
|
|
||||||
|
/* probably there's a fast good-enough-guess we could use here. */
|
||||||
|
from_origin_a = sqrt (ax * ax + ay * ay);
|
||||||
|
from_origin_b = sqrt (bx * bx + by * by);
|
||||||
|
|
||||||
|
if (from_origin_a < from_origin_b)
|
||||||
|
return -1;
|
||||||
|
else if (from_origin_a > from_origin_b)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
find_next_cascade (MetaWindow *window,
|
find_next_cascade (MetaWindow *window,
|
||||||
/* visible windows on relevant workspaces */
|
/* visible windows on relevant workspaces */
|
||||||
@ -88,7 +122,7 @@ find_next_cascade (MetaWindow *window,
|
|||||||
MetaBackend *backend = meta_context_get_backend (context);
|
MetaBackend *backend = meta_context_get_backend (context);
|
||||||
GList *tmp;
|
GList *tmp;
|
||||||
GList *sorted;
|
GList *sorted;
|
||||||
int cascade_x, cascade_y;
|
int cascade_origin_x, cascade_x, cascade_y;
|
||||||
MetaRectangle titlebar_rect;
|
MetaRectangle titlebar_rect;
|
||||||
int x_threshold, y_threshold;
|
int x_threshold, y_threshold;
|
||||||
MetaRectangle frame_rect;
|
MetaRectangle frame_rect;
|
||||||
@ -96,9 +130,7 @@ find_next_cascade (MetaWindow *window,
|
|||||||
int cascade_stage;
|
int cascade_stage;
|
||||||
MetaRectangle work_area;
|
MetaRectangle work_area;
|
||||||
MetaLogicalMonitor *current;
|
MetaLogicalMonitor *current;
|
||||||
|
gboolean ltr = meta_get_locale_direction () == META_LOCALE_DIRECTION_LTR;
|
||||||
sorted = g_list_copy (windows);
|
|
||||||
sorted = g_list_sort (sorted, northwestcmp);
|
|
||||||
|
|
||||||
/* This is a "fuzzy" cascade algorithm.
|
/* This is a "fuzzy" cascade algorithm.
|
||||||
* For each window in the list, we find where we'd cascade a
|
* For each window in the list, we find where we'd cascade a
|
||||||
@ -122,57 +154,81 @@ find_next_cascade (MetaWindow *window,
|
|||||||
current = meta_backend_get_current_logical_monitor (backend);
|
current = meta_backend_get_current_logical_monitor (backend);
|
||||||
meta_window_get_work_area_for_logical_monitor (window, current, &work_area);
|
meta_window_get_work_area_for_logical_monitor (window, current, &work_area);
|
||||||
|
|
||||||
cascade_x = MAX (0, work_area.x);
|
sorted = g_list_copy (windows);
|
||||||
cascade_y = MAX (0, work_area.y);
|
if (ltr)
|
||||||
|
sorted = g_list_sort (sorted, northwest_cmp);
|
||||||
/* Find first cascade position that's not used. */
|
else
|
||||||
|
sorted = g_list_sort_with_data (sorted, northeast_cmp, &work_area);
|
||||||
|
|
||||||
meta_window_get_frame_rect (window, &frame_rect);
|
meta_window_get_frame_rect (window, &frame_rect);
|
||||||
window_width = frame_rect.width;
|
window_width = frame_rect.width;
|
||||||
window_height = frame_rect.height;
|
window_height = frame_rect.height;
|
||||||
|
|
||||||
|
cascade_origin_x = ltr
|
||||||
|
? MAX (0, work_area.x)
|
||||||
|
: work_area.x + work_area.width - window_width;
|
||||||
|
cascade_x = cascade_origin_x;
|
||||||
|
cascade_y = MAX (0, work_area.y);
|
||||||
|
|
||||||
|
/* Find first cascade position that's not used. */
|
||||||
|
|
||||||
cascade_stage = 0;
|
cascade_stage = 0;
|
||||||
tmp = sorted;
|
tmp = sorted;
|
||||||
while (tmp != NULL)
|
while (tmp != NULL)
|
||||||
{
|
{
|
||||||
MetaWindow *w;
|
MetaWindow *w;
|
||||||
MetaRectangle w_frame_rect;
|
MetaRectangle w_frame_rect;
|
||||||
int wx, wy;
|
int wx, ww, wy;
|
||||||
|
gboolean nearby;
|
||||||
|
|
||||||
w = tmp->data;
|
w = tmp->data;
|
||||||
|
|
||||||
/* we want frame position, not window position */
|
/* we want frame position, not window position */
|
||||||
meta_window_get_frame_rect (w, &w_frame_rect);
|
meta_window_get_frame_rect (w, &w_frame_rect);
|
||||||
wx = w_frame_rect.x;
|
wx = w_frame_rect.x;
|
||||||
|
ww = w_frame_rect.width;
|
||||||
wy = w_frame_rect.y;
|
wy = w_frame_rect.y;
|
||||||
|
|
||||||
if (ABS (wx - cascade_x) < x_threshold &&
|
if (ltr)
|
||||||
ABS (wy - cascade_y) < y_threshold)
|
nearby = ABS (wx - cascade_x) < x_threshold &&
|
||||||
|
ABS (wy - cascade_y) < y_threshold;
|
||||||
|
else
|
||||||
|
nearby = ABS ((wx + ww) - (cascade_x + window_width)) < x_threshold &&
|
||||||
|
ABS (wy - cascade_y) < y_threshold;
|
||||||
|
|
||||||
|
if (nearby)
|
||||||
{
|
{
|
||||||
meta_window_get_titlebar_rect (w, &titlebar_rect);
|
meta_window_get_titlebar_rect (w, &titlebar_rect);
|
||||||
|
|
||||||
/* Cascade the window evenly by the titlebar height; this isn't a typo. */
|
/* Cascade the window evenly by the titlebar height; this isn't a typo. */
|
||||||
cascade_x = wx + titlebar_rect.height;
|
cascade_x = ltr
|
||||||
|
? wx + titlebar_rect.height
|
||||||
|
: wx + ww - titlebar_rect.height - window_width;
|
||||||
cascade_y = wy + titlebar_rect.height;
|
cascade_y = wy + titlebar_rect.height;
|
||||||
|
|
||||||
/* If we go off the screen, start over with a new cascade */
|
/* If we go off the screen, start over with a new cascade */
|
||||||
if (((cascade_x + window_width) >
|
if (((cascade_x + window_width) >
|
||||||
(work_area.x + work_area.width)) ||
|
(work_area.x + work_area.width)) ||
|
||||||
|
(cascade_x < work_area.x) ||
|
||||||
((cascade_y + window_height) >
|
((cascade_y + window_height) >
|
||||||
(work_area.y + work_area.height)))
|
(work_area.y + work_area.height)))
|
||||||
{
|
{
|
||||||
cascade_x = MAX (0, work_area.x);
|
cascade_x = cascade_origin_x;
|
||||||
cascade_y = MAX (0, work_area.y);
|
cascade_y = MAX (0, work_area.y);
|
||||||
|
|
||||||
#define CASCADE_INTERVAL 50 /* space between top-left corners of cascades */
|
#define CASCADE_INTERVAL 50 /* space between top-left corners of cascades */
|
||||||
cascade_stage += 1;
|
cascade_stage += 1;
|
||||||
|
if (ltr)
|
||||||
cascade_x += CASCADE_INTERVAL * cascade_stage;
|
cascade_x += CASCADE_INTERVAL * cascade_stage;
|
||||||
|
else
|
||||||
|
cascade_x -= CASCADE_INTERVAL * cascade_stage;
|
||||||
|
|
||||||
/* start over with a new cascade translated to the right, unless
|
/* start over with a new cascade translated to the right
|
||||||
* we are out of space
|
* (or to the left in RTL environment), unless we are out of space
|
||||||
*/
|
*/
|
||||||
if ((cascade_x + window_width) <
|
if (((cascade_x + window_width) <
|
||||||
(work_area.x + work_area.width))
|
(work_area.x + work_area.width)) &&
|
||||||
|
(cascade_x >= work_area.x))
|
||||||
{
|
{
|
||||||
tmp = sorted;
|
tmp = sorted;
|
||||||
continue;
|
continue;
|
||||||
@ -180,7 +236,7 @@ find_next_cascade (MetaWindow *window,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* All out of space, this cascade_x won't work */
|
/* All out of space, this cascade_x won't work */
|
||||||
cascade_x = MAX (0, work_area.x);
|
cascade_x = cascade_origin_x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,6 +491,13 @@ leftmost_cmp (gconstpointer a, gconstpointer b)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
rightmost_cmp (gconstpointer a,
|
||||||
|
gconstpointer b)
|
||||||
|
{
|
||||||
|
return -leftmost_cmp (a, b);
|
||||||
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
topmost_cmp (gconstpointer a, gconstpointer b)
|
topmost_cmp (gconstpointer a, gconstpointer b)
|
||||||
{
|
{
|
||||||
@ -470,7 +533,10 @@ center_tile_rect_in_area (MetaRectangle *rect,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
fluff = (work_area->width % (rect->width + 1)) / 2;
|
fluff = (work_area->width % (rect->width + 1)) / 2;
|
||||||
|
if (meta_get_locale_direction () == META_LOCALE_DIRECTION_LTR)
|
||||||
rect->x = work_area->x + fluff;
|
rect->x = work_area->x + fluff;
|
||||||
|
else
|
||||||
|
rect->x = work_area->x + work_area->width - rect->width - fluff;
|
||||||
fluff = (work_area->height % (rect->height + 1)) / 3;
|
fluff = (work_area->height % (rect->height + 1)) / 3;
|
||||||
rect->y = work_area->y + fluff;
|
rect->y = work_area->y + fluff;
|
||||||
}
|
}
|
||||||
@ -502,22 +568,23 @@ find_first_fit (MetaWindow *window,
|
|||||||
*/
|
*/
|
||||||
int retval;
|
int retval;
|
||||||
GList *below_sorted;
|
GList *below_sorted;
|
||||||
GList *right_sorted;
|
GList *end_sorted;
|
||||||
GList *tmp;
|
GList *tmp;
|
||||||
MetaRectangle rect;
|
MetaRectangle rect;
|
||||||
MetaRectangle work_area;
|
MetaRectangle work_area;
|
||||||
|
gboolean ltr = meta_get_locale_direction () == META_LOCALE_DIRECTION_LTR;
|
||||||
|
|
||||||
retval = FALSE;
|
retval = FALSE;
|
||||||
|
|
||||||
/* Below each window */
|
/* Below each window */
|
||||||
below_sorted = g_list_copy (windows);
|
below_sorted = g_list_copy (windows);
|
||||||
below_sorted = g_list_sort (below_sorted, leftmost_cmp);
|
below_sorted = g_list_sort (below_sorted, ltr ? leftmost_cmp : rightmost_cmp);
|
||||||
below_sorted = g_list_sort (below_sorted, topmost_cmp);
|
below_sorted = g_list_sort (below_sorted, topmost_cmp);
|
||||||
|
|
||||||
/* To the right of each window */
|
/* To the right of each window */
|
||||||
right_sorted = g_list_copy (windows);
|
end_sorted = g_list_copy (windows);
|
||||||
right_sorted = g_list_sort (right_sorted, topmost_cmp);
|
end_sorted = g_list_sort (end_sorted, topmost_cmp);
|
||||||
right_sorted = g_list_sort (right_sorted, leftmost_cmp);
|
end_sorted = g_list_sort (end_sorted, ltr ? leftmost_cmp : rightmost_cmp);
|
||||||
|
|
||||||
meta_window_get_frame_rect (window, &rect);
|
meta_window_get_frame_rect (window, &rect);
|
||||||
|
|
||||||
@ -576,8 +643,8 @@ find_first_fit (MetaWindow *window,
|
|||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to the right of each window */
|
/* try to the right (or left in RTL environment) of each window */
|
||||||
tmp = right_sorted;
|
tmp = end_sorted;
|
||||||
while (tmp != NULL)
|
while (tmp != NULL)
|
||||||
{
|
{
|
||||||
MetaWindow *w = tmp->data;
|
MetaWindow *w = tmp->data;
|
||||||
@ -585,11 +652,14 @@ find_first_fit (MetaWindow *window,
|
|||||||
|
|
||||||
meta_window_get_frame_rect (w, &frame_rect);
|
meta_window_get_frame_rect (w, &frame_rect);
|
||||||
|
|
||||||
|
if (ltr)
|
||||||
rect.x = frame_rect.x + frame_rect.width;
|
rect.x = frame_rect.x + frame_rect.width;
|
||||||
|
else
|
||||||
|
rect.x = frame_rect.x - rect.width;
|
||||||
rect.y = frame_rect.y;
|
rect.y = frame_rect.y;
|
||||||
|
|
||||||
if (meta_rectangle_contains_rect (&work_area, &rect) &&
|
if (meta_rectangle_contains_rect (&work_area, &rect) &&
|
||||||
!rectangle_overlaps_some_window (&rect, right_sorted))
|
!rectangle_overlaps_some_window (&rect, end_sorted))
|
||||||
{
|
{
|
||||||
*new_x = rect.x;
|
*new_x = rect.x;
|
||||||
*new_y = rect.y;
|
*new_y = rect.y;
|
||||||
@ -604,7 +674,7 @@ find_first_fit (MetaWindow *window,
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
g_list_free (below_sorted);
|
g_list_free (below_sorted);
|
||||||
g_list_free (right_sorted);
|
g_list_free (end_sorted);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user