/* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /********************************************************************* * FScreen.c * Xinerama abstraction support for window manager. * * This module is all original code * by Dmitry Yu. Bolkhovityanov * Copyright 2001, Dmitry Bolkhovityanov * You may use this code for any purpose, as long as the original * copyright remains in the source code and all documentation ********************************************************************/ /********************************************************************* * Brief description of used concept: * * This code is always used by client, regardless of if Xinerama is * available or not (either because -lXinerama was missing or * because Xinerama extension is missing on display). * * If Xinerama is available, this module maintains a list of screens, * from [1] to [num_screens]. screens[0] is always the "global" screen, * so if Xinerama is unavailable or disabled, the module performs * all checks on screens[0] instead of screens[1..num_screens]. * * The client should first call the FScreenInit(), passing * it the opened display descriptor. During this call the list of * Xinerama screens is retrieved and 'dpy' is saved for future * reference. * * If the client wishes to hard-disable Xinerama support (e.g. if * Xinerama extension is present but is broken on display), it should * call FScreenDisable() *before* FScreenInit(). * * Using real Xinerama screens info may be switched on/off "on the * fly" by calling FScreenSetState(0=off/else=on). * * Modules with Xinerama support should listen to the XineramaEnable * and XineramaDisable strings coming over the module pipe as * M_CONFIG_INFO packets and call FScreenEnable() or * FScreenDisable in response. * *********************************************************************/ #include "config.h" #include #include #include #include "defaults.h" #include "fvwmlib.h" #include "safemalloc.h" #include "FScreen.h" #ifdef HAVE_XINERAMA #include #else typedef struct { int screen_number; short x_org; short y_org; short width; short height; } XineramaScreenInfo; #endif #if 0 #ifdef HAVE_RANDR #include #include #endif #endif #ifndef DEBUG_PRINTS /* #define DEBUG_PRINTS 1 */ #endif enum { /* Replace with FSCREEN_GLOBAL to restore default behaviour */ DEFAULT_GEOMETRY_SCREEN = FSCREEN_PRIMARY }; /* In fact, only corners matter -- there will never be GRAV_NONE */ enum {GRAV_POS = 0, GRAV_NONE = 1, GRAV_NEG = 2}; static int grav_matrix[3][3] = { { NorthWestGravity, NorthGravity, NorthEastGravity }, { WestGravity, CenterGravity, EastGravity }, { SouthWestGravity, SouthGravity, SouthEastGravity } }; #define DEFAULT_GRAVITY NorthWestGravity static Display *disp = NULL; static Bool is_xinerama_enabled = DEFAULT_XINERAMA_ENABLED; static Bool is_sls_enabled = False; static XineramaScreenInfo *screens; static XineramaScreenInfo *screens_xi; static XineramaScreenInfo *screens_sls = NULL; /* # of Xinerama screens, *not* counting the global, 0 if disabled */ static int num_screens = 0; /* # of Xinerama screens, *not* counting the global */ static int total_screens = 0; static int total_screens_xi = 0; static int total_screens_sls = 1; static int total_sls_width = 1; static int total_sls_height = 1; static int first_to_check = 0; static int last_to_check = 0; static int default_geometry_scr = FSCREEN_PRIMARY; /* only to be accessed vie the set/get functions! */ static int primary_scr = DEFAULT_PRIMARY_SCREEN; #if 0 #ifdef HAVE_RANDR static Bool randr_disabled = 0; static Bool randr_active = 0; static int randr_event_base = -1; static int randr_error_base = -1; #endif #endif #ifdef USE_XINERAMA_EMULATION static Window blank_w, vert_w; #endif static int FScreenParseScreenBit(char *arg, char default_screen); static int FindScreenOfXY(int x, int y); static void GetMouseXY(XEvent *eventp, int *x, int *y) { if (!is_xinerama_enabled || last_to_check == first_to_check) { /* We use .x_org,.y_org because nothing prevents a screen to be not at * (0,0) */ *x = screens[first_to_check].x_org; *y = screens[first_to_check].y_org; } else { XEvent e; if (eventp == NULL) { eventp = &e; e.type = 0; } GetLocationFromEventOrQuery(disp, DefaultRootWindow(disp), eventp, x, y); } return; } Bool FScreenIsEnabled(void) { return (!is_xinerama_enabled || num_screens == 0) ? False : True; } Bool FScreenIsSLSEnabled(void) { return is_sls_enabled; } #ifdef USE_XINERAMA_EMULATION static void FScreenUpdateEmulationMapState(void) { static Bool is_mapped = False; if (is_xinerama_enabled && !is_sls_enabled) { if (!is_mapped) { XMapRaised(disp, blank_w); XMapRaised(disp, vert_w); is_mapped = True; } } else { if (is_mapped) { XUnmapWindow(disp, blank_w); XUnmapWindow(disp, vert_w); is_mapped = False; } } } #endif static void FScreenSetState(Bool do_enable) { is_xinerama_enabled = do_enable; if (do_enable && total_screens > 0) { num_screens = total_screens; first_to_check = 1; last_to_check = total_screens; } else { num_screens = 0; first_to_check = 0; last_to_check = 0; } #ifdef USE_XINERAMA_EMULATION FScreenUpdateEmulationMapState(); #endif } void FScreenInit(Display *dpy) { static Bool is_initialised = False; #ifdef HAVE_XINERAMA int dummy_rc; #endif if (is_initialised) return; is_initialised = True; disp = dpy; #ifdef USE_XINERAMA_EMULATION if (True) { int count; int w; int h; int ws; unsigned long scr; Window root; XSetWindowAttributes attributes; scr = DefaultScreen(disp); root = RootWindow(disp, scr); /* xinerama emulation simulates xinerama on a single screen: * * actual screen * +---------------------+--------------+ * | | | * | | | * | | | * | | simulated | * | | screen 2 | * | simulated screen 1 | | * | | | * | | | * | | | * | | | * +---------------------+ | * | blank area | | * | | | * +---------------------+--------------+ */ count = 2; total_screens_xi = count; screens_xi = (XineramaScreenInfo *) safemalloc(sizeof(XineramaScreenInfo) * (1 + count)); /* calculate the faked sub screen dimensions */ w = DisplayWidth(disp, scr); ws = 3 * w / 5; h = DisplayHeight(disp, scr); screens_xi[1].screen_number = 0; screens_xi[1].x_org = 0; screens_xi[1].y_org = 0; screens_xi[1].width = ws; screens_xi[1].height = 7 * h / 8; screens_xi[2].screen_number = 1; screens_xi[2].x_org = ws; screens_xi[2].y_org = 0; screens_xi[2].width = w - ws; screens_xi[2].height = h; /* add delimiter */ attributes.background_pixel = WhitePixel(disp, scr); attributes.override_redirect = True; blank_w = XCreateWindow( disp, root, 0, 7 * h / 8 - 1, ws, 2, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWBackPixel|CWOverrideRedirect, &attributes); vert_w = XCreateWindow( disp, root, ws - 1, 0, 2, h, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWBackPixel|CWOverrideRedirect, &attributes); } else #endif #ifdef HAVE_XINERAMA if (XineramaQueryExtension(disp, &dummy_rc, &dummy_rc) && XineramaIsActive(disp)) { int count; XineramaScreenInfo *info; info = XineramaQueryScreens(disp, &count); total_screens_xi = count; screens_xi = (XineramaScreenInfo *) safemalloc(sizeof(XineramaScreenInfo) * (1 + count)); memcpy(screens_xi + 1, info, sizeof(XineramaScreenInfo) * count); XFree(info); } else #endif { total_screens_xi = 0; screens_xi = (XineramaScreenInfo *)safemalloc(sizeof(XineramaScreenInfo)*1); } total_screens = total_screens_xi; screens = screens_xi; /* Now, fill screens[0] with global screen parameters */ screens_xi[0].screen_number = -1; screens_xi[0].x_org = 0; screens_xi[0].y_org = 0; screens_xi[0].width = DisplayWidth (disp, DefaultScreen(disp)); screens_xi[0].height = DisplayHeight(disp, DefaultScreen(disp)); /* Fill in the screen range */ FScreenSetState(is_xinerama_enabled); return; } void FScreenOnOff(Bool do_enable) { FScreenSetState(do_enable); } void FScreenSLSOnOff(Bool do_enable) { is_sls_enabled = do_enable; if (do_enable) { total_screens = total_screens_sls; if (!screens_sls) { /* Sls not configured yet, use whole screen by default */ FScreenConfigureSLS(1, 1); } screens = screens_sls; } else { total_screens = total_screens_xi; screens = screens_xi; } FScreenSetState(is_xinerama_enabled); } Bool FScreenConfigureSLS(int width, int height) { unsigned long scr = DefaultScreen(disp); int w = DisplayWidth(disp, scr); int h = DisplayHeight(disp, scr); if (width <= 1) { width = 1; } else if (width > w) { width = w; } if (height <= 1) { height = 1; } else if (height > h) { height = h; } if (total_sls_width == width && total_sls_height == height && screens_sls) { return False; } if (screens_sls) { free(screens_sls); screens_sls = NULL; } /* calculate the screens */ { int row, col, sn; int ws; int hs; total_screens_sls = width * height; total_sls_width = width; total_sls_height = height; ws = w / total_sls_width; hs = h / total_sls_height; screens_sls = (XineramaScreenInfo *) safemalloc(sizeof(XineramaScreenInfo) * (1 + total_screens_sls)); /* calculate the faked sub screen dimensions */ screens_sls[0] = screens_xi[0]; sn = 1; for (row = 0; row < total_sls_height; row++) { for (col = 0; col < total_sls_width; col++) { screens_sls[sn].screen_number = sn - 1; screens_sls[sn].x_org = col * ws; screens_sls[sn].y_org = row * hs; screens_sls[sn].width = ws; screens_sls[sn].height = hs; sn++; } } } FScreenSLSOnOff(is_sls_enabled); return True; } #if 0 void FScreenDisableRandR(void) { if (disp != NULL) { fprintf(stderr, "FScreen: WARNING: FScreenDisableRandR()" " called after FScreenInit()!\n"); } randr_disabled = 1; } #endif static int FScreenGetPrimaryScreen(XEvent *ev) { if (!is_xinerama_enabled) { return 0; } if (primary_scr == FSCREEN_GLOBAL) { return 0; } else if (primary_scr == FSCREEN_CURRENT) { int mx; int my; /* use current screen as primary screen */ GetMouseXY(ev, &mx, &my); return FindScreenOfXY(mx, my); } else if (primary_scr < 0 || primary_scr >= last_to_check) { /* out of range */ return 0; } return primary_scr + 1; } void FScreenSetPrimaryScreen(int scr) { primary_scr = scr; } /* Intended to be called by modules. Simply pass in the parameter from the * config string sent by fvwm. */ void FScreenConfigureModule(char *args) { int val[5]; int n; n = GetIntegerArguments(args, NULL, val, 5); if (n != 5) { /* ignore broken line */ return; } FScreenSetPrimaryScreen(val[1]); FScreenConfigureSLS(val[3], val[4]); FScreenSLSOnOff(val[2]); FScreenOnOff(val[0]); return; } /* Here's the function used by FVWM to generate the string which * FScreenConfigureModule expects to receive back as its argument. */ const char *FScreenGetConfiguration(void) { static char msg[200]; sprintf( msg, XINERAMA_CONFIG_STRING" %d %d %d %d %d", FScreenIsEnabled(), primary_scr, FScreenIsSLSEnabled(), total_sls_width, total_sls_height); return msg; } /* Sets the default screen for ...ParseGeometry if no screen spec is given. * Usually this is FSCREEN_SPEC_PRIMARY, but this won't allow modules to appear * under the pointer. */ void FScreenSetDefaultModuleScreen(char *scr_spec) { default_geometry_scr = FScreenParseScreenBit(scr_spec, FSCREEN_SPEC_PRIMARY); } static int FindScreenOfXY(int x, int y) { int i; for (i = first_to_check; i <= last_to_check; i++) { if (x >= screens[i].x_org && x < screens[i].x_org + screens[i].width && y >= screens[i].y_org && y < screens[i].y_org + screens[i].height) { return i; } } /* Ouch! A "black hole" coords? As for now, return global screen */ return 0; } /* Returns the specified screens geometry rectangle. screen can be a screen * number or any of the values FSCREEN_GLOBAL, FSCREEN_CURRENT, * FSCREEN_PRIMARY or FSCREEN_XYPOS. The arg union only has a meaning for * FSCREEN_CURRENT and FSCREEN_XYARG. For FSCREEN_CURRENT its mouse_ev member * may be given. It is tried to find out the pointer position from the event * first before querying the pointer. For FSCREEN_XYPOS the xpos member is used * to fetch the x/y position of the point on the screen. If arg is NULL, the * position 0 0 is assumed instead. * * Any of the arguments arg, x, y, w and h may be NULL. * * FSCREEN_GLOBAL: return the global screen dimensions * FSCREEN_CURRENT: return dimensions of the screen with the pointer * FSCREEN_PRIMARY: return the primary screen dimensions * FSCREEN_XYPOS: return dimensions of the screen with the given coordinates * * The function returns False if the global screen was returned and more than * one screen is configured. Otherwise it returns True. */ Bool FScreenGetScrRect( fscreen_scr_arg *arg, int screen, int *x, int *y, int *w, int *h) { fscreen_scr_arg tmp; if (num_screens == 0) { screen = FSCREEN_GLOBAL; } switch (screen) { case FSCREEN_GLOBAL: screen = 0; break; case FSCREEN_PRIMARY: screen = FScreenGetPrimaryScreen((arg && arg->mouse_ev) ? arg->mouse_ev : NULL); break; case FSCREEN_CURRENT: /* translate to xypos format */ if (!arg) { tmp.mouse_ev = NULL; arg = &tmp; } GetMouseXY(arg->mouse_ev, &arg->xypos.x, &arg->xypos.y); /* fall through */ case FSCREEN_XYPOS: /* translate to screen number */ if (!arg) { tmp.xypos.x = 0; tmp.xypos.y = 0; arg = &tmp; } screen = FindScreenOfXY(arg->xypos.x, arg->xypos.y); break; default: /* screen is given counting from 0; translate to counting from 1 */ screen++; break; } if (screen < first_to_check || screen > last_to_check) { screen = 0; } if (x) { *x = screens[screen].x_org; } if (y) { *y = screens[screen].y_org; } if (w) { *w = screens[screen].width; } if (h) { *h = screens[screen].height; } return !(screen == 0 && num_screens > 1); } /* Translates the coodinates *x *y from the screen specified by arg_src and * screen_src to coordinates on the screen specified by arg_dest and * screen_dest. (see FScreenGetScrRect for more details). */ void FScreenTranslateCoordinates( fscreen_scr_arg *arg_src, int screen_src, fscreen_scr_arg *arg_dest, int screen_dest, int *x, int *y) { int x_src; int y_src; int x_dest; int y_dest; FScreenGetScrRect(arg_src, screen_src, &x_src, &y_src, NULL, NULL); FScreenGetScrRect(arg_dest, screen_dest, &x_dest, &y_dest, NULL, NULL); if (x) { *x = *x + x_src - x_dest; } if (y) { *y = *y + y_src - y_dest; } return; } /* Arguments work exactly like for FScreenGetScrRect() */ int FScreenClipToScreen( fscreen_scr_arg *arg, int screen, int *x, int *y, int w, int h) { int sx; int sy; int sw; int sh; int lx = (x) ? *x : 0; int ly = (y) ? *y : 0; int x_grav = GRAV_POS; int y_grav = GRAV_POS; FScreenGetScrRect(arg, screen, &sx, &sy, &sw, &sh); if (lx + w > sx + sw) { lx = sx + sw - w; x_grav = GRAV_NEG; } if (ly + h > sy + sh) { ly = sy + sh - h; y_grav = GRAV_NEG; } if (lx < sx) { lx = sx; x_grav = GRAV_POS; } if (ly < sy) { ly = sy; y_grav = GRAV_POS; } if (x) { *x = lx; } if (y) { *y = ly; } return grav_matrix[y_grav][x_grav]; } /* Arguments work exactly like for FScreenGetScrRect() */ void FScreenCenterOnScreen( fscreen_scr_arg *arg, int screen, int *x, int *y, int w, int h) { int sx; int sy; int sw; int sh; int lx; int ly; FScreenGetScrRect(arg, screen, &sx, &sy, &sw, &sh); lx = (sw - w) / 2; ly = (sh - h) / 2; if (lx < 0) lx = 0; if (ly < 0) ly = 0; lx += sx; ly += sy; if (x) { *x = lx; } if (y) { *y = ly; } return; } void FScreenGetResistanceRect(int wx, int wy, int ww, int wh, int *x0, int *y0, int *x1, int *y1) { int scr; int sx0, sy0, sx1, sy1; /* Assign initial far-out-of-screen values */ *x0 = 32767; *y0 = 32767; *x1 = -32768; *y1 = -32768; /* Convert size to 2-nd edge coords */ ww += wx; wh += wy; for (scr = first_to_check; scr <= last_to_check; scr++) { sx0 = screens[scr].x_org; sy0 = screens[scr].y_org; sx1 = screens[scr].width + sx0; sy1 = screens[scr].height + sy0; /* Take this screen into account only if it intersects with the window. Otherwise this algorithm would behave badly in case of non-regularly-tiled screens (i.e. when they don't form a regular grid). */ if (sx0 < ww && sx1 > wx && sy0 < wh && sy1 > wy) { if (sx0 >= wx && sx0 - wx < *x0 - wx) *x0 = sx0; if (sy0 >= wy && sy0 - wy < *y0 - wy) *y0 = sy0; if (sx1 <= ww && ww - sx1 < ww - *x1) *x1 = sx1; if (sy1 <= wh && wh - sy1 < wh - *y1) *y1 = sy1; } } } /* Arguments work exactly like for FScreenGetScrRect() */ Bool FScreenIsRectangleOnScreen( fscreen_scr_arg *arg, int screen, rectangle *rec) { int sx; int sy; int sw; int sh; FScreenGetScrRect(arg, screen, &sx, &sy, &sw, &sh); return (rec->x + rec->width > sx && rec->x < sx + sw && rec->y + rec->height > sy && rec->y < sy + sh) ? True : False; } static int FScreenParseScreenBit(char *scr_spec, char default_screen) { int scr = default_geometry_scr; char c; c = (scr_spec) ? tolower(*scr_spec) : tolower(default_screen); if (c == FSCREEN_SPEC_GLOBAL) scr = FSCREEN_GLOBAL; else if (c == FSCREEN_SPEC_CURRENT) scr = FSCREEN_CURRENT; else if (c == FSCREEN_SPEC_PRIMARY) scr = FSCREEN_PRIMARY; else if (c == FSCREEN_SPEC_WINDOW) scr = FSCREEN_XYPOS; else if (isdigit(c)) scr = atoi(scr_spec); else { c = tolower(default_screen); if (c == FSCREEN_SPEC_GLOBAL) scr = FSCREEN_GLOBAL; else if (c == FSCREEN_SPEC_CURRENT) scr = FSCREEN_CURRENT; else if (c == FSCREEN_SPEC_PRIMARY) scr = FSCREEN_PRIMARY; else if (c == FSCREEN_SPEC_WINDOW) scr = FSCREEN_XYPOS; else if (isdigit(c)) scr = atoi(scr_spec); } return scr; } int FScreenGetScreenArgument(char *scr_spec, char default_screen) { while (scr_spec && isspace(*scr_spec)) scr_spec++; return FScreenParseScreenBit(scr_spec, default_screen); } /* * FScreenParseGeometry * Does the same as XParseGeometry, but handles additional "@scr". * Since it isn't safe to define "ScreenValue" constant (actual values * of other "XXXValue" are specified in Xutil.h, not by us, so there can * be a clash), the screen value is always returned, event if it wasn't * present in `parse_string' (set to default in that case). * */ int FScreenParseGeometryWithScreen( char *parsestring, int *x_return, int *y_return, unsigned int *width_return, unsigned int *height_return, int *screen_return) { int ret; char *copy, *scr_p; int s_size; int scr; /* Safety net */ if (parsestring == NULL || *parsestring == '\0') return 0; /* Make a local copy devoid of "@scr" */ s_size = strlen(parsestring) + 1; copy = safemalloc(s_size); memcpy(copy, parsestring, s_size); scr_p = strchr(copy, '@'); if (scr_p != NULL) *scr_p++ = '\0'; /* Do the parsing */ ret = XParseGeometry(copy, x_return, y_return, width_return, height_return); #if DEBUG_PRINTS fprintf(stderr, "copy=%s, scr_p=%s, x=%d, y=%d, w=%d, h=%d, flags:%s%s%s%s%s%s\n", copy, (scr_p)?scr_p:"(null)", *x_return, *y_return, *width_return, *height_return, ret&XValue? " XValue":"", ret&YValue? " YValue":"", ret&WidthValue? " WidthValue":"", ret&HeightValue? " HeightValue":"", ret&XNegative? " XNegative":"", ret&YNegative? " YNegative":""); #endif /* Parse the "@scr", if any */ scr = FScreenParseScreenBit(scr_p, FSCREEN_SPEC_PRIMARY); *screen_return = scr; /* We don't need the string any more */ free(copy); return ret; } /* Same as above, but dump screen return value to keep compatible with the X * function. */ int FScreenParseGeometry( char *parsestring, int *x_return, int *y_return, unsigned int *width_return, unsigned int *height_return) { int scr; int rc; int mx; int my; rc = FScreenParseGeometryWithScreen( parsestring, x_return, y_return, width_return, height_return, &scr); switch (scr) { case FSCREEN_GLOBAL: scr = 0; break; case FSCREEN_CURRENT: GetMouseXY(NULL, &mx, &my); scr = FindScreenOfXY(mx, my); break; case FSCREEN_PRIMARY: scr = FScreenGetPrimaryScreen(NULL); break; default: scr++; break; } if (scr <= 0 || scr > last_to_check) { scr = 0; } else { /* adapt geometry to selected screen */ if (rc & XValue) { if (rc & XNegative) { *x_return -= (screens[0].width - screens[scr].width - screens[scr].x_org); } else { *x_return += screens[scr].x_org; } } if (rc & YValue) { if (rc & YNegative) { *y_return -= (screens[0].height - screens[scr].height - screens[scr].y_org); } else { *y_return += screens[scr].y_org; } } } #if DEBUG_PRINTS fprintf(stderr, "*** xpg: x=%d, y=%d, w=%d, h=%d, flags:%s%s%s%s%s%s\n", *x_return, *y_return, *width_return, *height_return, rc&XValue? " XValue":"", rc&YValue? " YValue":"", rc&WidthValue? " WidthValue":"", rc&HeightValue? " HeightValue":"", rc&XNegative? " XNegative":"", rc&YNegative? " YNegative":""); #endif return rc; } /* FScreenGetGeometry * Parses the geometry in a form: XGeometry[@screen], i.e. * [=][{xX}][{+-}{+-}][@] * where is either a number or "G" (global) "C" (current) * or "P" (primary) * * Args: * parsestring, x_r, y_r, w_r, h_r the same as in XParseGeometry * hints window hints structure, may be NULL * flags bitmask of allowed flags (XValue, WidthValue, XNegative...) * * Note1: * hints->width and hints->height will be used to calc negative geometry * if width/height isn't specified in the geometry itself. * * Note2: * This function's behaviour is crafted to sutisfy/emulate the * FvwmWinList::MakeMeWindow()'s behaviour. * * Note3: * A special value of `flags' when [XY]Value are there but [XY]Negative * aren't, means that in case of negative geometry specification * x_r/y_r values will be promoted to the screen border, but w/h * wouldn't be subtracted, so that the program can do x-=w later * ([XY]Negative *will* be returned, albeit absent in `flags'). * This option is supposed for proggies like FvwmButtons, which * receive geometry specification long before they are able to actually * use it (and which calculate w/h themselves). * (The same effect can't be obtained with omitting {Width,Height}Value * in the flags, since the app may wish to get the dimensions but apply * some constraints later (as FvwmButtons do, BTW...).) * This option can be also useful in cases where dimensions are * specified not in pixels but in some other units (e.g., charcells). */ int FScreenGetGeometry( char *parsestring, int *x_return, int *y_return, int *width_return, int *height_return, XSizeHints *hints, int flags) { int ret; int saved; int x, y, w=0, h=0; int grav, x_grav, y_grav; int scr = default_geometry_scr; int scr_x, scr_y, scr_w, scr_h; /* I. Do the parsing and strip off extra bits */ ret = FScreenParseGeometryWithScreen(parsestring, &x, &y, &w, &h, &scr); saved = ret & (XNegative | YNegative); ret &= flags; /* II. Get the screen rectangle */ switch (scr) { case FSCREEN_GLOBAL: case FSCREEN_CURRENT: case FSCREEN_PRIMARY: case FSCREEN_XYPOS: FScreenGetScrRect(NULL, scr, &scr_x, &scr_y, &scr_w, &scr_h); break; default: scr++; if (scr < first_to_check || scr > last_to_check) scr = first_to_check; scr_x = screens[scr].x_org; scr_y = screens[scr].y_org; scr_w = screens[scr].width; scr_h = screens[scr].height; } #if DEBUG_PRINTS fprintf(stderr, "scr=%d, (%d,%d,%d,%d)\n", scr, scr_x, scr_y, scr_w, scr_h); #endif /* III. Interpret and fill in the values */ /* Fill in dimensions for future negative calculations if * omitted/forbidden */ /* Maybe should use *x_return,*y_return if hints==NULL? Unreliable... */ if (hints != NULL && hints->flags & PSize) { if ((ret & WidthValue) == 0) w = hints->width; if ((ret & HeightValue) == 0) h = hints->height; } else { /* This branch is required for case when size *is* specified, but masked * off */ if ((ret & WidthValue) == 0) w = 0; if ((ret & HeightValue) == 0) h = 0; } #if DEBUG_PRINTS fprintf(stderr, "PRE: x=%d, y=%d, w=%d, h=%d, flags:%s%s%s%s%s%s\n", x, y, w, h, ret&XValue? " XValue":"", ret&YValue? " YValue":"", ret&WidthValue? " WidthValue":"", ret&HeightValue? " HeightValue":"", ret&XNegative? " XNegative":"", ret&YNegative? " YNegative":""); #endif /* Advance coords to the screen... */ x += scr_x; y += scr_y; /* ...and process negative geometries */ if (saved & XNegative) x += scr_w; if (saved & YNegative) y += scr_h; if (ret & XNegative) x -= w; if (ret & YNegative) y -= h; /* Restore negative bits */ ret |= saved; /* Guess orientation */ x_grav = (ret & XNegative)? GRAV_NEG : GRAV_POS; y_grav = (ret & YNegative)? GRAV_NEG : GRAV_POS; grav = grav_matrix[y_grav][x_grav]; /* Return the values */ if (ret & XValue) { *x_return = x; if (hints != NULL) hints->x = x; } if (ret & YValue) { *y_return = y; if (hints != NULL) hints->y = y; } if (ret & WidthValue) { *width_return = w; if (hints != NULL) hints->width = w; } if (ret & HeightValue) { *height_return = h; if (hints != NULL) hints->height = h; } if (1 /*flags & GravityValue*/ && grav != DEFAULT_GRAVITY) { if (hints != NULL && hints->flags & PWinGravity) hints->win_gravity = grav; } if (hints != NULL && ret & XValue && ret & YValue) hints->flags |= USPosition; #if DEBUG_PRINTS fprintf(stderr, "x=%d, y=%d, w=%d, h=%d, flags:%s%s%s%s%s%s\n", x, y, w, h, ret&XValue? " XValue":"", ret&YValue? " YValue":"", ret&WidthValue? " WidthValue":"", ret&HeightValue? " HeightValue":"", ret&XNegative? " XNegative":"", ret&YNegative? " YNegative":""); #endif return ret; } /* no rand_r for now */ # if 0 int FScreenGetRandrEventType(void) { #ifdef HAVE_RANDR return randr_active? randr_event_base + RRScreenChangeNotify : 0; #else return 0; #endif } Bool FScreenHandleRandrEvent( XEvent *event, int *old_w, int *old_h, int *new_w, int *new_h) { #ifndef HAVE_RANDR return 0; #else XRRScreenChangeNotifyEvent *ev = (XRRScreenChangeNotifyEvent *)event; int nw, nh, tmp; if (!randr_active || event->type != randr_event_base + RRScreenChangeNotify) { return 0; } nw = ev->width; nh = ev->height; /* * Note1: this check is not very good, since the right way is to * obtain a list of possible rotations and ... * * Note2: as to WM's point of view, I'm unsure if rotation should be * treated exactly as resizing (i.e. that it should reposition * windows in the same fashion). */ if (ev->rotation & (1<<1 | 1<<3)) { tmp = nw; nw = nh; nh = tmp; } *old_w = screens[0].width; *old_h = screens[0].height; screens[0].width = nw; *new_w = nw; screens[0].height = nh; *new_h = nh; #ifdef DEBUG_PRINTS fprintf(stderr, "HandleRandrEvent(): rot=%d, old=%d*%d, new=%d*%d, d=%d*%d\n", ev->rotation, *old_w, *old_h, *new_w, *new_h, DisplayWidth(disp, DefaultScreen(disp)), DisplayHeight(disp, DefaultScreen(disp))); #endif return (nw != *old_w || nh != *old_h); #endif } #endif