X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fplace.c;h=579c56bdb607e4aeed032bef9fed38092860f473;hb=4d2ccf19168a4089a6a0de0109610479ec6d5507;hp=8a4a42649b0569110c7b343892faccef2c98fd39;hpb=c590a83207ed5825b513e2278789ed13f55574b2;p=chaz%2Fopenbox diff --git a/openbox/place.c b/openbox/place.c index 8a4a4264..579c56bd 100644 --- a/openbox/place.c +++ b/openbox/place.c @@ -25,6 +25,7 @@ #include "config.h" #include "dock.h" #include "debug.h" +#include "overlap.h" extern ObDock *dock; @@ -37,27 +38,29 @@ static Rect *pick_pointer_head(ObClient *c) When a window is being placed in the FOREGROUND, use a monitor chosen in the following order: - 1. same monitor as parent - 2. primary monitor if placement=PRIMARY + 1. per-app settings + 2. same monitor as parent + 3. primary monitor if placement=PRIMARY active monitor if placement=ACTIVE pointer monitor if placement=MOUSE - 3. primary monitor - 4. other monitors where the window has group members on the same desktop - 5. other monitors where the window has group members on other desktops - 6. other monitors + 4. primary monitor + 5. other monitors where the window has group members on the same desktop + 6. other monitors where the window has group members on other desktops + 7. other monitors When a window is being placed in the BACKGROUND, use a monitor chosen in the following order: - 1. same monitor as parent - 2. other monitors where the window has group members on the same desktop - 2a. primary monitor in this set - 2b. other monitors in this set - 3. other monitors where the window has group members on other desktops + 1. per-app settings + 2. same monitor as parent + 3. other monitors where the window has group members on the same desktop 3a. primary monitor in this set 3b. other monitors in this set - 4. other monitors + 4. other monitors where the window has group members on other desktops 4a. primary monitor in this set 4b. other monitors in this set + 5. other monitors + 5a. primary monitor in this set + 5b. other monitors in this set */ /*! One for each possible head, used to sort them in order of precedence. */ @@ -73,6 +76,7 @@ enum { HEAD_PRIMARY = 1 << 2, /* primary monitor */ HEAD_GROUP_DESK = 1 << 3, /* has a group member on the same desktop */ HEAD_GROUP = 1 << 4, /* has a group member on another desktop */ + HEAD_PERAPP = 1 << 5, /* chosen by per-app settings */ }; gint cmp_foreground(const void *a, const void *b) @@ -83,6 +87,10 @@ gint cmp_foreground(const void *a, const void *b) if (h1->monitor == h2->monitor) return 0; + if (h1->flags & HEAD_PERAPP) --i; + if (h2->flags & HEAD_PERAPP) ++i; + if (i) return i; + if (h1->flags & HEAD_PARENT) --i; if (h2->flags & HEAD_PARENT) ++i; if (i) return i; @@ -114,6 +122,10 @@ gint cmp_background(const void *a, const void *b) if (h1->monitor == h2->monitor) return 0; + if (h1->flags & HEAD_PERAPP) --i; + if (h2->flags & HEAD_PERAPP) ++i; + if (i) return i; + if (h1->flags & HEAD_PARENT) --i; if (h2->flags & HEAD_PARENT) ++i; if (i) return i; @@ -144,7 +156,8 @@ gint cmp_background(const void *a, const void *b) } /*! Pick a monitor to place a window on. */ -static Rect *pick_head(ObClient *c, gboolean foreground) +static Rect *pick_head(ObClient *c, gboolean foreground, + ObAppSettings *settings) { Rect *area; ObPlaceHead *choice; @@ -180,6 +193,33 @@ static Rect *pick_head(ObClient *c, gboolean foreground) choice[i].flags |= HEAD_PRIMARY; if (config_place_monitor == OB_PLACE_MONITOR_PRIMARY) choice[i].flags |= HEAD_PLACED; + if (settings && + settings->monitor_type == OB_PLACE_MONITOR_PRIMARY) + choice[i].flags |= HEAD_PERAPP; + } + + i = screen_monitor_active(); + if (i < screen_num_monitors) { + if (config_place_monitor == OB_PLACE_MONITOR_ACTIVE) + choice[i].flags |= HEAD_PLACED; + if (settings && + settings->monitor_type == OB_PLACE_MONITOR_ACTIVE) + choice[i].flags |= HEAD_PERAPP; + } + + i = screen_monitor_pointer(); + if (i < screen_num_monitors) { + if (config_place_monitor == OB_PLACE_MONITOR_MOUSE) + choice[i].flags |= HEAD_PLACED; + if (settings && + settings->monitor_type == OB_PLACE_MONITOR_MOUSE) + choice[i].flags |= HEAD_PERAPP; + } + + if (settings) { + i = settings->monitor - 1; + if (i < screen_num_monitors) + choice[i].flags |= HEAD_PERAPP; } /* direct parent takes highest precedence */ @@ -440,36 +480,15 @@ static gboolean place_under_mouse(ObClient *client, gint *x, gint *y) return TRUE; } -static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y, +static gboolean place_per_app_setting(ObClient *client, Rect *screen, + gint *x, gint *y, ObAppSettings *settings) { - Rect *screen = NULL; - if (!settings || (settings && !settings->pos_given)) return FALSE; ob_debug("placing by per-app settings"); - /* Find which head the pointer is on */ - if (settings->monitor_type == OB_APP_SETTINGS_MONITOR_PRIMARY) { - guint m = screen_monitor_primary(TRUE); - screen = screen_area(client->desktop, m, NULL); - } - else if (settings->monitor_type == OB_APP_SETTINGS_MONITOR_ACTIVE) { - guint m = screen_monitor_active(); - screen = screen_area(client->desktop, m, NULL); - } - else if (settings->monitor_type == OB_APP_SETTINGS_MONITOR_MOUSE) { - screen = pick_pointer_head(client); - g_assert(screen); - } - else { - guint m = settings->monitor; - if (m < 1 || m > screen_num_monitors) - m = screen_monitor_primary(TRUE) + 1; - screen = screen_area(client->desktop, m - 1, NULL); - } - if (settings->position.x.center) *x = screen->x + screen->width / 2 - client->area.width / 2; else if (settings->position.x.opposite) @@ -490,7 +509,6 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y, if (settings->position.y.denom) *y = (*y * screen->height) / settings->position.y.denom; - g_slice_free(Rect, screen); return TRUE; } @@ -541,6 +559,56 @@ static gboolean place_transient_splash(ObClient *client, Rect *area, return FALSE; } +static gboolean place_least_overlap(ObClient *c, gint *x, gint *y, Rect * const head) +{ + /* assemble the list of "interesting" windows to calculate overlap against */ + GSList* interesting_clients = NULL; + int n_client_rects = 0; + + /* if we're "showing desktop", ignore all existing windows */ + if (!screen_showing_desktop) { + GList* it; + for (it = client_list; it != NULL; it = g_list_next(it)) { + ObClient* maybe_client = (ObClient*) it->data; + if (maybe_client == c) + continue; + if (maybe_client->iconic) + continue; + if (c->desktop != DESKTOP_ALL) { + if (maybe_client->desktop != c->desktop && + maybe_client->desktop != DESKTOP_ALL) continue; + } else { + if (maybe_client->desktop != screen_desktop && + maybe_client->desktop != DESKTOP_ALL) continue; + } + if (maybe_client->type == OB_CLIENT_TYPE_SPLASH || + maybe_client->type == OB_CLIENT_TYPE_DESKTOP) continue; + /* it is interesting, so add it */ + interesting_clients = g_slist_prepend(interesting_clients, maybe_client); + n_client_rects += 1; + } + } + Rect client_rects[n_client_rects]; + GSList* it; + unsigned int i = 0; + for (it = interesting_clients; it != NULL; it = g_slist_next(it)) { + ObClient* interesting_client = (ObClient*) it->data; + client_rects[i] = interesting_client->frame->area; + i += 1; + } + g_slist_free(interesting_clients); + + Point result; + Size req_size; + SIZE_SET(req_size, c->frame->area.width, c->frame->area.height); + overlap_find_least_placement(client_rects, n_client_rects, head, + &req_size, &result); + *x = result.x; + *y = result.y; + + return TRUE; +} + /*! Return TRUE if openbox chose the position for the window, and FALSE if the application chose it */ gboolean place_client(ObClient *client, gboolean foreground, gint *x, gint *y, @@ -557,13 +625,15 @@ gboolean place_client(ObClient *client, gboolean foreground, gint *x, gint *y, !(settings && settings->pos_given))) return FALSE; - area = pick_head(client, foreground); + area = pick_head(client, foreground, settings); /* try a number of methods */ - ret = place_per_app_setting(client, x, y, settings) || + ret = place_per_app_setting(client, area, x, y, settings) || place_transient_splash(client, area, x, y) || - (config_place_policy == OB_PLACE_POLICY_MOUSE && - place_under_mouse(client, x, y)) || + (config_place_policy == OB_PLACE_POLICY_MOUSE + && place_under_mouse (client, x, y)) || + (config_place_policy == OB_PLACE_POLICY_LEASTOVERLAP + && place_least_overlap(client, x, y, area)) || place_nooverlap(client, area, x, y) || place_random(client, area, x, y); g_assert(ret);