diff options
Diffstat (limited to 'src/newt/native/xrandr_utils.c')
-rw-r--r-- | src/newt/native/xrandr_utils.c | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/src/newt/native/xrandr_utils.c b/src/newt/native/xrandr_utils.c new file mode 100644 index 000000000..564fdd44b --- /dev/null +++ b/src/newt/native/xrandr_utils.c @@ -0,0 +1,322 @@ +/** + * This file contains code from xrandr.c, + * see <http://cgit.freedesktop.org/xorg/app/xrandr/tree/xrandr.c>: + * + * ++++ + * + * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. + * Copyright © 2002 Hewlett Packard Company, Inc. + * Copyright © 2006 Intel Corporation + * Copyright © 2013 NVIDIA Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Thanks to Jim Gettys who wrote most of the client side code, + * and part of the server code for randr. + * + * ++++ + * + * Modifications / Additions are from: + * + * Copyright 2015 JogAmp Community. All rights reserved. + * + * License text: Same as above! + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include "X11Common.h" + +#include <math.h> + +typedef struct { + int x1, y1, x2, y2; +} box_t; +typedef struct { + int x, y; +} point_t; +typedef struct { + XTransform transform; + char *filter; + int nparams; + XFixed *params; +} transform_t; +typedef struct _crtc { + struct _crtc *next; + RRCrtc crtc_id; + Rotation rotation; + transform_t transform; + int x, y; + RRMode mode_id; + // float refresh; + // Bool primary; + + XRRModeInfo *mode_info; + XRRCrtcInfo *crtc_info; + XRRPanning *panning_info; +} crtc_t; +static int mode_height (XRRModeInfo *mode_info, Rotation rotation) { + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode_info->height; + case RR_Rotate_90: + case RR_Rotate_270: + return mode_info->width; + default: + return 0; + } +} +static int mode_width (XRRModeInfo *mode_info, Rotation rotation) { + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode_info->width; + case RR_Rotate_90: + case RR_Rotate_270: + return mode_info->height; + default: + return 0; + } +} +static Bool transform_point (XTransform *transform, double *xp, double *yp) { + double vector[3]; + double result[3]; + int i, j; + double v; + + vector[0] = *xp; + vector[1] = *yp; + vector[2] = 1; + for (j = 0; j < 3; j++) + { + v = 0; + for (i = 0; i < 3; i++) { + v += (XFixedToDouble (transform->matrix[j][i]) * vector[i]); + } + if (v > 32767 || v < -32767) { + return False; + } + result[j] = v; + } + if (!result[2]) { + return False; + } + for (j = 0; j < 2; j++) { + vector[j] = result[j] / result[2]; + } + *xp = vector[0]; + *yp = vector[1]; + return True; +} +static void path_bounds (XTransform *transform, point_t *points, int npoints, box_t *box) { + int i; + box_t point; + + for (i = 0; i < npoints; i++) { + double x, y; + x = points[i].x; + y = points[i].y; + transform_point (transform, &x, &y); + point.x1 = floor (x); + point.y1 = floor (y); + point.x2 = ceil (x); + point.y2 = ceil (y); + if (i == 0) { + *box = point; + } else { + if (point.x1 < box->x1) { box->x1 = point.x1; } + if (point.y1 < box->y1) { box->y1 = point.y1; } + if (point.x2 > box->x2) { box->x2 = point.x2; } + if (point.y2 > box->y2) { box->y2 = point.y2; } + } + } +} +static void mode_geometry (XRRModeInfo *mode_info, Rotation rotation, + XTransform *transform, box_t *bounds) { + point_t rect[4]; + int width = mode_width (mode_info, rotation); + int height = mode_height (mode_info, rotation); + + rect[0].x = 0; + rect[0].y = 0; + rect[1].x = width; + rect[1].y = 0; + rect[2].x = width; + rect[2].y = height; + rect[3].x = 0; + rect[3].y = height; + path_bounds (transform, rect, 4, bounds); +} +static void get_screen_size0(Display * dpy, Window root, + crtc_t * root_crtc, int *io_scrn_width, int *io_scrn_height) { + int fb_width = *io_scrn_width; + int fb_height = *io_scrn_height; + crtc_t *crtc; + for (crtc = root_crtc; NULL != crtc; crtc = crtc->next) { + if( None == crtc->mode_id || NULL == crtc->mode_info || 0 == crtc->crtc_info->noutput ) { + // disabled + continue; + } + XRRModeInfo *mode_info = crtc->mode_info; + int x, y, w, h; + box_t bounds; + + mode_geometry (mode_info, crtc->rotation, + &crtc->transform.transform, &bounds); + x = crtc->x + bounds.x1; + y = crtc->y + bounds.y1; + w = bounds.x2 - bounds.x1; + h = bounds.y2 - bounds.y1; + + /* fit fb to crtc */ + XRRPanning *pan; + if (x + w > fb_width) { + fb_width = x + w; + } + if (y + h > fb_height) { + fb_height = y + h; + } + pan = crtc->panning_info; + if (pan && pan->left + pan->width > fb_width) { + fb_width = pan->left + pan->width; + } + if (pan && pan->top + pan->height > fb_height) { + fb_height = pan->top + pan->height; + } + } + int minWidth=0, minHeight=0, maxWidth=0, maxHeight=0; + if( 1 != XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, &maxWidth, &maxHeight) ) { + // Use defaults in case of error .. + minWidth=8; minHeight=8; maxWidth=16384; maxHeight=16384; + } + if( fb_width < minWidth ) { + fb_width = minWidth; + } else if( fb_width > maxWidth ) { + fb_width = maxWidth; + } + if( fb_height < minHeight ) { + fb_height = minHeight; + } else if( fb_height > maxHeight ) { + fb_height = maxHeight; + } + *io_scrn_width = fb_width; + *io_scrn_height = fb_height; +} +static crtc_t* createCrtcChain(Display *dpy, + XRRScreenResources *resources, + RRCrtc customCrtc, XRRCrtcInfo *customCrtcInfo, + Rotation customRotation, int customX, int customY, + XRRModeInfo *customModeInfo) +{ + crtc_t *root_crtc = NULL; + crtc_t *iter_crtc = NULL; + int i; + for(i=0; i<resources->ncrtc; i++) { + crtc_t *next_crtc = calloc(1, sizeof(crtc_t)); + if( NULL == iter_crtc ) { + root_crtc = next_crtc; + } else { + iter_crtc->next = next_crtc; + } + iter_crtc = next_crtc; + + RRCrtc crtcId = resources->crtcs[i]; + iter_crtc->crtc_id = crtcId; + if( crtcId == customCrtc && 0 != customCrtc ) { + iter_crtc->rotation = customRotation; + iter_crtc->x = customX; + iter_crtc->y = customY; + iter_crtc->mode_info = customModeInfo; + iter_crtc->mode_id = customModeInfo->id; + iter_crtc->crtc_info = customCrtcInfo; + } else { + XRRCrtcInfo *xrrCrtcInfo = XRRGetCrtcInfo (dpy, resources, crtcId); + iter_crtc->rotation = xrrCrtcInfo->rotation; + iter_crtc->x = xrrCrtcInfo->x; + iter_crtc->y = xrrCrtcInfo->y; + iter_crtc->mode_id = xrrCrtcInfo->mode; + iter_crtc->mode_info = findMode(resources, iter_crtc->mode_id); + iter_crtc->crtc_info = xrrCrtcInfo; + } + iter_crtc->panning_info = XRRGetPanning(dpy, resources, crtcId); + } + return root_crtc; +} +static void destroyCrtcChain(crtc_t *root_crtc, RRCrtc customCrtc) { + crtc_t * iter_crtc = root_crtc; + while(NULL!=iter_crtc) { + if( NULL != iter_crtc->crtc_info ) { + if( iter_crtc->crtc_id != customCrtc || 0 == customCrtc ) { + XRRFreeCrtcInfo(iter_crtc->crtc_info); + } + iter_crtc->crtc_info = NULL; + } + if( NULL != iter_crtc->panning_info ) { + XRRFreePanning(iter_crtc->panning_info); + iter_crtc->panning_info = NULL; + } + { + crtc_t * last = iter_crtc; + iter_crtc = iter_crtc->next; + last->next = NULL; + free(last); + } + } +} +static crtc_t *get_screen_size1(Display * dpy, Window root, + int *io_scrn_width, int *io_scrn_height, + XRRScreenResources *resources, + RRCrtc customCrtc, XRRCrtcInfo *customCrtcInfo, + Rotation customRotation, int customX, int customY, + XRRModeInfo *customModeInfo) { + crtc_t *root_crtc = createCrtcChain(dpy, resources, customCrtc, customCrtcInfo, + customRotation, customX, customY, customModeInfo); + get_screen_size0(dpy, root, root_crtc, io_scrn_width, io_scrn_height); + return root_crtc; +} +static crtc_t *get_screen_size2(Display * dpy, Window root, + int *io_scrn_width, int *io_scrn_height, + XRRScreenResources *resources) { + crtc_t *root_crtc = createCrtcChain(dpy, resources, 0, NULL, 0, 0, 0, NULL); + get_screen_size0(dpy, root, root_crtc, io_scrn_width, io_scrn_height); + return root_crtc; +} +static Bool get_screen_sizemm(Display *dpy, int screen_idx, + int fb_width, int fb_height, + int *fb_width_mm, int *fb_height_mm, + int *pre_fb_width, int *pre_fb_height) { + *pre_fb_width = DisplayWidth (dpy, screen_idx); + *pre_fb_height = DisplayHeight (dpy, screen_idx); + Bool fb_change; + if (fb_width != *pre_fb_width || fb_height != *pre_fb_height ) { + float dpi = (25.4 * *pre_fb_height) / DisplayHeightMM(dpy, screen_idx); + *fb_width_mm = (25.4 * fb_width) / dpi; + *fb_height_mm = (25.4 * fb_height) / dpi; + fb_change = True; + } else { + *fb_width_mm = DisplayWidthMM (dpy, screen_idx); + *fb_height_mm = DisplayHeightMM (dpy, screen_idx); + fb_change = False; + } + return fb_change; +} + |