/*-
* Copyright (c) 2001 Jordan DeLong
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "wm.h"
/* xinerama support is optional */
#ifdef USE_XINERAMA
/* is xinerama active on the display */
static int xinerama_active = 0;
/* xinerama screen information */
static int xinerama_count;
static rect_t *xinerama_screens;
/*
* determine if the xinerama extension exists and if the display we
* are on is using it.
*/
void xinerama_init() {
XineramaScreenInfo *sinfo;
int i;
/* try for the xinerama extension */
if (!XineramaQueryExtension(display, &i, &i))
return;
if (!XineramaIsActive(display))
return;
/* grab screen information structures */
sinfo = XineramaQueryScreens(display, &xinerama_count);
if (xinerama_count == 0 || !sinfo)
return;
/*
* turn screen info structures to rectangles and
* free the memory associated with them.
*/
xinerama_screens = malloc(sizeof(rect_t) * xinerama_count);
if (!xinerama_screens) {
XFree(sinfo);
return;
}
for (i = 0; i < xinerama_count; i++) {
xinerama_screens[i].x1 = sinfo[i].x_org;
xinerama_screens[i].y1 = sinfo[i].y_org;
xinerama_screens[i].x2 = sinfo[i].x_org + sinfo[i].width;
xinerama_screens[i].y2 = sinfo[i].y_org + sinfo[i].height;
}
XFree(sinfo);
/* mention that we are doing xinerama stuff */
warnx("display has active XINERAMA");
xinerama_active = 1;
}
/* free screen size rectangles */
void xinerama_shutdown() {
if (!xinerama_active)
return;
free(xinerama_screens);
}
/*
* zoom a client; make it as large as the screen that it
* is mostly on.
*/
int xinerama_zoom(client_t *client) {
rect_t rect;
int most, mosti;
int area, i;
if (!xinerama_active)
return 1;
/* get a rect of client dimensions */
rect.x1 = client->x;
rect.y1 = client->y;
rect.x2 = FULLWIDTH(client) + rect.x1;
rect.y2 = FULLHEIGHT(client) + rect.y1;
/*
* determine which screen this client is mostly
* on by checking the area of intersection of
* the client's rectangle and the xinerama
* screen's rectangle.
*/
most = mosti = 0;
for (i = 0; i < xinerama_count; i++) {
area = rect_intersection(&rect, &xinerama_screens[i]);
if (area > most) {
most = area;
mosti = i;
}
}
/* zoom it on the screen it's mostly on */
client->x = xinerama_screens[mosti].x1;
client->y = xinerama_screens[mosti].y1;
client->width = RECTWIDTH(&xinerama_screens[mosti]) - DWIDTH(client);
client->height = RECTHEIGHT(&xinerama_screens[mosti]) - DHEIGHT(client);
return 0;
}
/*
* correct a client's location if it falls across two or more
* monitors so that it is, if possible, located on only one
* monitor.
*/
void xinerama_correctloc(client_t *client) {
rect_t rect;
int isect, carea, i, cnt;
int most, mosti;
/* dont do anything if no xinerama */
if (!xinerama_active)
return;
/* get client area and rectangle */
rect.x1 = client->x;
rect.y1 = client->y;
rect.x2 = FULLWIDTH(client) + rect.x1;
rect.y2 = FULLHEIGHT(client) + rect.y1;
carea = RECTWIDTH(&rect) * RECTHEIGHT(&rect);
/*
* determine if the client is stretched across more
* than one xinerama screen.
*/
for (i = 0, cnt = 0; i < xinerama_count; i++) {
isect = rect_intersection(&rect, &xinerama_screens[i]);
if (isect) {
if (isect == carea)
return;
if (++cnt >= 2)
goto correct;
}
}
return;
/*
* we've found that the client lies across more than one
* monitor, so try to push it into the one it is mostly
* on.
*/
correct:
trace("found a window \"%s\" that needs correction", client->store_name ? : "unamed");
most = mosti = 0;
for (i = 0; i < xinerama_count; i++) {
isect = rect_intersection(&rect, &xinerama_screens[i]);
if (isect > most) {
most = isect;
mosti = i;
}
}
/* make sure it is small enough to fit */
if (RECTWIDTH(&rect) >= RECTWIDTH(&xinerama_screens[mosti]))
return;
if (RECTHEIGHT(&rect) >= RECTWIDTH(&xinerama_screens[mosti]))
return;
/* push it into the screen */
if (client->x < xinerama_screens[mosti].x1)
client->x = xinerama_screens[mosti].x1;
else if (client->x + FULLWIDTH(client) > xinerama_screens[mosti].x2)
client->x = xinerama_screens[mosti].x2 - FULLWIDTH(client);
if (client->y < xinerama_screens[mosti].y1)
client->y = xinerama_screens[mosti].y1;
else if (client->y + FULLHEIGHT(client) > xinerama_screens[mosti].y2)
client->y = xinerama_screens[mosti].y2 - FULLHEIGHT(client);
}
/*
* used to fill rects with the dimensions of each xinerama
* monitor in order. the screen_t is provided so that if
* xinerama is not active on the display we can just give a
* rect of the size of that screen. *mon is used as an index
* to which monitor to get the dims of, and should be 0
* on the first call to the function. return 0 when there
* aren't any more monitors.
*/
int xinerama_scrdims(screen_t *screen, int *mon, rect_t *rect) {
if (xinerama_active) {
if (*mon >= xinerama_count)
return 0;
rect->x1 = xinerama_screens[*mon].x1;
rect->y1 = xinerama_screens[*mon].y1;
rect->x2 = xinerama_screens[*mon].x2;
rect->y2 = xinerama_screens[*mon].y2;
} else {
if (*mon)
return 0;
rect->x1 = 0;
rect->y1 = 0;
rect->x2 = screen->width;
rect->y2 = screen->height;
}
(*mon)++;
return 1;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1