]> Dogcows Code - chaz/openbox/blobdiff - openbox/place.c
LeastOverlap placement option (Fix bug 5385)
[chaz/openbox] / openbox / place.c
index efcec7ed75fe9389d5fc254cd9330cbc5d8f7144..579c56bdb607e4aeed032bef9fed38092860f473 100644 (file)
@@ -25,6 +25,7 @@
 #include "config.h"
 #include "dock.h"
 #include "debug.h"
 #include "config.h"
 #include "dock.h"
 #include "debug.h"
+#include "overlap.h"
 
 extern ObDock *dock;
 
 
 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:
 
    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
       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:
 
    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
     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
     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. */
 */
 
 /*! 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_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)
 };
 
 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->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;
     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->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;
     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. */
 }
 
 /*! 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;
 {
     Rect *area;
     ObPlaceHead *choice;
@@ -159,16 +172,18 @@ static Rect *pick_head(ObClient *c, gboolean foreground)
     }
 
     /* find monitors with group members */
     }
 
     /* find monitors with group members */
-    for (it = c->group->members; it; it = g_slist_next(it)) {
-        ObClient *itc = it->data;
-        if (itc != c) {
-            guint m = client_monitor(itc);
-
-            if (m < screen_num_monitors) {
-                if (screen_compare_desktops(itc->desktop, c->desktop))
-                    choice[m].flags |= HEAD_GROUP_DESK;
-                else
-                    choice[m].flags |= HEAD_GROUP;
+    if (c->group) {
+        for (it = c->group->members; it; it = g_slist_next(it)) {
+            ObClient *itc = it->data;
+            if (itc != c) {
+                guint m = client_monitor(itc);
+
+                if (m < screen_num_monitors) {
+                    if (screen_compare_desktops(itc->desktop, c->desktop))
+                        choice[m].flags |= HEAD_GROUP_DESK;
+                    else
+                        choice[m].flags |= HEAD_GROUP;
+                }
             }
         }
     }
             }
         }
     }
@@ -178,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;
         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 */
     }
 
     /* direct parent takes highest precedence */
@@ -438,27 +480,15 @@ static gboolean place_under_mouse(ObClient *client, gint *x, gint *y)
     return TRUE;
 }
 
     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)
 {
                                       ObAppSettings *settings)
 {
-    Rect *screen = NULL;
-
     if (!settings || (settings && !settings->pos_given))
         return FALSE;
 
     ob_debug("placing by per-app settings");
 
     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 == 0)
-        /* this can return NULL */
-        screen = pick_pointer_head(client);
-    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)
     if (settings->position.x.center)
         *x = screen->x + screen->width / 2 - client->area.width / 2;
     else if (settings->position.x.opposite)
@@ -479,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;
 
     if (settings->position.y.denom)
         *y = (*y * screen->height) / settings->position.y.denom;
 
-    g_slice_free(Rect, screen);
     return TRUE;
 }
 
     return TRUE;
 }
 
@@ -530,6 +559,56 @@ static gboolean place_transient_splash(ObClient *client, Rect *area,
     return FALSE;
 }
 
     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,
 /*! 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,
@@ -546,13 +625,15 @@ gboolean place_client(ObClient *client, gboolean foreground, gint *x, gint *y,
          !(settings && settings->pos_given)))
         return FALSE;
 
          !(settings && settings->pos_given)))
         return FALSE;
 
-    area = pick_head(client, foreground);
+    area = pick_head(client, foreground, settings);
 
     /* try a number of methods */
 
     /* 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) ||
         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);
         place_nooverlap(client, area, x, y) ||
         place_random(client, area, x, y);
     g_assert(ret);
This page took 0.027831 seconds and 4 git commands to generate.