+ gint l, r, t, b;
+ Rect **areas;
+ guint i;
+
+ areas = pick_head(client);
+ i = (config_place_monitor != OB_PLACE_MONITOR_ANY) ?
+ 0 : g_random_int_range(0, screen_num_monitors);
+
+ l = areas[i]->x;
+ t = areas[i]->y;
+ r = areas[i]->x + areas[i]->width - client->frame->area.width;
+ b = areas[i]->y + areas[i]->height - client->frame->area.height;
+
+ if (r > l) *x = g_random_int_range(l, r + 1);
+ else *x = areas[i]->x;
+ if (b > t) *y = g_random_int_range(t, b + 1);
+ else *y = areas[i]->y;
+
+ for (i = 0; i < screen_num_monitors; ++i)
+ g_free(areas[i]);
+ g_free(areas);
+
+ return TRUE;
+}
+
+static GSList* area_add(GSList *list, Rect *a)
+{
+ Rect *r = g_new(Rect, 1);
+ *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_free(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, gint *x, gint *y)
+{
+ Rect **areas;
+ gint ignore;
+ gboolean ret;
+ gint maxsize;
+ GSList *spaces = NULL, *sit, *maxit;
+ guint i;
+
+ areas = pick_head(c);
+ ret = FALSE;
+ maxsize = 0;
+ maxit = NULL;
+
+ /* try ignoring different things to find empty space */
+ for (ignore = 0; ignore < IGNORE_END && !ret; ignore++) {
+ /* try all monitors in order of preference, but only the first one
+ if config_place_monitor is MOUSE or ACTIVE */
+ for (i = 0; (i < (config_place_monitor != OB_PLACE_MONITOR_ANY ?
+ 1 : screen_num_monitors) && !ret); ++i)
+ {
+ GList *it;
+
+ /* add the whole monitor */
+ spaces = area_add(spaces, areas[i]);
+
+ /* 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_free(spaces->data);
+ spaces = g_slist_delete_link(spaces, spaces);
+ }
+ }
+ }
+
+ for (i = 0; i < screen_num_monitors; ++i)
+ g_free(areas[i]);
+ g_free(areas);
+ return ret;
+}
+
+static gboolean place_under_mouse(ObClient *client, gint *x, gint *y)
+{
+ gint l, r, t, b;
+ gint px, py;