From 2c88b6dfd4eb7e2cd9a50fa48e08ecafc980931a Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Fri, 20 Mar 2015 21:42:23 +0100
Subject: Bug 1147 - Fix XRandR13 Usage: Rotate / Change-Mode, use unique
 CRTC/Mode ids, ..

RandR 1.3 XRRSetCrtcConfig related:

- X11RandR13 now sets the new screen size via XRRSetScreenSize(..)

- X11RandR13 now propagates RRScreenChangeNotify events
  via XRRUpdateConfiguration(event).
  Hence reporting virtual desktop size now.

- X11RandR13 now disables the CRTC before XRRSetCrtcConfig(..)
  to avoid invalid configuration (see spec)!

RandR 1.3 General:

- Uses unique id named instead of unstable index
  for modes and CRTC.
  This allows proper identification even for 'swizzled' devices.
---
 src/newt/native/xrandr_utils.c | 322 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 322 insertions(+)
 create mode 100644 src/newt/native/xrandr_utils.c

(limited to 'src/newt/native/xrandr_utils.c')

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;
+}
+
-- 
cgit v1.2.3