diff --git a/src/core/place.c b/src/core/place.c index f9877dfc7..52f0915a8 100644 --- a/src/core/place.c +++ b/src/core/place.c @@ -45,7 +45,8 @@ typedef enum } MetaWindowDirection; static gint -northwestcmp (gconstpointer a, gconstpointer b) +northwest_cmp (gconstpointer a, + gconstpointer b) { MetaWindow *aw = (gpointer) a; MetaWindow *bw = (gpointer) b; @@ -74,6 +75,39 @@ northwestcmp (gconstpointer a, gconstpointer b) 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 find_next_cascade (MetaWindow *window, /* visible windows on relevant workspaces */ @@ -88,7 +122,7 @@ find_next_cascade (MetaWindow *window, MetaBackend *backend = meta_context_get_backend (context); GList *tmp; GList *sorted; - int cascade_x, cascade_y; + int cascade_origin_x, cascade_x, cascade_y; MetaRectangle titlebar_rect; int x_threshold, y_threshold; MetaRectangle frame_rect; @@ -96,9 +130,7 @@ find_next_cascade (MetaWindow *window, int cascade_stage; MetaRectangle work_area; MetaLogicalMonitor *current; - - sorted = g_list_copy (windows); - sorted = g_list_sort (sorted, northwestcmp); + gboolean ltr = meta_get_locale_direction () == META_LOCALE_DIRECTION_LTR; /* This is a "fuzzy" cascade algorithm. * 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); meta_window_get_work_area_for_logical_monitor (window, current, &work_area); - cascade_x = MAX (0, work_area.x); - cascade_y = MAX (0, work_area.y); - - /* Find first cascade position that's not used. */ + sorted = g_list_copy (windows); + if (ltr) + sorted = g_list_sort (sorted, northwest_cmp); + else + sorted = g_list_sort_with_data (sorted, northeast_cmp, &work_area); meta_window_get_frame_rect (window, &frame_rect); window_width = frame_rect.width; 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; tmp = sorted; while (tmp != NULL) { MetaWindow *w; MetaRectangle w_frame_rect; - int wx, wy; + int wx, ww, wy; + gboolean nearby; w = tmp->data; /* we want frame position, not window position */ meta_window_get_frame_rect (w, &w_frame_rect); wx = w_frame_rect.x; + ww = w_frame_rect.width; wy = w_frame_rect.y; - if (ABS (wx - cascade_x) < x_threshold && - ABS (wy - cascade_y) < y_threshold) + if (ltr) + 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); /* 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; /* 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)) || + (cascade_x < work_area.x) || ((cascade_y + window_height) > - (work_area.y + work_area.height))) - { - cascade_x = MAX (0, work_area.x); - cascade_y = MAX (0, work_area.y); + (work_area.y + work_area.height))) + { + cascade_x = cascade_origin_x; + cascade_y = MAX (0, work_area.y); #define CASCADE_INTERVAL 50 /* space between top-left corners of cascades */ cascade_stage += 1; - cascade_x += CASCADE_INTERVAL * cascade_stage; + if (ltr) + cascade_x += CASCADE_INTERVAL * cascade_stage; + else + cascade_x -= CASCADE_INTERVAL * cascade_stage; - /* start over with a new cascade translated to the right, unless - * we are out of space + /* start over with a new cascade translated to the right + * (or to the left in RTL environment), unless we are out of space */ - if ((cascade_x + window_width) < - (work_area.x + work_area.width)) + if (((cascade_x + window_width) < + (work_area.x + work_area.width)) && + (cascade_x >= work_area.x)) { tmp = sorted; continue; @@ -180,10 +236,10 @@ find_next_cascade (MetaWindow *window, else { /* All out of space, this cascade_x won't work */ - cascade_x = MAX (0, work_area.x); + cascade_x = cascade_origin_x; break; } - } + } } else { @@ -435,6 +491,13 @@ leftmost_cmp (gconstpointer a, gconstpointer b) return 0; } +static gint +rightmost_cmp (gconstpointer a, + gconstpointer b) +{ + return -leftmost_cmp (a, b); +} + static gint topmost_cmp (gconstpointer a, gconstpointer b) { @@ -469,9 +532,12 @@ center_tile_rect_in_area (MetaRectangle *rect, * as a group) */ - fluff = (work_area->width % (rect->width+1)) / 2; - rect->x = work_area->x + fluff; - fluff = (work_area->height % (rect->height+1)) / 3; + fluff = (work_area->width % (rect->width + 1)) / 2; + if (meta_get_locale_direction () == META_LOCALE_DIRECTION_LTR) + 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; rect->y = work_area->y + fluff; } @@ -502,22 +568,23 @@ find_first_fit (MetaWindow *window, */ int retval; GList *below_sorted; - GList *right_sorted; + GList *end_sorted; GList *tmp; MetaRectangle rect; MetaRectangle work_area; + gboolean ltr = meta_get_locale_direction () == META_LOCALE_DIRECTION_LTR; retval = FALSE; /* 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, ltr ? leftmost_cmp : rightmost_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); + end_sorted = g_list_copy (windows); + end_sorted = g_list_sort (end_sorted, topmost_cmp); + end_sorted = g_list_sort (end_sorted, ltr ? leftmost_cmp : rightmost_cmp); meta_window_get_frame_rect (window, &rect); @@ -576,8 +643,8 @@ find_first_fit (MetaWindow *window, tmp = tmp->next; } - /* try to the right of each window */ - tmp = right_sorted; + /* try to the right (or left in RTL environment) of each window */ + tmp = end_sorted; while (tmp != NULL) { MetaWindow *w = tmp->data; @@ -585,11 +652,14 @@ find_first_fit (MetaWindow *window, meta_window_get_frame_rect (w, &frame_rect); - rect.x = frame_rect.x + frame_rect.width; + if (ltr) + rect.x = frame_rect.x + frame_rect.width; + else + rect.x = frame_rect.x - rect.width; rect.y = frame_rect.y; 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_y = rect.y; @@ -602,9 +672,9 @@ find_first_fit (MetaWindow *window, tmp = tmp->next; } - out: +out: g_list_free (below_sorted); - g_list_free (right_sorted); + g_list_free (end_sorted); return retval; }