From dc4cfa94c9cd7bd30cdc87a6e4ab8174d8a9703f Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sun, 30 Sep 2012 21:12:07 -0400 Subject: Make LeastOverlap placment replace the behaviour of Smart and address style nits --- Makefile.am | 4 +- data/rc.xsd | 1 - openbox/client.c | 6 ++ openbox/client.h | 4 + openbox/config.c | 6 +- openbox/overlap.c | 175 ---------------------------------- openbox/overlap.h | 24 ----- openbox/place.c | 245 +++++------------------------------------------- openbox/place.h | 3 +- openbox/place_overlap.c | 175 ++++++++++++++++++++++++++++++++++ openbox/place_overlap.h | 25 +++++ 11 files changed, 239 insertions(+), 429 deletions(-) delete mode 100644 openbox/overlap.c delete mode 100644 openbox/overlap.h create mode 100644 openbox/place_overlap.c create mode 100644 openbox/place_overlap.h diff --git a/Makefile.am b/Makefile.am index 37059ae5..f32591f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -282,12 +282,12 @@ openbox_openbox_SOURCES = \ openbox/mwm.h \ openbox/openbox.c \ openbox/openbox.h \ - openbox/overlap.c \ - openbox/overlap.h \ openbox/ping.c \ openbox/ping.h \ openbox/place.c \ openbox/place.h \ + openbox/place_overlap.c \ + openbox/place_overlap.h \ openbox/prompt.c \ openbox/prompt.h \ openbox/popup.c \ diff --git a/data/rc.xsd b/data/rc.xsd index 07357ad5..ad96994a 100644 --- a/data/rc.xsd +++ b/data/rc.xsd @@ -511,7 +511,6 @@ - diff --git a/openbox/client.c b/openbox/client.c index 07db26bf..c54b21fb 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -2774,6 +2774,12 @@ gboolean client_helper(ObClient *self) self->type == OB_CLIENT_TYPE_TOOLBAR); } +gboolean client_occupies_space(ObClient *self) +{ + return !(self->type == OB_CLIENT_TYPE_DESKTOP || + self->type == OB_CLIENT_TYPE_SPLASH); +} + gboolean client_mouse_focusable(ObClient *self) { return !(self->type == OB_CLIENT_TYPE_MENU || diff --git a/openbox/client.h b/openbox/client.h index 18c88ec1..5a20822f 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -363,6 +363,10 @@ gboolean client_normal(ObClient *self); (utilty, menu, etc) */ gboolean client_helper(ObClient *self); +/*! Returns true if the window occupies space in the monitor conceptually, or + false if it does not and its presence should be ignored when possible. */ +gboolean client_occupies_space(ObClient *self); + /*! Return if the client is a type which should be given focus from mouse presses on the *client* window. This doesn't affect clicking on the decorations. This doesn't count for focus cycling, different rules apply to diff --git a/openbox/config.c b/openbox/config.c index 1a3e6ddf..0d9eb689 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -581,13 +581,9 @@ static void parse_placement(xmlNodePtr node, gpointer d) node = node->children; - if ((n = obt_xml_find_node(node, "policy"))) { + if ((n = obt_xml_find_node(node, "policy"))) if (obt_xml_node_contains(n, "UnderMouse")) config_place_policy = OB_PLACE_POLICY_MOUSE; - else if (obt_xml_node_contains(n, "LeastOverlap")) - config_place_policy = OB_PLACE_POLICY_LEASTOVERLAP; - - } if ((n = obt_xml_find_node(node, "center"))) config_place_center = obt_xml_node_bool(n); if ((n = obt_xml_find_node(node, "monitor"))) { diff --git a/openbox/overlap.c b/openbox/overlap.c deleted file mode 100644 index abc600e4..00000000 --- a/openbox/overlap.c +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- - - overlap.c for the Openbox window manager - Copyright (c) 2011 Ian Zimmerman - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - See the COPYING file for a copy of the GNU General Public License. -*/ - -#include "config.h" -#include "geom.h" -#include "overlap.h" - -#include - -static void -make_grid(const Rect* client_rects, int n_client_rects, const Rect* bound, - int* x_edges, int* y_edges, int max_edges); - -static int -best_direction(const Point* grid_point, - const Rect* client_rects, int n_client_rects, - const Rect* bound, const Size* req_size, Point* best_top_left); - -/* Choose the placement on a grid with least overlap */ - -void -overlap_find_least_placement(const Rect* client_rects, int n_client_rects, - Rect *const bound, - const Size* req_size, Point* result) -{ - result->x = result->y = 0; - int overlap = G_MAXINT; - int max_edges = 2 * (n_client_rects + 1); - - int x_edges[max_edges]; - int y_edges[max_edges]; - make_grid(client_rects, n_client_rects, bound, - x_edges, y_edges, max_edges); - int i; - for (i = 0; i < max_edges; ++i) { - if (x_edges[i] == G_MAXINT) - break; - int j; - for (j = 0; j < max_edges; ++j) { - if (y_edges[j] == G_MAXINT) - break; - Point grid_point = {.x = x_edges[i], .y = y_edges[j]}; - Point best_top_left; - int this_overlap = - best_direction(&grid_point, client_rects, n_client_rects, - bound, req_size, &best_top_left); - if (this_overlap < overlap) { - overlap = this_overlap; - *result = best_top_left; - } - if (overlap == 0) - break; - } - if (overlap == 0) - break; - } -} - -static int compare_ints(const void* a, const void* b) -{ - const int* ia = (const int*)a; - const int* ib = (const int*)b; - return *ia - *ib; -} - -static void uniquify(int* edges, int n_edges) -{ - int i = 0; - int j = 0; - - while (j < n_edges) { - int last = edges[j++]; - edges[i++] = last; - while (j < n_edges && edges[j] == last) - ++j; - } - /* fill the rest with nonsense */ - for (; i < n_edges ; ++i) - edges[i] = G_MAXINT; -} - -static void -make_grid(const Rect* client_rects, int n_client_rects, const Rect* bound, - int* x_edges, int* y_edges, int max_edges) -{ - int i; - int n_edges = 0; - for (i = 0; i < n_client_rects; ++i) { - if (!RECT_INTERSECTS_RECT(client_rects[i], *bound)) - continue; - x_edges[n_edges] = client_rects[i].x; - y_edges[n_edges++] = client_rects[i].y; - x_edges[n_edges] = client_rects[i].x + client_rects[i].width; - y_edges[n_edges++] = client_rects[i].y + client_rects[i].height; - } - x_edges[n_edges] = bound->x; - y_edges[n_edges++] = bound->y; - x_edges[n_edges] = bound->x + bound->width; - y_edges[n_edges++] = bound->y + bound->height; - for (i = n_edges; i < max_edges; ++i) - x_edges[i] = y_edges[i] = G_MAXINT; - qsort(x_edges, n_edges, sizeof(int), compare_ints); - uniquify(x_edges, n_edges); - qsort(y_edges, n_edges, sizeof(int), compare_ints); - uniquify(y_edges, n_edges); -} - -static int total_overlap(const Rect* client_rects, int n_client_rects, - const Rect* proposed_rect) -{ - int overlap = 0; - int i; - for (i = 0; i < n_client_rects; ++i) { - if (!RECT_INTERSECTS_RECT(*proposed_rect, client_rects[i])) - continue; - Rect rtemp; - RECT_SET_INTERSECTION(rtemp, *proposed_rect, client_rects[i]); - overlap += RECT_AREA(rtemp); - } - return overlap; -} - -/* Given a list of Rect RECTS, a Point PT and a Size size, determine the - * direction from PT which results in the least total overlap with RECTS - * if a rectangle is placed in that direction. Return the top/left - * Point of such rectangle and the resulting overlap amount. Only - * consider placements within BOUNDS. */ - -#define NUM_DIRECTIONS 4 - -static int -best_direction(const Point* grid_point, - const Rect* client_rects, int n_client_rects, - const Rect* bound, const Size* req_size, Point* best_top_left) -{ - static const Size directions[NUM_DIRECTIONS] = { - {0, 0}, {0, -1}, {-1, 0}, {-1, -1} - }; - int overlap = G_MAXINT; - int i; - for (i = 0; i < NUM_DIRECTIONS; ++i) { - Point pt = { - .x = grid_point->x + (req_size->width * directions[i].width), - .y = grid_point->y + (req_size->height * directions[i].height) - }; - Rect r; - RECT_SET_POINT(r, pt.x, pt.y); - RECT_SET_SIZE(r, req_size->width, req_size->height); - if (!RECT_CONTAINS_RECT(*bound, r)) - continue; - int this_overlap = total_overlap(client_rects, n_client_rects, &r); - if (this_overlap < overlap) { - overlap = this_overlap; - *best_top_left = pt; - } - if (overlap == 0) - break; - } - return overlap; -} diff --git a/openbox/overlap.h b/openbox/overlap.h deleted file mode 100644 index 0c61035d..00000000 --- a/openbox/overlap.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- - - overlap.h for the Openbox window manager - Copyright (c) 2011 Ian Zimmerman - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - See the COPYING file for a copy of the GNU General Public License. -*/ - -#include "geom.h" - -void -overlap_find_least_placement(const Rect* client_rects, int n_client_rects, - Rect *const bounds, const Size* req_size, - Point* result); diff --git a/openbox/place.c b/openbox/place.c index 579c56bd..26021228 100644 --- a/openbox/place.c +++ b/openbox/place.c @@ -25,7 +25,7 @@ #include "config.h" #include "dock.h" #include "debug.h" -#include "overlap.h" +#include "place_overlap.h" extern ObDock *dock; @@ -256,203 +256,6 @@ static Rect *pick_head(ObClient *c, gboolean foreground, return area; } -static gboolean place_random(ObClient *client, Rect *area, gint *x, gint *y) -{ - gint l, r, t, b; - - ob_debug("placing randomly"); - - l = area->x; - t = area->y; - r = area->x + area->width - client->frame->area.width; - b = area->y + area->height - client->frame->area.height; - - if (r > l) *x = g_random_int_range(l, r + 1); - else *x = area->x; - if (b > t) *y = g_random_int_range(t, b + 1); - else *y = area->y; - - return TRUE; -} - -static GSList* area_add(GSList *list, Rect *a) -{ - Rect *r = g_slice_new(Rect); - *r = *a; - return g_slist_prepend(list, r); -} - -static GSList* area_remove(GSList *list, Rect *a) -{ - GSList *sit; - GSList *result = NULL; - - for (sit = list; sit; sit = g_slist_next(sit)) { - Rect *r = sit->data; - - if (!RECT_INTERSECTS_RECT(*r, *a)) { - result = g_slist_prepend(result, r); - /* dont free r, it's moved to the result list */ - } else { - Rect isect, extra; - - /* Use an intersection of a and r to determine the space - around r that we can use. - - NOTE: the spaces calculated can overlap. - */ - - RECT_SET_INTERSECTION(isect, *r, *a); - - if (RECT_LEFT(isect) > RECT_LEFT(*r)) { - RECT_SET(extra, r->x, r->y, - RECT_LEFT(isect) - r->x, r->height); - result = area_add(result, &extra); - } - - if (RECT_TOP(isect) > RECT_TOP(*r)) { - RECT_SET(extra, r->x, r->y, - r->width, RECT_TOP(isect) - r->y + 1); - result = area_add(result, &extra); - } - - if (RECT_RIGHT(isect) < RECT_RIGHT(*r)) { - RECT_SET(extra, RECT_RIGHT(isect) + 1, r->y, - RECT_RIGHT(*r) - RECT_RIGHT(isect), r->height); - result = area_add(result, &extra); - } - - if (RECT_BOTTOM(isect) < RECT_BOTTOM(*r)) { - RECT_SET(extra, r->x, RECT_BOTTOM(isect) + 1, - r->width, RECT_BOTTOM(*r) - RECT_BOTTOM(isect)); - result = area_add(result, &extra); - } - - /* 'r' is not being added to the result list, so free it */ - g_slice_free(Rect, r); - } - } - g_slist_free(list); - return result; -} - -enum { - IGNORE_FULLSCREEN = 1, - IGNORE_MAXIMIZED = 2, - IGNORE_MENUTOOL = 3, - /*IGNORE_SHADED = 3,*/ - IGNORE_NONGROUP = 4, - IGNORE_BELOW = 5, - /*IGNORE_NONFOCUS = 1 << 5,*/ - IGNORE_DOCK = 6, - IGNORE_END = 7 -}; - -static gboolean place_nooverlap(ObClient *c, Rect *area, gint *x, gint *y) -{ - gint ignore; - gboolean ret; - gint maxsize; - GSList *spaces = NULL, *sit, *maxit; - - ob_debug("placing nonoverlap"); - - ret = FALSE; - maxsize = 0; - maxit = NULL; - - /* try ignoring different things to find empty space */ - for (ignore = 0; ignore < IGNORE_END && !ret; ignore++) { - GList *it; - - /* add the whole monitor */ - spaces = area_add(spaces, area); - - /* go thru all the windows */ - for (it = client_list; it; it = g_list_next(it)) { - ObClient *test = it->data; - - /* should we ignore this client? */ - if (screen_showing_desktop) continue; - if (c == test) continue; - if (test->iconic) continue; - if (c->desktop != DESKTOP_ALL) { - if (test->desktop != c->desktop && - test->desktop != DESKTOP_ALL) continue; - } else { - if (test->desktop != screen_desktop && - test->desktop != DESKTOP_ALL) continue; - } - if (test->type == OB_CLIENT_TYPE_SPLASH || - test->type == OB_CLIENT_TYPE_DESKTOP) continue; - - - if ((ignore >= IGNORE_FULLSCREEN) && - test->fullscreen) continue; - if ((ignore >= IGNORE_MAXIMIZED) && - test->max_horz && test->max_vert) continue; - if ((ignore >= IGNORE_MENUTOOL) && - (test->type == OB_CLIENT_TYPE_MENU || - test->type == OB_CLIENT_TYPE_TOOLBAR) && - client_has_parent(c)) continue; - /* - if ((ignore >= IGNORE_SHADED) && - test->shaded) continue; - */ - if ((ignore >= IGNORE_NONGROUP) && - client_has_group_siblings(c) && - test->group != c->group) continue; - if ((ignore >= IGNORE_BELOW) && - test->layer < c->layer) continue; - /* - if ((ignore >= IGNORE_NONFOCUS) && - focus_client != test) continue; - */ - /* don't ignore this window, so remove it from the available - area */ - spaces = area_remove(spaces, &test->frame->area); - } - - if (ignore < IGNORE_DOCK) { - Rect a; - dock_get_area(&a); - spaces = area_remove(spaces, &a); - } - - for (sit = spaces; sit; sit = g_slist_next(sit)) { - Rect *r = sit->data; - - if (r->width >= c->frame->area.width && - r->height >= c->frame->area.height && - r->width * r->height > maxsize) - { - maxsize = r->width * r->height; - maxit = sit; - } - } - - if (maxit) { - Rect *r = maxit->data; - - /* center it in the area */ - *x = r->x; - *y = r->y; - if (config_place_center) { - *x += (r->width - c->frame->area.width) / 2; - *y += (r->height - c->frame->area.height) / 2; - } - ret = TRUE; - } - - while (spaces) { - g_slice_free(Rect, spaces->data); - spaces = g_slist_delete_link(spaces, spaces); - } - } - - return ret; -} - static gboolean place_under_mouse(ObClient *client, gint *x, gint *y) { gint l, r, t, b; @@ -559,50 +362,55 @@ 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) +static gboolean place_least_overlap(ObClient *c, Rect * const head, + gint *x, gint *y) { - /* assemble the list of "interesting" windows to calculate overlap against */ - GSList* interesting_clients = NULL; + /* Assemble the list of windows that could overlap with @c in the user's + current view. */ + GSList* potential_overlap_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; + ObClient* maybe_client = (ObClient*)it->data; if (maybe_client == c) continue; if (maybe_client->iconic) continue; + if (!client_occupies_space(maybe_client)) + continue; if (c->desktop != DESKTOP_ALL) { if (maybe_client->desktop != c->desktop && - maybe_client->desktop != DESKTOP_ALL) continue; + maybe_client->desktop != DESKTOP_ALL) + continue; } else { if (maybe_client->desktop != screen_desktop && - maybe_client->desktop != DESKTOP_ALL) continue; + 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); + + potential_overlap_clients = g_slist_prepend( + potential_overlap_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; + for (it = potential_overlap_clients; it != NULL; it = g_slist_next(it)) { + ObClient* potential_overlap_client = (ObClient*)it->data; + client_rects[i] = potential_overlap_client->frame->area; i += 1; } - g_slist_free(interesting_clients); + g_slist_free(potential_overlap_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); + place_overlap_find_least_placement(client_rects, n_client_rects, head, + &req_size, &result); *x = result.x; *y = result.y; @@ -630,12 +438,9 @@ gboolean place_client(ObClient *client, gboolean foreground, gint *x, gint *y, /* try a number of methods */ 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_LEASTOVERLAP - && place_least_overlap(client, x, y, area)) || - place_nooverlap(client, area, x, y) || - place_random(client, area, x, y); + (config_place_policy == OB_PLACE_POLICY_MOUSE && + place_under_mouse(client, x, y)) || + place_least_overlap(client, area, x, y); g_assert(ret); g_slice_free(Rect, area); diff --git a/openbox/place.h b/openbox/place.h index 25df752c..94e2dc0f 100644 --- a/openbox/place.h +++ b/openbox/place.h @@ -28,8 +28,7 @@ struct _ObAppSettings; typedef enum { OB_PLACE_POLICY_SMART, - OB_PLACE_POLICY_MOUSE, - OB_PLACE_POLICY_LEASTOVERLAP, + OB_PLACE_POLICY_MOUSE } ObPlacePolicy; typedef enum diff --git a/openbox/place_overlap.c b/openbox/place_overlap.c new file mode 100644 index 00000000..e365a370 --- /dev/null +++ b/openbox/place_overlap.c @@ -0,0 +1,175 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + overlap.c for the Openbox window manager + Copyright (c) 2011 Ian Zimmerman + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "config.h" +#include "geom.h" +#include "place_overlap.h" + +#include + +static void make_grid(const Rect* client_rects, int n_client_rects, + const Rect* bound, int* x_edges, int* y_edges, + int max_edges); + +static int best_direction(const Point* grid_point, + const Rect* client_rects, int n_client_rects, + const Rect* bound, const Size* req_size, + Point* best_top_left); + +/* Choose the placement on a grid with least overlap */ + +void place_overlap_find_least_placement(const Rect* client_rects, + int n_client_rects, + Rect *const bound, + const Size* req_size, + Point* result) +{ + result->x = result->y = 0; + int overlap = G_MAXINT; + int max_edges = 2 * (n_client_rects + 1); + + int x_edges[max_edges]; + int y_edges[max_edges]; + make_grid(client_rects, n_client_rects, bound, + x_edges, y_edges, max_edges); + int i; + for (i = 0; i < max_edges; ++i) { + if (x_edges[i] == G_MAXINT) + break; + int j; + for (j = 0; j < max_edges; ++j) { + if (y_edges[j] == G_MAXINT) + break; + Point grid_point = {.x = x_edges[i], .y = y_edges[j]}; + Point best_top_left; + int this_overlap = + best_direction(&grid_point, client_rects, n_client_rects, + bound, req_size, &best_top_left); + if (this_overlap < overlap) { + overlap = this_overlap; + *result = best_top_left; + } + if (overlap == 0) + break; + } + if (overlap == 0) + break; + } +} + +static int compare_ints(const void* a, const void* b) +{ + const int* ia = (const int*)a; + const int* ib = (const int*)b; + return *ia - *ib; +} + +static void uniquify(int* edges, int n_edges) +{ + int i = 0; + int j = 0; + + while (j < n_edges) { + int last = edges[j++]; + edges[i++] = last; + while (j < n_edges && edges[j] == last) + ++j; + } + /* fill the rest with nonsense */ + for (; i < n_edges ; ++i) + edges[i] = G_MAXINT; +} + +static void make_grid(const Rect* client_rects, int n_client_rects, + const Rect* bound, int* x_edges, int* y_edges, + int max_edges) +{ + int i; + int n_edges = 0; + for (i = 0; i < n_client_rects; ++i) { + if (!RECT_INTERSECTS_RECT(client_rects[i], *bound)) + continue; + x_edges[n_edges] = client_rects[i].x; + y_edges[n_edges++] = client_rects[i].y; + x_edges[n_edges] = client_rects[i].x + client_rects[i].width; + y_edges[n_edges++] = client_rects[i].y + client_rects[i].height; + } + x_edges[n_edges] = bound->x; + y_edges[n_edges++] = bound->y; + x_edges[n_edges] = bound->x + bound->width; + y_edges[n_edges++] = bound->y + bound->height; + for (i = n_edges; i < max_edges; ++i) + x_edges[i] = y_edges[i] = G_MAXINT; + qsort(x_edges, n_edges, sizeof(int), compare_ints); + uniquify(x_edges, n_edges); + qsort(y_edges, n_edges, sizeof(int), compare_ints); + uniquify(y_edges, n_edges); +} + +static int total_overlap(const Rect* client_rects, int n_client_rects, + const Rect* proposed_rect) +{ + int overlap = 0; + int i; + for (i = 0; i < n_client_rects; ++i) { + if (!RECT_INTERSECTS_RECT(*proposed_rect, client_rects[i])) + continue; + Rect rtemp; + RECT_SET_INTERSECTION(rtemp, *proposed_rect, client_rects[i]); + overlap += RECT_AREA(rtemp); + } + return overlap; +} + +/* Given a list of Rect RECTS, a Point PT and a Size size, determine the + direction from PT which results in the least total overlap with RECTS + if a rectangle is placed in that direction. Return the top/left + Point of such rectangle and the resulting overlap amount. Only + consider placements within BOUNDS. */ + +#define NUM_DIRECTIONS 4 + +static int best_direction(const Point* grid_point, + const Rect* client_rects, int n_client_rects, + const Rect* bound, const Size* req_size, + Point* best_top_left) +{ + static const Size directions[NUM_DIRECTIONS] = { + {0, 0}, {0, -1}, {-1, 0}, {-1, -1} + }; + int overlap = G_MAXINT; + int i; + for (i = 0; i < NUM_DIRECTIONS; ++i) { + Point pt = { + .x = grid_point->x + (req_size->width * directions[i].width), + .y = grid_point->y + (req_size->height * directions[i].height) + }; + Rect r; + RECT_SET(r, pt.x, pt.y, req_size->width, req_size->height); + if (!RECT_CONTAINS_RECT(*bound, r)) + continue; + int this_overlap = total_overlap(client_rects, n_client_rects, &r); + if (this_overlap < overlap) { + overlap = this_overlap; + *best_top_left = pt; + } + if (overlap == 0) + break; + } + return overlap; +} diff --git a/openbox/place_overlap.h b/openbox/place_overlap.h new file mode 100644 index 00000000..9ceed34e --- /dev/null +++ b/openbox/place_overlap.h @@ -0,0 +1,25 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + overlap.h for the Openbox window manager + Copyright (c) 2011 Ian Zimmerman + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "geom.h" + +void place_overlap_find_least_placement(const Rect* client_rects, + int n_client_rects, + Rect *const bounds, + const Size* req_size, + Point* result); -- cgit v1.2.3