diff options
Diffstat (limited to 'src/screen.c')
-rw-r--r-- | src/screen.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..8fb63a5 --- /dev/null +++ b/src/screen.c @@ -0,0 +1,152 @@ +/* + * \/\/\ + * + * Copyright (C) 2012-2016 Vito Caputo - <vcaputo@gnugeneration.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* return the appropriate screen, don't use the return value across event loops because randr events reallocate the array. */ + +#include <X11/Xlib.h> +#include <stdarg.h> +#include <values.h> + +#include "list.h" +#include "screen.h" +#include "vwm.h" +#include "window.h" +#include "xwindow.h" + + /* Xinerama/multihead screen functions */ + +/* return what fraction (0.0-1.0) of vwin overlaps with scr */ +static float vwm_screen_overlaps_xwin(vwm_t *vwm, const vwm_screen_t *scr, vwm_xwindow_t *xwin) +{ + float pct = 0, xover = 0, yover = 0; + + if (scr->x_org + scr->width < xwin->attrs.x || scr->x_org > xwin->attrs.x + xwin->attrs.width || + scr->y_org + scr->height < xwin->attrs.y || scr->y_org > xwin->attrs.y + xwin->attrs.height) + goto _out; + + /* they overlap, by how much? */ + xover = MIN(scr->x_org + scr->width, xwin->attrs.x + xwin->attrs.width) - MAX(scr->x_org, xwin->attrs.x); + yover = MIN(scr->y_org + scr->height, xwin->attrs.y + xwin->attrs.height) - MAX(scr->y_org, xwin->attrs.y); + + pct = (xover * yover) / (xwin->attrs.width * xwin->attrs.height); +_out: + VWM_TRACE("xover=%f yover=%f width=%i height=%i pct=%.4f", xover, yover, xwin->attrs.width, xwin->attrs.height, pct); + return pct; +} + + +const vwm_screen_t * vwm_screen_find(vwm_t *vwm, vwm_screen_rel_t rel, ...) +{ + static vwm_screen_t faux; + vwm_screen_t *scr, *best = &faux; /* default to faux as best */ + int i; + + faux.screen_number = 0; + faux.x_org = 0; + faux.y_org = 0; + faux.width = WidthOfScreen(DefaultScreenOfDisplay(vwm->display)); + faux.height = HeightOfScreen(DefaultScreenOfDisplay(vwm->display)); + + if (!vwm->xinerama_screens) goto _out; + +#define for_each_screen(_tmp) \ + for (i = 0, _tmp = vwm->xinerama_screens; i < vwm->xinerama_screens_cnt; _tmp = &vwm->xinerama_screens[++i]) + + switch (rel) { + case VWM_SCREEN_REL_XWIN: { + va_list ap; + vwm_xwindow_t *xwin; + float best_pct = 0, this_pct; + + va_start(ap, rel); + xwin = va_arg(ap, vwm_xwindow_t *); + va_end(ap); + + for_each_screen(scr) { + this_pct = vwm_screen_overlaps_xwin(vwm, scr, xwin); + if (this_pct > best_pct) { + best = scr; + best_pct = this_pct; + } + } + break; + } + + case VWM_SCREEN_REL_POINTER: { + int root_x, root_y, win_x, win_y; + unsigned int mask; + Window root, child; + + /* get the pointer coordinates and find which screen it's in */ + XQueryPointer(vwm->display, VWM_XROOT(vwm), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask); + + for_each_screen(scr) { + if (root_x >= scr->x_org && root_x < scr->x_org + scr->width && + root_y >= scr->y_org && root_y < scr->y_org + scr->height) { + best = scr; + break; + } + } + break; + } + + case VWM_SCREEN_REL_TOTAL: { + short x1 = MAXSHORT, y1 = MAXSHORT, x2 = MINSHORT, y2 = MINSHORT; + /* find the smallest x_org and y_org, the highest x_org + width and y_org + height, those are the two corners of the total rect */ + for_each_screen(scr) { + if (scr->x_org < x1) x1 = scr->x_org; + if (scr->y_org < y1) y1 = scr->y_org; + if (scr->x_org + scr->width > x2) x2 = scr->x_org + scr->width; + if (scr->y_org + scr->height > y2) y2 = scr->y_org + scr->height; + } + faux.x_org = x1; + faux.y_org = y1; + faux.width = x2 - x1; + faux.height = y2 - y1; + best = &faux; + break; + } + } +_out: + VWM_TRACE("Found Screen #%i: %hix%hi @ %hi,%hi", best->screen_number, best->width, best->height, best->x_org, best->y_org); + + return best; +} + + +/* check if a screen contains any windows (assuming the current desktop) */ +int vwm_screen_is_empty(vwm_t *vwm, const vwm_screen_t *scr) +{ + vwm_xwindow_t *xwin; + int is_empty = 1; + + list_for_each_entry(xwin, &vwm->xwindows, xwindows) { + if (!xwin->mapped) continue; + if (!xwin->managed || (xwin->managed->desktop == vwm->focused_desktop && !xwin->managed->shelved && !xwin->managed->configuring)) { + /* XXX: it may make more sense to see what %age of the screen is overlapped by windows, and consider it empty if < some % */ + /* This is just seeing if any window is predominantly within the specified screen, the rationale being if you had a focusable + * window on the screen you would have used the keyboard to make windows go there; this function is only used in determining + * wether a new window should go where the pointer is or not. */ + if (vwm_screen_overlaps_xwin(vwm, scr, xwin) >= 0.05) { + is_empty = 0; + break; + } + } + } + + return is_empty; +} |