160 lines
3.8 KiB
C
160 lines
3.8 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/extensions/Xrandr.h>
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "config.h"
|
|
|
|
int nmonitors = 0;
|
|
XRRMonitorInfo* monitorinfo;
|
|
int* xstep;
|
|
int* ystep;
|
|
|
|
void fetchmonitorinfo() {
|
|
if (monitorinfo)
|
|
XRRFreeMonitors(monitorinfo);
|
|
if (xstep)
|
|
free(xstep);
|
|
if (ystep)
|
|
free(ystep);
|
|
|
|
monitorinfo = XRRGetMonitors(dpy, DefaultRootWindow(dpy), 1, &nmonitors);
|
|
xstep = malloc(nmonitors * sizeof(int));
|
|
ystep = malloc(nmonitors * sizeof(int));
|
|
for (int i = 0; i < nmonitors; i++) {
|
|
xstep[i] = monitorinfo[i].width / CASCADE_DENSITY;
|
|
ystep[i] = monitorinfo[i].height / CASCADE_DENSITY;
|
|
}
|
|
}
|
|
|
|
void getcascadecoords(Window w, int monitor, int* x, int* y) {
|
|
int mappedclients = 0;
|
|
Client* c;
|
|
int ox = monitorinfo[monitor].x;
|
|
int oy = monitorinfo[monitor].y;
|
|
|
|
if (w == 0)
|
|
return;
|
|
for (c = clients; c; c = c->next) {
|
|
if (
|
|
c->window != w && c->state == NormalState &&
|
|
getmonitorbyclient(c) == monitor) {
|
|
mappedclients++;
|
|
}
|
|
}
|
|
for (;;) {
|
|
if (mappedclients < CASCADE_DENSITY) {
|
|
*x = ox + mappedclients * xstep[monitor];
|
|
*y = oy + mappedclients * ystep[monitor];
|
|
return;
|
|
} else if (mappedclients < 1.5 * CASCADE_DENSITY) {
|
|
*x = ox + (mappedclients - CASCADE_DENSITY + 1) * xstep[monitor];
|
|
*y = oy + (mappedclients - CASCADE_DENSITY) * ystep[monitor];
|
|
return;
|
|
} else if (mappedclients < 2 * CASCADE_DENSITY) {
|
|
*x = ox + (mappedclients - 1.5 * CASCADE_DENSITY) * xstep[monitor];
|
|
*y = oy + (mappedclients - 1.5 * CASCADE_DENSITY + 1) * ystep[monitor];
|
|
return;
|
|
} else {
|
|
mappedclients -= 2 * CASCADE_DENSITY;
|
|
}
|
|
}
|
|
}
|
|
|
|
int getmonitorbyclient(Client* c) {
|
|
XRRMonitorInfo m;
|
|
int cx, cy, i, p;
|
|
cx = cy = 0;
|
|
|
|
/* we check which monitor the center of the window is in */
|
|
if (c) {
|
|
cx = c->x + c->dx / 2;
|
|
cy = c->y + c->dy / 2;
|
|
}
|
|
|
|
p = 0;
|
|
|
|
for (i = 0; i < nmonitors; i++) {
|
|
m = monitorinfo[i];
|
|
if (
|
|
c && cx >= m.x && cx < m.x + m.width && cy >= m.y &&
|
|
cy < m.y + m.height) {
|
|
return i;
|
|
}
|
|
|
|
if (m.primary) {
|
|
p = i;
|
|
}
|
|
}
|
|
|
|
/* if center is not within any monitor, return primary */
|
|
return p;
|
|
}
|
|
|
|
int getmonitorbymouse() {
|
|
Window w;
|
|
int x, y, i;
|
|
unsigned int mask;
|
|
XRRMonitorInfo m;
|
|
|
|
XQueryPointer(dpy, DefaultRootWindow(dpy), &w, &w, &x, &y, &x, &y, &mask);
|
|
for (i = 0; i < nmonitors; i++) {
|
|
m = monitorinfo[i];
|
|
if (x >= m.x && x < m.x + m.width && y >= m.y && y < m.y + m.height) {
|
|
return i;
|
|
}
|
|
}
|
|
/* should never reach here, but return first monitor if we do */
|
|
return 0;
|
|
}
|
|
|
|
void wrangle(Client* c, XRRMonitorInfo monitor) {
|
|
|
|
if (!c)
|
|
return;
|
|
|
|
/* If it's bigger than the screen, try to set it maximized */
|
|
|
|
if (c->dx >= monitor.width && c->dy >= monitor.height) {
|
|
quickreshape(c, monitor.x, monitor.y, monitor.width, monitor.height, 1);
|
|
/* and if it's got an edge out of bounds, nudge it into bounds */
|
|
} else {
|
|
if (c->x < monitor.x + BORDER) {
|
|
quickreshape(
|
|
c,
|
|
monitor.x,
|
|
c->y - BORDER,
|
|
c->dx + 2 * BORDER,
|
|
c->dy + 2 * BORDER,
|
|
0);
|
|
}
|
|
if (c->y < monitor.y + BORDER) {
|
|
quickreshape(
|
|
c,
|
|
c->x - BORDER,
|
|
monitor.y,
|
|
c->dx + 2 * BORDER,
|
|
c->dy + 2 * BORDER,
|
|
0);
|
|
}
|
|
if (c->x + c->dx + BORDER > monitor.x + monitor.width) {
|
|
quickreshape(
|
|
c,
|
|
monitor.x + monitor.width - (c->dx + 2 * BORDER),
|
|
c->y - BORDER,
|
|
c->dx + 2 * BORDER,
|
|
c->dy + 2 * BORDER,
|
|
0);
|
|
}
|
|
if (c->y + c->dy + BORDER > monitor.y + monitor.height) {
|
|
quickreshape(
|
|
c,
|
|
c->x - BORDER,
|
|
monitor.y + monitor.height - (c->dy + 2 * BORDER),
|
|
c->dx + 2 * BORDER,
|
|
c->dy + 2 * BORDER,
|
|
0);
|
|
}
|
|
}
|
|
}
|