/* * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Conectiva Linux shall * not be used in advertising or otherwise to promote the sale, use or other * dealings in this Software without prior written authorization from * Conectiva Linux. * * Author: Paulo César Pereira de Andrade * */ #include #include #include #include "screen.h" #define CW 1 #define CCW -1 /* * Prototypes */ void ReshapeScreenWidget(xf86cfgScreen*); static int qcmp_screen(_Xconst void*, _Xconst void*); /* * Initialization */ extern Widget work; static int rows, columns; /* number of rows/columns of monitors */ static int mon_width, mon_height; static int *mon_widths, *mon_heights; /* * Implementation */ void SetScreenRotate(xf86cfgScreen *screen) { static char *Rotate = "Rotate", *_CW = "CW", *_CCW = "CCW"; int rotate = 0; XF86OptionPtr option, options; /* This is the only place where xf86cfg is intrusive, and deletes options * added by the user directly in the config file. The "Rotate" option * will be kept in the screen section. */ if (screen->monitor != NULL) { options = ((XF86ConfMonitorPtr)(screen->monitor->config))->mon_option_lst; if ((option = xf86findOption(options, Rotate)) != NULL) { if (option->opt_val != NULL) rotate = strcasecmp(option->opt_val, _CW) == 0 ? CW : strcasecmp(option->opt_val, _CCW) == 0 ? CCW : 0; xf86removeOption(&((XF86ConfMonitorPtr)(screen->monitor->config)) ->mon_option_lst, Rotate); } } if (screen->card != NULL) { options = ((XF86ConfDevicePtr)(screen->card->config))->dev_option_lst; if ((option = xf86findOption(options, Rotate)) != NULL) { if (option->opt_val != NULL) rotate += strcasecmp(option->opt_val, _CW) == 0 ? CW : strcasecmp(option->opt_val, _CCW) == 0 ? CCW : 0; xf86removeOption(&((XF86ConfDevicePtr)(screen->card->config)) ->dev_option_lst, Rotate); } } options = screen->screen->scrn_option_lst; if ((option = xf86findOption(options, Rotate)) != NULL) { if (option->opt_val != NULL) rotate += strcasecmp(option->opt_val, _CW) == 0 ? CW : strcasecmp(option->opt_val, _CCW) == 0 ? CCW : 0; xf86removeOption(&screen->screen->scrn_option_lst, Rotate); } rotate = rotate > 0 ? CW : rotate < 0 ? CCW : 0; if (rotate) screen->screen->scrn_option_lst = xf86addNewOption(screen->screen->scrn_option_lst, XtNewString(Rotate), XtNewString(rotate > 0 ? _CW : _CCW)); screen->rotate = rotate; } void CreateScreenWidget(xf86cfgScreen *screen) { Widget w = XtCreateWidget("screen", simpleWidgetClass, XtParent(computer.cpu), NULL, 0); SetScreenRotate(screen); XtRealizeWidget(w); screen->widget = w; screen->column = screen->row = -1; ReshapeScreenWidget(screen); } void ReshapeScreenWidget(xf86cfgScreen *screen) { Pixmap pixmap; XGCValues values; GC gc; int x = 0, y = 0, width = screen->rect.width, height = screen->rect.height; Widget w = screen->widget; if (screen->state == USED && screen->row >= 0) { if (screen->column == 0) x = w->core.width - width; else if (screen->column == columns - 1) x = w->core.width - mon_widths[screen->column]; else x = (w->core.width - mon_widths[screen->column]) + ((mon_widths[screen->column] - width) >> 1); if (screen->row == 0) y = w->core.height - height; else if (screen->row == rows - 1) y = w->core.height - mon_heights[screen->row]; else y = (w->core.height - mon_heights[screen->row]) + ((mon_heights[screen->row] - height) >> 1); } else if (screen->rect.width == 0) { width = w->core.width; height = w->core.height; } screen->rect.x = x; screen->rect.y = y; screen->rect.width = width; screen->rect.height = height; pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w), w->core.width, w->core.height, 1); values.foreground = 0; values.background = 1; gc = XCreateGC(XtDisplay(w), pixmap, GCForeground | GCBackground, &values); XFillRectangle(XtDisplay(w), pixmap, gc, 0, 0, w->core.width, w->core.height); XSetForeground(XtDisplay(w), gc, 1); DrawScreenMask(XtDisplay(w), pixmap, gc, x, y, x + width, y + height, screen->rotate); XShapeCombineMask(XtDisplay(w), XtWindow(w), ShapeBounding, 0, 0, pixmap, ShapeSet); /* Do not call XtSetValues, to avoid all extra code for caching pixmaps */ XFreePixmap(XtDisplay(w), pixmap); if (XtIsRealized(w)) { pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w), w->core.width, w->core.height, DefaultDepthOfScreen(XtScreen(w))); DrawScreen(XtDisplay(w), pixmap, x, y, x + width, y + height, screen->state == USED ? True : False, screen->rotate); XSetWindowBackgroundPixmap(XtDisplay(w), XtWindow(w), pixmap); XClearWindow(XtDisplay(w), XtWindow(w)); XFreePixmap(XtDisplay(w), pixmap); } XFreeGC(XtDisplay(w), gc); } void AddScreen(xf86cfgDevice *mon, xf86cfgDevice *dev) { int nscreens = 0; char screen_name[48]; XF86ConfScreenPtr screen = XF86Config->conf_screen_lst; XF86ConfAdjacencyPtr adj; while (screen != NULL) { ++nscreens; screen = (XF86ConfScreenPtr)(screen->list.next); } do { XmuSnprintf(screen_name, sizeof(screen_name), "Screen%d", nscreens); ++nscreens; } while (xf86findScreen(screen_name, XF86Config->conf_screen_lst) != NULL); screen = (XF86ConfScreenPtr)XtCalloc(1, sizeof(XF86ConfScreenRec)); screen->scrn_identifier = XtNewString(screen_name); screen->scrn_device_str = XtNewString(((XF86ConfDevicePtr)(dev->config))->dev_identifier); screen->scrn_device = (XF86ConfDevicePtr)(dev->config); screen->scrn_monitor_str = XtNewString(((XF86ConfMonitorPtr)(mon->config))->mon_identifier); screen->scrn_monitor = (XF86ConfMonitorPtr)(mon->config); XF86Config->conf_screen_lst = xf86addScreen(XF86Config->conf_screen_lst, screen); adj = (XF86ConfAdjacencyPtr)XtCalloc(1, sizeof(XF86ConfAdjacencyRec)); adj->adj_screen = screen; adj->adj_screen_str = XtNewString(screen_name); if (computer.layout == NULL) computer.layout = XF86Config->conf_layout_lst = (XF86ConfLayoutPtr) XtCalloc(1, sizeof(XF86ConfLayoutRec)); computer.layout->lay_adjacency_lst = (XF86ConfAdjacencyPtr) xf86addListItem((GenericListPtr)computer.layout->lay_adjacency_lst, (GenericListPtr)adj); computer.screens = (xf86cfgScreen**) XtRealloc((XtPointer)computer.screens, sizeof(xf86cfgScreen*) * (computer.num_screens + 1)); computer.screens[computer.num_screens] = (xf86cfgScreen*)XtCalloc(1, sizeof(xf86cfgScreen)); computer.screens[computer.num_screens]->screen = screen; computer.screens[computer.num_screens]->card = dev; computer.screens[computer.num_screens]->monitor = mon; ++dev->refcount; ++mon->refcount; CreateScreenWidget(computer.screens[computer.num_screens]); computer.screens[computer.num_screens]->type = SCREEN; SetTip((xf86cfgDevice*)computer.screens[computer.num_screens]); ++computer.num_screens; } void RemoveScreen(xf86cfgDevice *mon, xf86cfgDevice *dev) { XF86ConfScreenPtr screen = XF86Config->conf_screen_lst; int i; mon->state = dev->state = UNUSED; while (screen != NULL) { if ((XtPointer)screen->scrn_monitor == mon->config && (XtPointer)screen->scrn_device == dev->config) break; screen = (XF86ConfScreenPtr)(screen->list.next); } --mon->refcount; --dev->refcount; for (i = 0; i < computer.num_screens; i++) { if (computer.screens[i]->screen == screen) { XtDestroyWidget(computer.screens[i]->widget); if (i < --computer.num_screens) memmove(&computer.screens[i], &computer.screens[i + 1], (computer.num_screens - i) * sizeof(xf86cfgScreen*)); break; } } xf86removeScreen(XF86Config, screen); } void ChangeScreen(XF86ConfMonitorPtr mon, XF86ConfMonitorPtr oldmon, XF86ConfDevicePtr dev, XF86ConfDevicePtr olddev) { int ioldm, im, ioldc, ic; if (mon == oldmon && dev == olddev) return; if (mon != NULL) { for (im = 0; im < computer.num_devices; im++) if (computer.devices[im]->config == (XtPointer)mon) break; } else im = -1; if (oldmon != NULL) { for (ioldm = 0; ioldm < computer.num_devices; ioldm++) if (computer.devices[ioldm]->config == (XtPointer)oldmon) break; } else ioldm = -1; if (dev != NULL) { for (ic = 0; ic < computer.num_devices; ic++) if (computer.devices[ic]->config == (XtPointer)dev) break; } else ic = -1; if (olddev != NULL) { for (ioldc = 0; ioldc < computer.num_devices; ioldc++) if (computer.devices[ioldc]->config == (XtPointer)olddev) break; } else ioldc = -1; if (ioldm >= 0 && ioldc >= 0) { RemoveScreen(computer.devices[ioldm], computer.devices[ioldc]); computer.devices[ioldm]->state = UNUSED; /* computer.devices[ioldc]->state = UNUSED;*/ } if (im >= 0 && ic >= 0) { AddScreen(computer.devices[im], computer.devices[ic]); computer.devices[im]->state = USED; /* computer.devices[ic]->state = USED;*/ } } /* +------------------------------------------------+ | | | +------------------------------------------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +------------------------------------------+ | | | +------------------------------------------------+ | | +-------+ +-------+ | | +----------------------------------------+ */ static double oxs = 0.0, oys = 0.0, oxe = 100.0, oye = 70.0; static double ixs = 7.0, iys = 7.0, ixe = 93.0, iye = 63.0; static double lin[] = { 25.0, 70.0, 25.0, 75.0, 5.0, 75.0, 5.0, 80.0, 95.0, 80.0, 95.0, 75.0, 75.0, 75.0, 75.0, 70.0 }; void DrawScreen(Display *dpy, Drawable win, int xs, int ys, int xe, int ye, Bool active, int rotate) { double xfact, yfact; XPoint points[(sizeof(lin) / sizeof(lin[0])) >> 1]; int i; static GC gray0, gray1, gray2, black, red; if (black == NULL) { XColor color, exact; XGCValues values; XAllocNamedColor(XtDisplay(toplevel), toplevel->core.colormap, "gray95", &color, &exact); values.foreground = color.pixel; gray0 = XCreateGC(XtDisplay(toplevel), win, GCForeground, &values); XAllocNamedColor(XtDisplay(toplevel), toplevel->core.colormap, "gray75", &color, &exact); values.foreground = color.pixel; gray1 = XCreateGC(XtDisplay(toplevel), win, GCForeground, &values); XAllocNamedColor(XtDisplay(toplevel), toplevel->core.colormap, "gray60", &color, &exact); values.foreground = color.pixel; gray2 = XCreateGC(XtDisplay(toplevel), win, GCForeground, &values); XAllocNamedColor(XtDisplay(toplevel), toplevel->core.colormap, "gray20", &color, &exact); values.foreground = color.pixel; black = XCreateGC(XtDisplay(toplevel), win, GCForeground, &values); XAllocNamedColor(XtDisplay(toplevel), toplevel->core.colormap, "red", &color, &exact); values.foreground = color.pixel; values.line_width = 4; values.cap_style = CapButt; red = XCreateGC(XtDisplay(toplevel), win, GCForeground | GCLineWidth | GCCapStyle, &values); } if (rotate) { xfact = (xe - xs) / 80.0; yfact = (ye - ys) / 100.0; if (rotate == CW) { /* outer rectangle */ XFillRectangle(dpy, win, gray1, oxs * xfact + xs + .5, oys * yfact + ys + .5, (oye - oys) * xfact + .5, (oxe - oxs) * yfact + .5); XDrawLine(dpy, win, gray2, xs, ye - 1, 70 * xfact + xs - 1 + .5, ye - 1); XDrawLine(dpy, win, gray2, 70 * xfact + xs - 1 + .5, ye - 1, 70 * xfact + xs - 1 + .5, ys); /* inner rectangle */ XFillRectangle(dpy, win, black, ixs * xfact + xs + .5, iys * yfact + ys + .5, (iye - iys) * xfact + .5, (ixe - ixs) * yfact + .5); for (i = 0; i < sizeof(points) / sizeof(points[0]); i++) { points[i].x = lin[(i<<1) + 1] * xfact + xs + .5; points[i].y = lin[(i<<1)] * yfact + ys + .5; } XFillPolygon(dpy, win, gray2, points, i, Convex, CoordModeOrigin); XDrawLine(dpy, win, gray0, (oxe - 10) * xfact + xs + .5, oys * yfact + ys + .5, xs, oys * yfact + ys + .5); XDrawLine(dpy, win, gray0, xs, ys, xs, xe); XDrawLine(dpy, win, black, lin[7] * xfact + xs - 1 + .5, lin[6] * yfact + ys + .5, lin[9] * xfact + xs - 1 + .5, lin[8] * yfact + ys - 1 + .5); XDrawLine(dpy, win, black, lin[9] * xfact + xs - 1 + .5, lin[8] * yfact + ys - 1 + .5, lin[11] * xfact + xs + .5, lin[10] * yfact + ys - 1 + .5); XDrawLine(dpy, win, black, lin[13] * xfact + xs + .5, lin[12] * yfact + ys - 1 + .5, lin[15] * xfact + xs + .5, lin[14] * yfact + ys - 1 + .5); if (!active) { XDrawLine(dpy, win, red, iys * xfact, ixs * yfact, iye * xfact, ixe * yfact); XDrawLine(dpy, win, red, iye * xfact, ixs * yfact, iys * xfact, ixe * yfact); } } else if (rotate == CCW) { /* outer rectangle */ XFillRectangle(dpy, win, gray1, 10 * xfact + xs + .5, oys * yfact + ys + .5, (oye - oys) * xfact + .5, (oxe - oxs) * yfact + .5); XDrawLine(dpy, win, gray2, 10 * xfact + xs + .5, ye - 1, oxe * xfact + xs - 1 + .5, ye - 1); XDrawLine(dpy, win, gray2, xe - 1, ye - 1, xe - 1, ys); /* inner rectangle */ XFillRectangle(dpy, win, black, (ixs + 10) * xfact + xs + .5, iys * yfact + ys + .5, (iye - iys) * xfact + .5, (ixe - ixs) * yfact + .5); for (i = 0; i < sizeof(points) / sizeof(points[0]); i++) { points[i].x = (-lin[(i<<1) + 1] + 80.0) * xfact + xs + .5; points[i].y = lin[(i<<1)] * yfact + ys + .5; } XFillPolygon(dpy, win, gray2, points, i, Convex, CoordModeOrigin); XDrawLine(dpy, win, gray0, oxe * xfact + xs + .5, oys * yfact + ys + .5, (oxs - 10) * xfact + xs + .5, oys * yfact + ys + .5); XDrawLine(dpy, win, gray0, (oxs + 10) * xfact + xs + .5, ys, (oxs + 10) * xfact + xs + .5, xe); XDrawLine(dpy, win, black, xs, lin[8] * yfact - 1 + ys + .5, 4 * xfact + xs + .5, lin[8] * yfact - 1 + ys + .5); XDrawLine(dpy, win, black, 4 * xfact + xs, lin[8] * yfact - 1 + ys + .5, 4 * xfact + xs, lin[3] * yfact - 1 + ys + .5); XDrawLine(dpy, win, black, 4 * xfact + xs + .5, lin[3] * yfact - 1 + ys + .5, 10 * xfact + xs + .5 - 1, lin[3] * yfact - 1 + ys + .5); XDrawLine(dpy, win, black, 4 * xfact + xs, lin[0] * yfact - 1 + ys + .5, 4 * xfact + xs, lin[4] * yfact - 1 + ys + .5); if (!active) { XDrawLine(dpy, win, red, (iys + 10) * xfact, ixs * yfact, (iye + 10) * xfact, ixe * yfact); XDrawLine(dpy, win, red, (iye + 10) * xfact, ixs * yfact, (iys + 10) * xfact, ixe * yfact); } } } else { xfact = (xe - xs) / 100.0; yfact = (ye - ys) / 80.0; /* outer rectangle */ XFillRectangle(dpy, win, gray1, oxs * xfact + xs + .5, oys * yfact + ys + .5, (oxe - oxs) * xfact + .5, (oye - oys) * yfact + .5); XDrawLine(dpy, win, gray2, oxs * xfact + xs + .5, oye * yfact + ys - 1 + .5, oxe * xfact + xs - 1 + .5, oye * yfact + ys - 1 + .5); XDrawLine(dpy, win, gray2, oxe * xfact + xs - 1 + .5, oys * yfact + ys + .5, oxe * xfact + xs - 1 + .5, oye * yfact + ys - 1 + .5); /* inner rectangle */ XFillRectangle(dpy, win, black, ixs * xfact + xs + .5, iys * yfact + ys + .5, (ixe - ixs) * xfact + .5, (iye - iys) * yfact + .5); for (i = 0; i < sizeof(points) / sizeof(points[0]); i++) { points[i].x = lin[i<<1] * xfact + xs + .5; points[i].y = lin[(i<<1) + 1] * yfact + ys + .5; } XFillPolygon(dpy, win, gray2, points, i, Convex, CoordModeOrigin); XDrawLine(dpy, win, black, lin[6] * xfact + xs + .5, lin[7] * yfact + ys - 1 + .5, lin[8] * xfact + xs - 1 + .5, lin[9] * yfact + ys - 1 + .5); XDrawLine(dpy, win, black, lin[8] * xfact + xs - 1 + .5, lin[9] * yfact + ys - 1 + .5, lin[10] * xfact + xs - 1 + .5, lin[11] * yfact + ys + .5); XDrawLine(dpy, win, black, lin[12] * xfact + xs - 1 + .5, lin[13] * yfact + ys + .5, lin[14] * xfact + xs - 1 + .5, lin[15] * yfact + ys + .5); XDrawLine(dpy, win, gray0, oxe * xfact + xs + .5, oys * yfact + ys + .5, oxs * xfact + xs + .5, oys * yfact + ys + .5); XDrawLine(dpy, win, gray0, oxs * xfact + xs + .5, oys * yfact + ys + .5, oxs * xfact + xs + .5, lin[1] * yfact + ys + .5); if (!active) { XDrawLine(dpy, win, red, ixs * xfact, iys * yfact, ixe * xfact, iye * yfact); XDrawLine(dpy, win, red, ixe * xfact, iys * yfact, ixs * xfact, iye * yfact); } } } void DrawScreenMask(Display *dpy, Drawable win, GC gc, int xs, int ys, int xe, int ye, int rotate) { double xfact, yfact; XPoint points[(sizeof(lin) / sizeof(lin[0])) >> 1]; int i = 0, x = 0, y = 0, width, height; if (rotate) { xfact = (xe - xs) / 80.0; yfact = (ye - ys) / 100.0; width = (oye - oys) * xfact + .5; height = (oxe - oxs) * yfact + .5; if (rotate == CW) { x = oxs * xfact + xs + .5; y = oys * yfact + ys + .5; for (i = 0; i < sizeof(points) / sizeof(points[0]); i++) { points[i].x = lin[(i<<1) + 1] * xfact + xs + .5; points[i].y = lin[(i<<1)] * yfact + ys + .5; } } else if (rotate == CCW) { x = 10 * xfact + xs + .5; y = oys * yfact + ys + .5; for (i = 0; i < sizeof(points) / sizeof(points[0]); i++) { points[i].x = (-lin[(i<<1) + 1] + 80.0) * xfact + xs + .5; points[i].y = lin[(i<<1)] * yfact + ys + .5; } } } else { xfact = (xe - xs) / 100.0; yfact = (ye - ys) / 80.0; x = oxs * xfact + xs + .5; y = oys * yfact + ys + .5; width = (oxe - oxs) * xfact + .5; height = (oye - oys) * yfact + .5; for (i = 0; i < sizeof(points) / sizeof(points[0]); i++) { points[i].x = lin[(i<<1)] * xfact + xs + .5; points[i].y = lin[(i<<1) + 1] * yfact + ys + .5; } } /* rectangle */ XFillRectangle(dpy, win, gc, x, y, width, height); XFillPolygon(dpy, win, gc, points, i, Convex, CoordModeOrigin); } void AdjustScreenUI(void) { XF86ConfLayoutPtr lay = computer.layout; XF86ConfAdjacencyPtr adj; int i, dx, dy, x, y, w, h, base = -1; double xf, yf; if (lay == NULL) return; adj = lay->lay_adjacency_lst; #define USED1 -USED XtFree((XtPointer)mon_widths); XtFree((XtPointer)mon_heights); mon_widths = (int*)XtCalloc(1, sizeof(int) * columns); mon_heights = (int*)XtCalloc(1, sizeof(int) * rows); mon_width = mon_height = 0; for (i = 0; i < computer.num_screens; i++) { if (base == -1 && computer.screens[i]->state == USED) base = i; if (computer.screens[i]->screen->scrn_monitor->mon_width > mon_width) mon_width = computer.screens[i]->screen->scrn_monitor->mon_width; if (computer.screens[i]->screen->scrn_monitor->mon_height > mon_height) mon_height = computer.screens[i]->screen->scrn_monitor->mon_height; } if (base < 0) { for (i = 0; i < computer.num_screens; i++) ReshapeScreenWidget(computer.screens[i]); return; } if (mon_width == 0) { mon_width = 10; mon_height = 8; } XtUnmapWidget(work); while (adj) { xf86cfgScreen *scr = NULL, *topscr = NULL, *botscr = NULL, *lefscr = NULL, *rigscr = NULL; for (i = 0; i < computer.num_screens; i++) if (computer.screens[i]->screen == adj->adj_screen) break; if (i < computer.num_screens) scr = computer.screens[i]; if (adj->adj_top != NULL) { for (i = 0; i < computer.num_screens; i++) if (computer.screens[i]->screen == adj->adj_top) break; if (i < computer.num_screens) topscr = computer.screens[i]; } if (adj->adj_bottom != NULL) { for (i = 0; i < computer.num_screens; i++) if (computer.screens[i]->screen == adj->adj_bottom) break; if (i < computer.num_screens) botscr = computer.screens[i]; } if (adj->adj_left != NULL) { for (i = 0; i < computer.num_screens; i++) if (computer.screens[i]->screen == adj->adj_left) break; if (i < computer.num_screens) lefscr = computer.screens[i]; } if (adj->adj_right != NULL) { for (i = 0; i < computer.num_screens; i++) if (computer.screens[i]->screen == adj->adj_right) break; if (i < computer.num_screens) rigscr = computer.screens[i]; } if (lefscr == NULL && rigscr == NULL && topscr == NULL && lefscr == NULL) { XF86ConfScreenPtr s; if (adj->adj_where >= CONF_ADJ_RIGHTOF && adj->adj_where <= CONF_ADJ_BELOW) { s = xf86findScreen(adj->adj_refscreen, XF86Config->conf_screen_lst); for (i = 0; i < computer.num_screens; i++) if (computer.screens[i]->screen == s) break; if (i < computer.num_screens) { switch (adj->adj_where) { case CONF_ADJ_RIGHTOF: lefscr = computer.screens[i]; break; case CONF_ADJ_LEFTOF: rigscr = computer.screens[i]; break; case CONF_ADJ_ABOVE: botscr = computer.screens[i]; break; case CONF_ADJ_BELOW: topscr = computer.screens[i]; break; } } } } XtMoveWidget(scr->widget, 0, 0); scr->state = USED1; if (lefscr != NULL) { if (lefscr->state == USED1) XtMoveWidget(scr->widget, lefscr->widget->core.x + lefscr->widget->core.width, lefscr->widget->core.y); else XtMoveWidget(lefscr->widget, -(int)(lefscr->widget->core.width), scr->widget->core.y); } if (rigscr != NULL) { if (rigscr->state == USED1) { dx = rigscr->widget->core.x - scr->widget->core.width - scr->widget->core.x; dy = rigscr->widget->core.y - scr->widget->core.y; XtMoveWidget(scr->widget, scr->widget->core.x + dx, scr->widget->core.y + dy); if (lefscr != NULL && lefscr->state != USED1) XtMoveWidget(lefscr->widget, lefscr->widget->core.x + dx, lefscr->widget->core.y + dy); } else XtMoveWidget(rigscr->widget, scr->widget->core.width, scr->widget->core.y); } if (topscr != NULL) { if (topscr->state == USED1) { dx = topscr->widget->core.x - scr->widget->core.x; dy = topscr->widget->core.y + topscr->widget->core.height - scr->widget->core.y; XtMoveWidget(scr->widget, scr->widget->core.x + dx, scr->widget->core.y + dy); if (lefscr != NULL && lefscr->state != USED1) XtMoveWidget(lefscr->widget, lefscr->widget->core.x + dx, lefscr->widget->core.y + dy); if (rigscr != NULL && rigscr->state != USED1) XtMoveWidget(rigscr->widget, rigscr->widget->core.x + dx, rigscr->widget->core.y + dy); } else XtMoveWidget(topscr->widget, scr->widget->core.x, scr->widget->core.y - topscr->widget->core.height); } if (botscr != NULL) { if (botscr->state == USED1) { dx = botscr->widget->core.x - scr->widget->core.x; dy = botscr->widget->core.y - scr->widget->core.height - scr->widget->core.y; XtMoveWidget(scr->widget, scr->widget->core.x + dx, scr->widget->core.y + dy); if (lefscr != NULL && lefscr->state != USED1) XtMoveWidget(lefscr->widget, lefscr->widget->core.x + dx, lefscr->widget->core.y + dy); if (rigscr != NULL && rigscr->state != USED1) XtMoveWidget(rigscr->widget, rigscr->widget->core.x + dx, rigscr->widget->core.y + dy); if (botscr != NULL && botscr->state != USED1) XtMoveWidget(botscr->widget, botscr->widget->core.x + dx, botscr->widget->core.y + dy); } else XtMoveWidget(botscr->widget, scr->widget->core.x, scr->widget->core.y + scr->widget->core.height); } adj = (XF86ConfAdjacencyPtr)(adj->list.next); } for (i = 0; i < computer.num_screens; i++) if (computer.screens[i]->state == USED1) computer.screens[i]->state = USED; else XLowerWindow(XtDisplay(computer.screens[i]->widget), XtWindow(computer.screens[i]->widget)); w = work->core.width / (columns + 1) - 5; h = work->core.height / (rows + 1) - 5; if (w > h) w = h; else h = w; dx = (work->core.width - (columns * w)) >> 1; dy = (work->core.height - (rows * h)) >> 1; xf = (double)w / (double)computer.screens[0]->widget->core.width; yf = (double)h / (double)computer.screens[0]->widget->core.height; for (i = 0; i < computer.num_screens; i++) { Widget z = computer.screens[i]->widget; if (computer.screens[i]->state == USED) XtConfigureWidget(z, z->core.x * xf + dx, z->core.y * yf + dy, w, h, 0); else XtConfigureWidget(z, z->core.x, z->core.y, w, h, 0); } if (computer.screens[base]->row >= 0) { double xf, yf; int width, height; for (i = 0; i < computer.num_screens; i++) { width = computer.screens[i]->screen->scrn_monitor->mon_width; height = computer.screens[i]->screen->scrn_monitor->mon_height; if (width <= 0) { width = mon_width; height = mon_height; } if (computer.screens[i]->rotate) { xf = (double)width / (double)mon_width * 8. / 10.; yf = (double)height / (double)mon_height; } else { xf = (double)width / (double)mon_width; yf = (double)height / (double)mon_height * 8. / 10.; } width = computer.screens[i]->widget->core.width * xf; height = computer.screens[i]->widget->core.height * yf; if (computer.screens[i]->state == USED) { if (mon_widths[computer.screens[i]->column] < width) mon_widths[computer.screens[i]->column] = width; if (mon_heights[computer.screens[i]->row] < height) mon_heights[computer.screens[i]->row] = height; } /* do it here to avoid recalculation */ computer.screens[i]->rect.width = width; computer.screens[i]->rect.height = height; } } for (i = 0; i < computer.num_screens; i++) ReshapeScreenWidget(computer.screens[i]); /* do a new pass, to avoid gaps if the monitors have different * sizes. */ if (computer.screens[base]->row >= 0) { x = computer.screens[base]->widget->core.x; y = computer.screens[base]->widget->core.y; /* screens representations are already ordered */ for (i = base; i < computer.num_screens; i++) { if (computer.screens[i]->state == UNUSED) continue; if (computer.screens[i]->column != 0) x += mon_widths[computer.screens[i]->column]; else { x = computer.screens[base]->widget->core.x; if (i != base) y += mon_heights[computer.screens[i]->row]; } XtMoveWidget(computer.screens[i]->widget, x, y); } } XtMapWidget(work); } static int qcmp_screen(_Xconst void *a, _Xconst void *b) { xf86cfgScreen *s1, *s2; s1 = *(xf86cfgScreen**)a; s2 = *(xf86cfgScreen**)b; if (s1->widget->core.x > s2->widget->core.x) { if (s2->widget->core.y >= s1->widget->core.y + (s1->widget->core.height >> 1)) return (-1); return (1); } else { if (s1->widget->core.y >= s2->widget->core.y + (s2->widget->core.height >> 1)) return (1); return (-1); } /*NOTREACHED*/ } void UpdateScreenUI(void) { XF86ConfLayoutPtr lay = computer.layout; XF86ConfAdjacencyPtr adj, prev, left, base; int i, p, cols, scrno; if (lay == NULL) return; rows = columns = cols = 1; qsort(computer.screens, computer.num_screens, sizeof(xf86cfgScreen*), qcmp_screen); adj = prev = left = base = NULL; for (i = p = scrno = 0; i < computer.num_screens; i++) { XF86ConfScreenPtr scr = computer.screens[i]->screen; if (computer.screens[i]->state == UNUSED) continue; adj = (XF86ConfAdjacencyPtr)XtCalloc(1, sizeof(XF86ConfAdjacencyRec)); adj->adj_scrnum = scrno++; adj->adj_screen = scr; adj->adj_screen_str = XtNewString(scr->scrn_identifier); if (base == NULL) { base = left = adj; computer.screens[i]->row = computer.screens[i]->column = 0; } else { int dy = computer.screens[i]->widget->core.y - computer.screens[p]->widget->core.y; prev->list.next = adj; if (dy > (computer.screens[i]->widget->core.height >> 1)) { adj->adj_where = CONF_ADJ_BELOW; adj->adj_refscreen = XtNewString(left->adj_screen_str); left = adj; computer.screens[i]->row = rows; computer.screens[i]->column = 0; cols = 1; ++rows; } else { computer.screens[i]->row = rows - 1; computer.screens[i]->column = cols; adj->adj_where = CONF_ADJ_RIGHTOF; if (++cols > columns) columns = cols; adj->adj_refscreen = XtNewString(prev->adj_screen_str); } } prev = adj; p = i; } adj = lay->lay_adjacency_lst; while (adj != NULL) { prev = adj; adj = (XF86ConfAdjacencyPtr)(adj->list.next); XtFree(prev->adj_screen_str); XtFree(prev->adj_right_str); XtFree(prev->adj_left_str); XtFree(prev->adj_top_str); XtFree(prev->adj_bottom_str); XtFree(prev->adj_refscreen); XtFree((char*)prev); } lay->lay_adjacency_lst = base; }