/* -*- 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* monitor, 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* monitor, 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, const Rect *monitor, const Size* req_size, Point* result) { POINT_SET(*result, monitor->x, monitor->y); 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, monitor, 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, monitor, 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* monitor, 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], *monitor)) 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] = monitor->x; y_edges[n_edges++] = monitor->y; x_edges[n_edges] = monitor->x + monitor->width; y_edges[n_edges++] = monitor->y + monitor->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* monitor, 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(*monitor, 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; }