/*- * 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