aboutsummaryrefslogtreecommitdiff
path: root/xbmc-xrandr.c
diff options
context:
space:
mode:
authorJoakim Plate <elupus@xbmc.org>2012-07-08 02:13:59 +0200
committerJoakim Plate <elupus@ecce.se>2012-07-08 14:33:21 +0200
commit2e490dc437301b77bd0db87d6e6ed87768f0963a (patch)
treea13885edad9399ca51c8300419fe040cbe289496 /xbmc-xrandr.c
parent3dc35f648156f1c642f7d6126384602122d3e055 (diff)
[xrandr] update xbmc-xrandr.c base code
Supports selection of CRTC's in a better way
Diffstat (limited to 'xbmc-xrandr.c')
-rw-r--r--xbmc-xrandr.c1258
1 files changed, 1053 insertions, 205 deletions
diff --git a/xbmc-xrandr.c b/xbmc-xrandr.c
index 9f3f23f076..35b5d1afae 100644
--- a/xbmc-xrandr.c
+++ b/xbmc-xrandr.c
@@ -32,16 +32,13 @@
#include <X11/Xatom.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xrender.h> /* we share subpixel information */
+#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <math.h>
-#if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 2)
-#define HAS_RANDR_1_2 1
-#endif
-
static char *program_name;
static Display *dpy;
static Window root;
@@ -49,6 +46,8 @@ static int screen = -1;
static Bool verbose = False;
static Bool automatic = False;
static Bool properties = False;
+static Bool grab_server = True;
+static Bool no_primary = False;
static char *direction[5] = {
"normal",
@@ -89,7 +88,7 @@ static const struct {
{ NULL, 0 }
};
-static void
+static void _X_NORETURN
usage(void)
{
fprintf(stderr, "usage: %s [options]\n", program_name);
@@ -106,16 +105,13 @@ usage(void)
fprintf(stderr, " -y (reflect in y)\n");
fprintf(stderr, " --screen <screen>\n");
fprintf(stderr, " --verbose\n");
+ fprintf(stderr, " --current\n");
fprintf(stderr, " --dryrun\n");
-#if HAS_RANDR_1_2
+ fprintf(stderr, " --nograb\n");
fprintf(stderr, " --prop or --properties\n");
fprintf(stderr, " --fb <width>x<height>\n");
fprintf(stderr, " --fbmm <width>x<height>\n");
fprintf(stderr, " --dpi <dpi>/<output>\n");
-#if 0
- fprintf(stderr, " --clone\n");
- fprintf(stderr, " --extend\n");
-#endif
fprintf(stderr, " --output <output>\n");
fprintf(stderr, " --auto\n");
fprintf(stderr, " --mode <mode>\n");
@@ -130,22 +126,30 @@ usage(void)
fprintf(stderr, " --below <output>\n");
fprintf(stderr, " --same-as <output>\n");
fprintf(stderr, " --set <property> <value>\n");
+ fprintf(stderr, " --scale <x>x<y>\n");
+ fprintf(stderr, " --scale-from <w>x<h>\n");
+ fprintf(stderr, " --transform <a>,<b>,<c>,<d>,<e>,<f>,<g>,<h>,<i>\n");
fprintf(stderr, " --off\n");
fprintf(stderr, " --crtc <crtc>\n");
+ fprintf(stderr, " --panning <w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n");
+ fprintf(stderr, " --gamma <r>:<g>:<b>\n");
+ fprintf(stderr, " --primary\n");
+ fprintf(stderr, " --noprimary\n");
fprintf(stderr, " --newmode <name> <clock MHz>\n");
fprintf(stderr, " <hdisp> <hsync-start> <hsync-end> <htotal>\n");
fprintf(stderr, " <vdisp> <vsync-start> <vsync-end> <vtotal>\n");
- fprintf(stderr, " [+HSync] [-HSync] [+VSync] [-VSync]\n");
+ fprintf(stderr, " [flags...]\n");
+ fprintf(stderr, " Valid flags: +HSync -HSync +VSync -VSync\n");
+ fprintf(stderr, " +CSync -CSync CSync Interlace DoubleScan\n");
fprintf(stderr, " --rmmode <name>\n");
fprintf(stderr, " --addmode <output> <name>\n");
fprintf(stderr, " --delmode <output> <name>\n");
-#endif
exit(1);
/*NOTREACHED*/
}
-static void
+static void _X_NORETURN
fatal (const char *format, ...)
{
va_list ap;
@@ -158,6 +162,23 @@ fatal (const char *format, ...)
/*NOTREACHED*/
}
+static void
+warning (const char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ fprintf (stderr, "%s: ", program_name);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+}
+
+/* Because fmin requires C99 suppport */
+static inline double dmin (double x, double y)
+{
+ return x < y ? x : y;
+}
+
static char *
rotation_name (Rotation rotation)
{
@@ -188,15 +209,26 @@ reflection_name (Rotation rotation)
return "invalid reflection";
}
-#if HAS_RANDR_1_2
-typedef enum _policy {
- cloned, extend
-} policy_t;
-
typedef enum _relation {
- left_of, right_of, above, below, same_as
+ relation_left_of,
+ relation_right_of,
+ relation_above,
+ relation_below,
+ relation_same_as,
} relation_t;
+typedef struct {
+ int x, y, width, height;
+} rectangle_t;
+
+typedef struct {
+ int x1, y1, x2, y2;
+} box_t;
+
+typedef struct {
+ int x, y;
+} point_t;
+
typedef enum _changes {
changes_none = 0,
changes_crtc = (1 << 0),
@@ -207,7 +239,11 @@ typedef enum _changes {
changes_reflection = (1 << 5),
changes_automatic = (1 << 6),
changes_refresh = (1 << 7),
- changes_property = (1 << 8)
+ changes_property = (1 << 8),
+ changes_transform = (1 << 9),
+ changes_panning = (1 << 10),
+ changes_gamma = (1 << 11),
+ changes_primary = (1 << 12),
} changes_t;
typedef enum _name_kind {
@@ -215,7 +251,7 @@ typedef enum _name_kind {
name_string = (1 << 0),
name_xid = (1 << 1),
name_index = (1 << 2),
- name_preferred = (1 << 3)
+ name_preferred = (1 << 3),
} name_kind_t;
typedef struct {
@@ -227,20 +263,30 @@ typedef struct {
typedef struct _crtc crtc_t;
typedef struct _output output_t;
+typedef struct _transform transform_t;
typedef struct _umode umode_t;
typedef struct _output_prop output_prop_t;
+struct _transform {
+ XTransform transform;
+ char *filter;
+ int nparams;
+ XFixed *params;
+};
+
struct _crtc {
name_t crtc;
Bool changing;
XRRCrtcInfo *crtc_info;
XRRModeInfo *mode_info;
+ XRRPanning *panning_info;
int x;
int y;
Rotation rotation;
output_t **outputs;
int noutput;
+ transform_t current_transform, pending_transform;
};
struct _output_prop {
@@ -264,7 +310,7 @@ struct _output {
crtc_t *current_crtc_info;
name_t mode;
- float refresh;
+ double refresh;
XRRModeInfo *mode_info;
name_t addmode;
@@ -274,8 +320,24 @@ struct _output {
int x, y;
Rotation rotation;
-
+
+ XRRPanning panning;
+
Bool automatic;
+ int scale_from_w, scale_from_h;
+ transform_t transform;
+
+ struct {
+ float red;
+ float green;
+ float blue;
+ } gamma;
+
+ float brightness;
+
+ Bool primary;
+
+ Bool found;
};
typedef enum _umode_action {
@@ -327,11 +389,12 @@ static int num_crtcs;
static XRRScreenResources *res;
static int fb_width = 0, fb_height = 0;
static int fb_width_mm = 0, fb_height_mm = 0;
-static float dpi = 0;
+static double dpi = 0;
static char *dpi_output = NULL;
static Bool dryrun = False;
static int minWidth, maxWidth, minHeight, maxHeight;
static Bool has_1_2 = False;
+static Bool has_1_3 = False;
static int
mode_height (XRRModeInfo *mode_info, Rotation rotation)
@@ -363,28 +426,104 @@ mode_width (XRRModeInfo *mode_info, Rotation rotation)
}
}
+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]);
+ result[j] = v;
+ }
+ if (!result[2])
+ return False;
+ for (j = 0; j < 2; j++) {
+ vector[j] = result[j] / result[2];
+ if (vector[j] > 32767 || vector[j] < -32767)
+ return False;
+ }
+ *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);
+}
+
/* v refresh frequency in Hz */
-static float
+static double
mode_refresh (XRRModeInfo *mode_info)
{
- float rate;
+ double rate;
if (mode_info->hTotal && mode_info->vTotal)
- rate = ((float) mode_info->dotClock /
- ((float) mode_info->hTotal * (float) mode_info->vTotal));
+ rate = ((double) mode_info->dotClock /
+ ((double) mode_info->hTotal * (double) mode_info->vTotal));
else
rate = 0;
return rate;
}
/* h sync frequency in Hz */
-static float
+static double
mode_hsync (XRRModeInfo *mode_info)
{
- float rate;
+ double rate;
if (mode_info->hTotal)
- rate = (float) mode_info->dotClock / (float) mode_info->hTotal;
+ rate = (double) mode_info->dotClock / (double) mode_info->hTotal;
else
rate = 0;
return rate;
@@ -438,10 +577,11 @@ set_name_all (name_t *name, name_t *old)
static void
set_name (name_t *name, char *string, name_kind_t valid)
{
- XID xid;
+ unsigned int xid; /* don't make it XID (which is unsigned long):
+ scanf() takes unsigned int */
int index;
- if ((valid & name_xid) && sscanf (string, "0x%lx", &xid) == 1)
+ if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1)
set_name_xid (name, xid);
else if ((valid & name_index) && sscanf (string, "%d", &index) == 1)
set_name_index (name, index);
@@ -451,14 +591,63 @@ set_name (name_t *name, char *string, name_kind_t valid)
usage ();
}
+static void
+init_transform (transform_t *transform)
+{
+ int x;
+ memset (&transform->transform, '\0', sizeof (transform->transform));
+ for (x = 0; x < 3; x++)
+ transform->transform.matrix[x][x] = XDoubleToFixed (1.0);
+ transform->filter = "";
+ transform->nparams = 0;
+ transform->params = NULL;
+}
+
+static void
+set_transform (transform_t *dest,
+ XTransform *transform,
+ char *filter,
+ XFixed *params,
+ int nparams)
+{
+ dest->transform = *transform;
+ dest->filter = strdup (filter);
+ dest->nparams = nparams;
+ dest->params = malloc (nparams * sizeof (XFixed));
+ memcpy (dest->params, params, nparams * sizeof (XFixed));
+}
+
+static void
+copy_transform (transform_t *dest, transform_t *src)
+{
+ set_transform (dest, &src->transform,
+ src->filter, src->params, src->nparams);
+}
+
+static Bool
+equal_transform (transform_t *a, transform_t *b)
+{
+ if (memcmp (&a->transform, &b->transform, sizeof (XTransform)) != 0)
+ return False;
+ if (strcmp (a->filter, b->filter) != 0)
+ return False;
+ if (a->nparams != b->nparams)
+ return False;
+ if (memcmp (a->params, b->params, a->nparams * sizeof (XFixed)) != 0)
+ return False;
+ return True;
+}
+
static output_t *
add_output (void)
{
output_t *output = calloc (1, sizeof (output_t));
if (!output)
- fatal ("out of memory");
+ fatal ("out of memory\n");
output->next = NULL;
+ output->found = False;
+ output->brightness = 1.0;
*outputs_tail = output;
outputs_tail = &output->next;
return output;
@@ -538,11 +727,11 @@ find_crtc_by_xid (RRCrtc crtc)
}
static XRRModeInfo *
-find_mode (name_t *name, float refresh)
+find_mode (name_t *name, double refresh)
{
int m;
XRRModeInfo *best = NULL;
- float bestDist = 0;
+ double bestDist = 0;
for (m = 0; m < res->nmode; m++)
{
@@ -554,7 +743,7 @@ find_mode (name_t *name, float refresh)
}
if ((name->kind & name_string) && !strcmp (name->string, mode->name))
{
- float dist;
+ double dist;
if (refresh)
dist = fabs (mode_refresh (mode) - refresh);
@@ -565,7 +754,6 @@ find_mode (name_t *name, float refresh)
bestDist = dist;
best = mode;
}
- break;
}
}
return best;
@@ -581,18 +769,30 @@ find_mode_by_xid (RRMode mode)
return find_mode (&mode_name, 0);
}
+#if 0
static XRRModeInfo *
+find_mode_by_name (char *name)
+{
+ name_t mode_name;
+ init_name (&mode_name);
+ set_name_string (&mode_name, name);
+ return find_mode (&mode_name, 0);
+}
+#endif
+
+static
+XRRModeInfo *
find_mode_for_output (output_t *output, name_t *name)
{
XRROutputInfo *output_info = output->output_info;
int m;
XRRModeInfo *best = NULL;
- float bestDist = 0;
+ double bestDist = 0;
for (m = 0; m < output_info->nmode; m++)
{
XRRModeInfo *mode;
-
+
mode = find_mode_by_xid (output_info->modes[m]);
if (!mode) continue;
if ((name->kind & name_xid) && name->xid == mode->id)
@@ -602,8 +802,12 @@ find_mode_for_output (output_t *output, name_t *name)
}
if ((name->kind & name_string) && !strcmp (name->string, mode->name))
{
- float dist;
-
+ double dist;
+
+ /* Stay away from doublescan modes unless refresh rate is specified. */
+ if (!output->refresh && (mode->modeFlags & RR_DoubleScan))
+ continue;
+
if (output->refresh)
dist = fabs (mode_refresh (mode) - output->refresh);
else
@@ -618,7 +822,7 @@ find_mode_for_output (output_t *output, name_t *name)
return best;
}
-XRRModeInfo *
+static XRRModeInfo *
preferred_mode (output_t *output)
{
XRROutputInfo *output_info = output->output_info;
@@ -686,6 +890,45 @@ crtc_can_use_rotation (crtc_t *crtc, Rotation rotation)
return False;
}
+#if 0
+static Bool
+crtc_can_use_transform (crtc_t *crtc, XTransform *transform)
+{
+ int major, minor;
+
+ XRRQueryVersion (dpy, &major, &minor);
+ if (major > 1 || (major == 1 && minor >= 3))
+ return True;
+ return False;
+}
+#endif
+
+/*
+ * Report only rotations that are supported by all crtcs
+ */
+static Rotation
+output_rotations (output_t *output)
+{
+ Bool found = False;
+ Rotation rotation = RR_Rotate_0;
+ XRROutputInfo *output_info = output->output_info;
+ int c;
+
+ for (c = 0; c < output_info->ncrtc; c++)
+ {
+ crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]);
+ if (crtc)
+ {
+ if (!found) {
+ rotation = crtc->crtc_info->rotations;
+ found = True;
+ } else
+ rotation &= crtc->crtc_info->rotations;
+ }
+ }
+ return rotation;
+}
+
static Bool
output_can_use_rotation (output_t *output, Rotation rotation)
{
@@ -706,13 +949,111 @@ output_can_use_rotation (output_t *output, Rotation rotation)
return True;
}
+static Bool
+output_is_primary(output_t *output)
+{
+ if (has_1_3)
+ return XRRGetOutputPrimary(dpy, root) == output->output.xid;
+ return False;
+}
+
+/* Returns the index of the last value in an array < 0xffff */
+static int
+find_last_non_clamped(CARD16 array[], int size) {
+ int i;
+ for (i = size - 1; i > 0; i--) {
+ if (array[i] < 0xffff)
+ return i;
+ }
+ return 0;
+}
+
+static void
+set_gamma_info(output_t *output)
+{
+ XRRCrtcGamma *gamma;
+ double i1, v1, i2, v2;
+ int size, middle, last_best, last_red, last_green, last_blue;
+ CARD16 *best_array;
+
+ if (!output->crtc_info)
+ return;
+
+ size = XRRGetCrtcGammaSize(dpy, output->crtc_info->crtc.xid);
+ if (!size) {
+ warning("Failed to get size of gamma for output %s\n", output->output.string);
+ return;
+ }
+
+ gamma = XRRGetCrtcGamma(dpy, output->crtc_info->crtc.xid);
+ if (!gamma) {
+ warning("Failed to get gamma for output %s\n", output->output.string);
+ return;
+ }
+
+ /*
+ * Here is a bit tricky because gamma is a whole curve for each
+ * color. So, typically, we need to represent 3 * 256 values as 3 + 1
+ * values. Therefore, we approximate the gamma curve (v) by supposing
+ * it always follows the way we set it: a power function (i^g)
+ * multiplied by a brightness (b).
+ * v = i^g * b
+ * so g = (ln(v) - ln(b))/ln(i)
+ * and b can be found using two points (v1,i1) and (v2, i2):
+ * b = e^((ln(v2)*ln(i1) - ln(v1)*ln(i2))/ln(i1/i2))
+ * For the best resolution, we select i2 at the highest place not
+ * clamped and i1 at i2/2. Note that if i2 = 1 (as in most normal
+ * cases), then b = v2.
+ */
+ last_red = find_last_non_clamped(gamma->red, size);
+ last_green = find_last_non_clamped(gamma->green, size);
+ last_blue = find_last_non_clamped(gamma->blue, size);
+ best_array = gamma->red;
+ last_best = last_red;
+ if (last_green > last_best) {
+ last_best = last_green;
+ best_array = gamma->green;
+ }
+ if (last_blue > last_best) {
+ last_best = last_blue;
+ best_array = gamma->blue;
+ }
+ if (last_best == 0)
+ last_best = 1;
+
+ middle = last_best / 2;
+ i1 = (double)(middle + 1) / size;
+ v1 = (double)(best_array[middle]) / 65535;
+ i2 = (double)(last_best + 1) / size;
+ v2 = (double)(best_array[last_best]) / 65535;
+ if (v2 < 0.0001) { /* The screen is black */
+ output->brightness = 0;
+ output->gamma.red = 1;
+ output->gamma.green = 1;
+ output->gamma.blue = 1;
+ } else {
+ if ((last_best + 1) == size)
+ output->brightness = v2;
+ else
+ output->brightness = exp((log(v2)*log(i1) - log(v1)*log(i2))/log(i1/i2));
+ output->gamma.red = log((double)(gamma->red[last_red / 2]) / output->brightness
+ / 65535) / log((double)((last_red / 2) + 1) / size);
+ output->gamma.green = log((double)(gamma->green[last_green / 2]) / output->brightness
+ / 65535) / log((double)((last_green / 2) + 1) / size);
+ output->gamma.blue = log((double)(gamma->blue[last_blue / 2]) / output->brightness
+ / 65535) / log((double)((last_blue / 2) + 1) / size);
+ }
+
+ XRRFreeGamma(gamma);
+}
+
static void
set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info)
{
/* sanity check output info */
if (output_info->connection != RR_Disconnected && !output_info->nmode)
- fatal ("Output %s is not disconnected but has no modes\n",
- output_info->name);
+ warning ("Output %s is not disconnected but has no modes\n",
+ output_info->name);
/* set output name and info */
if (!(output->output.kind & name_xid))
@@ -745,7 +1086,13 @@ set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info)
/* set mode name and info */
if (!(output->changes & changes_mode))
{
- if (output->crtc_info)
+ crtc_t *crtc = NULL;
+
+ if (output_info->crtc)
+ crtc = find_crtc_by_xid(output_info->crtc);
+ if (crtc && crtc->crtc_info)
+ set_name_xid (&output->mode, crtc->crtc_info->mode);
+ else if (output->crtc_info)
set_name_xid (&output->mode, output->crtc_info->crtc_info->mode);
else
set_name_xid (&output->mode, None);
@@ -817,10 +1164,51 @@ set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info)
output->output.string,
rotation_name (output->rotation),
reflection_name (output->rotation));
+
+ /* set gamma */
+ if (!(output->changes & changes_gamma))
+ set_gamma_info(output);
+
+ /* set transformation */
+ if (!(output->changes & changes_transform))
+ {
+ if (output->crtc_info)
+ copy_transform (&output->transform, &output->crtc_info->current_transform);
+ else
+ init_transform (&output->transform);
+ } else {
+ /* transform was already set for --scale or --transform */
+
+ /* for --scale-from, figure out the mode size and compute the transform
+ * for the target framebuffer area */
+ if (output->scale_from_w > 0 && output->mode_info) {
+ double sx = (double)output->scale_from_w /
+ output->mode_info->width;
+ double sy = (double)output->scale_from_h /
+ output->mode_info->height;
+ if (verbose)
+ printf("scaling %s by %lfx%lf\n", output->output.string, sx,
+ sy);
+ init_transform (&output->transform);
+ output->transform.transform.matrix[0][0] = XDoubleToFixed (sx);
+ output->transform.transform.matrix[1][1] = XDoubleToFixed (sy);
+ output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0);
+ if (sx != 1 || sy != 1)
+ output->transform.filter = "bilinear";
+ else
+ output->transform.filter = "nearest";
+ output->transform.nparams = 0;
+ output->transform.params = NULL;
+ }
+ }
+
+ /* set primary */
+ if (!(output->changes & changes_primary))
+ output->primary = output_is_primary(output);
}
static void
-get_screen (void)
+get_screen (Bool current)
{
if (!has_1_2)
fatal ("Server RandR version before 1.2\n");
@@ -828,7 +1216,10 @@ get_screen (void)
XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight,
&maxWidth, &maxHeight);
- res = XRRGetScreenResources (dpy, root);
+ if (current)
+ res = XRRGetScreenResourcesCurrent (dpy, root);
+ else
+ res = XRRGetScreenResources (dpy, root);
if (!res) fatal ("could not get screen resources");
}
@@ -839,15 +1230,30 @@ get_crtcs (void)
num_crtcs = res->ncrtc;
crtcs = calloc (num_crtcs, sizeof (crtc_t));
- if (!crtcs) fatal ("out of memory");
+ if (!crtcs) fatal ("out of memory\n");
for (c = 0; c < res->ncrtc; c++)
{
XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]);
+ XRRCrtcTransformAttributes *attr;
+ XRRPanning *panning_info = NULL;
+
+ if (has_1_3) {
+ XRRPanning zero;
+ memset(&zero, 0, sizeof(zero));
+ panning_info = XRRGetPanning (dpy, res, res->crtcs[c]);
+ zero.timestamp = panning_info->timestamp;
+ if (!memcmp(panning_info, &zero, sizeof(zero))) {
+ Xfree(panning_info);
+ panning_info = NULL;
+ }
+ }
+
set_name_xid (&crtcs[c].crtc, res->crtcs[c]);
set_name_index (&crtcs[c].crtc, c);
- if (!crtc_info) fatal ("could not get crtc 0x%x information", res->crtcs[c]);
+ if (!crtc_info) fatal ("could not get crtc 0x%x information\n", res->crtcs[c]);
crtcs[c].crtc_info = crtc_info;
+ crtcs[c].panning_info = panning_info;
if (crtc_info->mode == None)
{
crtcs[c].mode_info = NULL;
@@ -855,7 +1261,20 @@ get_crtcs (void)
crtcs[c].y = 0;
crtcs[c].rotation = RR_Rotate_0;
}
- }
+ if (XRRGetCrtcTransform (dpy, res->crtcs[c], &attr) && attr) {
+ set_transform (&crtcs[c].current_transform,
+ &attr->currentTransform,
+ attr->currentFilter,
+ attr->currentParams,
+ attr->currentNparams);
+ XFree (attr);
+ }
+ else
+ {
+ init_transform (&crtcs[c].current_transform);
+ }
+ copy_transform (&crtcs[c].pending_transform, &crtcs[c].current_transform);
+ }
}
static void
@@ -870,8 +1289,9 @@ crtc_add_output (crtc_t *crtc, output_t *output)
crtc->y = output->y;
crtc->rotation = output->rotation;
crtc->mode_info = output->mode_info;
- }
- if (!crtc->outputs) fatal ("out of memory");
+ copy_transform (&crtc->pending_transform, &output->transform);
+ }
+ if (!crtc->outputs) fatal ("out of memory\n");
crtc->outputs[crtc->noutput++] = output;
}
@@ -887,6 +1307,106 @@ set_crtcs (void)
}
}
+static void
+set_panning (void)
+{
+ output_t *output;
+
+ for (output = outputs; output; output = output->next)
+ {
+ if (! output->crtc_info)
+ continue;
+ if (! (output->changes & changes_panning))
+ continue;
+ if (! output->crtc_info->panning_info)
+ output->crtc_info->panning_info = malloc (sizeof(XRRPanning));
+ memcpy (output->crtc_info->panning_info, &output->panning, sizeof(XRRPanning));
+ output->crtc_info->changing = 1;
+ }
+}
+
+static void
+set_gamma(void)
+{
+ output_t *output;
+
+ for (output = outputs; output; output = output->next) {
+ int i, size;
+ crtc_t *crtc;
+ XRRCrtcGamma *gamma;
+
+ if (!(output->changes & changes_gamma))
+ continue;
+
+ if (!output->crtc_info) {
+ fatal("Need crtc to set gamma on.\n");
+ continue;
+ }
+
+ crtc = output->crtc_info;
+
+ size = XRRGetCrtcGammaSize(dpy, crtc->crtc.xid);
+
+ if (!size) {
+ fatal("Gamma size is 0.\n");
+ continue;
+ }
+
+ gamma = XRRAllocGamma(size);
+ if (!gamma) {
+ fatal("Gamma allocation failed.\n");
+ continue;
+ }
+
+ if(output->gamma.red == 0.0 && output->gamma.green == 0.0 && output->gamma.blue == 0.0)
+ output->gamma.red = output->gamma.green = output->gamma.blue = 1.0;
+
+ for (i = 0; i < size; i++) {
+ if (output->gamma.red == 1.0 && output->brightness == 1.0)
+ gamma->red[i] = (i << 8) + i;
+ else
+ gamma->red[i] = dmin(pow((double)i/(double)(size - 1),
+ output->gamma.red) * output->brightness,
+ 1.0) * 65535.0;
+
+ if (output->gamma.green == 1.0 && output->brightness == 1.0)
+ gamma->green[i] = (i << 8) + i;
+ else
+ gamma->green[i] = dmin(pow((double)i/(double)(size - 1),
+ output->gamma.green) * output->brightness,
+ 1.0) * 65535.0;
+
+ if (output->gamma.blue == 1.0 && output->brightness == 1.0)
+ gamma->blue[i] = (i << 8) + i;
+ else
+ gamma->blue[i] = dmin(pow((double)i/(double)(size - 1),
+ output->gamma.blue) * output->brightness,
+ 1.0) * 65535.0;
+ }
+
+ XRRSetCrtcGamma(dpy, crtc->crtc.xid, gamma);
+
+ free(gamma);
+ }
+}
+
+static void
+set_primary(void)
+{
+ output_t *output;
+
+ if (no_primary) {
+ XRRSetOutputPrimary(dpy, root, None);
+ } else {
+ for (output = outputs; output; output = output->next) {
+ if (!(output->changes & changes_primary))
+ continue;
+ if (output->primary)
+ XRRSetOutputPrimary(dpy, root, output->output.xid);
+ }
+ }
+}
+
static Status
crtc_disable (crtc_t *crtc)
{
@@ -899,6 +1419,20 @@ crtc_disable (crtc_t *crtc)
0, 0, None, RR_Rotate_0, NULL, 0);
}
+static void
+crtc_set_transform (crtc_t *crtc, transform_t *transform)
+{
+ int major, minor;
+
+ XRRQueryVersion (dpy, &major, &minor);
+ if (major > 1 || (major == 1 && minor >= 3))
+ XRRSetCrtcTransform (dpy, crtc->crtc.xid,
+ &transform->transform,
+ transform->filter,
+ transform->params,
+ transform->nparams);
+}
+
static Status
crtc_revert (crtc_t *crtc)
{
@@ -909,6 +1443,9 @@ crtc_revert (crtc_t *crtc)
if (dryrun)
return RRSetConfigSuccess;
+
+ if (!equal_transform (&crtc->current_transform, &crtc->pending_transform))
+ crtc_set_transform (crtc, &crtc->current_transform);
return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
crtc_info->x, crtc_info->y,
crtc_info->mode, crtc_info->rotation,
@@ -944,9 +1481,19 @@ crtc_apply (crtc_t *crtc)
if (dryrun)
s = RRSetConfigSuccess;
else
+ {
+ if (!equal_transform (&crtc->current_transform, &crtc->pending_transform))
+ crtc_set_transform (crtc, &crtc->pending_transform);
s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
crtc->x, crtc->y, mode, crtc->rotation,
rr_outputs, crtc->noutput);
+ if (s == RRSetConfigSuccess && crtc->panning_info) {
+ if (has_1_3)
+ s = XRRSetPanning (dpy, res, crtc->crtc.xid, crtc->panning_info);
+ else
+ fatal ("panning needs RandR 1.3\n");
+ }
+ }
free (rr_outputs);
return s;
}
@@ -1005,7 +1552,7 @@ revert (void)
* the configuration. Revert to the previous configuration
* and bail
*/
-static void
+static void _X_NORETURN
panic (Status s, crtc_t *crtc)
{
int c = crtc->crtc.index;
@@ -1025,13 +1572,22 @@ panic (Status s, crtc_t *crtc)
exit (1);
}
-void
+static void
apply (void)
{
Status s;
int c;
/*
+ * Hold the server grabbed while messing with
+ * the screen so that apps which notice the resize
+ * event and ask for xinerama information from the server
+ * receive up-to-date information
+ */
+ if (grab_server)
+ XGrabServer (dpy);
+
+ /*
* Turn off any crtcs which are to be disabled or which are
* larger than the target size
*/
@@ -1052,16 +1608,21 @@ apply (void)
{
XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode);
int x, y, w, h;
+ box_t bounds;
if (!old_mode)
panic (RRSetConfigFailed, crtc);
/* old position and size information */
- x = crtc_info->x;
- y = crtc_info->y;
- w = mode_width (old_mode, crtc_info->rotation);
- h = mode_height (old_mode, crtc_info->rotation);
-
+ mode_geometry (old_mode, crtc_info->rotation,
+ &crtc->current_transform.transform,
+ &bounds);
+
+ x = crtc_info->x + bounds.x1;
+ y = crtc_info->y + bounds.y1;
+ w = bounds.x2 - bounds.x1;
+ h = bounds.y2 - bounds.y1;
+
/* if it fits, skip it */
if (x + w <= fb_width && y + h <= fb_height)
continue;
@@ -1073,13 +1634,6 @@ apply (void)
}
/*
- * Hold the server grabbed while messing with
- * the screen so that apps which notice the resize
- * event receive up-to-date information
- */
- XGrabServer (dpy);
-
- /*
* Set the screen size
*/
screen_apply ();
@@ -1096,27 +1650,32 @@ apply (void)
if (s != RRSetConfigSuccess)
panic (s, crtc);
}
+
+ set_primary ();
+
/*
* Release the server grab and let all clients
* respond to the updated state
*/
- XUngrabServer (dpy);
+ if (grab_server)
+ XUngrabServer (dpy);
}
/*
* Use current output state to complete the output list
*/
-void
+static void
get_outputs (void)
{
int o;
+ output_t *q;
for (o = 0; o < res->noutput; o++)
{
XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]);
output_t *output;
name_t output_name;
- if (!output_info) fatal ("could not get output 0x%x information", res->outputs[o]);
+ if (!output_info) fatal ("could not get output 0x%x information\n", res->outputs[o]);
set_name_xid (&output_name, res->outputs[o]);
set_name_index (&output_name, o);
set_name_string (&output_name, output_info->name);
@@ -1148,6 +1707,7 @@ get_outputs (void)
}
}
}
+ output->found = True;
/*
* Automatic mode -- track connection state and enable/disable outputs
@@ -1178,9 +1738,17 @@ get_outputs (void)
set_output_info (output, res->outputs[o], output_info);
}
+ for (q = outputs; q; q = q->next)
+ {
+ if (!q->found)
+ {
+ fprintf(stderr, "warning: output %s not found; ignoring\n",
+ q->output.string);
+ }
+ }
}
-void
+static void
mark_changing_crtcs (void)
{
int c;
@@ -1213,7 +1781,7 @@ mark_changing_crtcs (void)
/*
* Test whether 'crtc' can be used for 'output'
*/
-Bool
+static Bool
check_crtc_for_output (crtc_t *crtc, output_t *output)
{
int c;
@@ -1256,11 +1824,27 @@ check_crtc_for_output (crtc_t *crtc, output_t *output)
return False;
if (crtc->rotation != output->rotation)
return False;
+ if (!equal_transform (&crtc->current_transform, &output->transform))
+ return False;
+ }
+ else if (crtc->crtc_info->noutput)
+ {
+ /* make sure the state matches the already used state */
+ XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode);
+
+ if (mode != output->mode_info)
+ return False;
+ if (crtc->crtc_info->x != output->x)
+ return False;
+ if (crtc->crtc_info->y != output->y)
+ return False;
+ if (crtc->crtc_info->rotation != output->rotation)
+ return False;
}
return True;
}
-crtc_t *
+static crtc_t *
find_crtc_for_output (output_t *output)
{
int c;
@@ -1323,23 +1907,23 @@ set_positions (void)
}
switch (output->relation) {
- case left_of:
+ case relation_left_of:
output->y = relation->y;
output->x = relation->x - mode_width (output->mode_info, output->rotation);
break;
- case right_of:
+ case relation_right_of:
output->y = relation->y;
output->x = relation->x + mode_width (relation->mode_info, relation->rotation);
break;
- case above:
+ case relation_above:
output->x = relation->x;
output->y = relation->y - mode_height (output->mode_info, output->rotation);
break;
- case below:
+ case relation_below:
output->x = relation->x;
output->y = relation->y + mode_height (relation->mode_info, relation->rotation);
break;
- case same_as:
+ case relation_same_as:
output->x = relation->x;
output->y = relation->y;
}
@@ -1388,25 +1972,40 @@ set_screen_size (void)
{
XRRModeInfo *mode_info = output->mode_info;
int x, y, w, h;
+ box_t bounds;
if (!mode_info) continue;
- x = output->x;
- y = output->y;
- w = mode_width (mode_info, output->rotation);
- h = mode_height (mode_info, output->rotation);
+ mode_geometry (mode_info, output->rotation,
+ &output->transform.transform,
+ &bounds);
+ x = output->x + bounds.x1;
+ y = output->y + bounds.y1;
+ w = bounds.x2 - bounds.x1;
+ h = bounds.y2 - bounds.y1;
/* make sure output fits in specified size */
if (fb_specified)
{
if (x + w > fb_width || y + h > fb_height)
- fatal ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n",
- fb_width, fb_height, output->output.string, w, h, x, y);
+ warning ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n",
+ fb_width, fb_height, output->output.string, w, h, x, y);
}
/* fit fb to output */
else
{
- if (x + w > fb_width) fb_width = x + w;
- if (y + h > fb_height) fb_height = y + h;
+ XRRPanning *pan;
+ if (x + w > fb_width)
+ fb_width = x + w;
+ if (y + h > fb_height)
+ fb_height = y + h;
+ if (output->changes & changes_panning)
+ pan = &output->panning;
+ else
+ pan = output->crtc_info ? output->crtc_info->panning_info : NULL;
+ 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;
}
}
@@ -1425,9 +2024,8 @@ set_screen_size (void)
}
}
-#endif
-
-void
+
+static void
disable_outputs (output_t *outputs)
{
while (outputs)
@@ -1440,7 +2038,7 @@ disable_outputs (output_t *outputs)
/*
* find the best mapping from output to crtc available
*/
-int
+static int
pick_crtcs_score (output_t *outputs)
{
output_t *output;
@@ -1493,21 +2091,20 @@ pick_crtcs_score (output_t *outputs)
best_score = score;
}
}
+ if (output->crtc_info != best_crtc)
+ output->crtc_info = best_crtc;
/*
* Reset other outputs based on this one using the best crtc
*/
- if (output->crtc_info != best_crtc)
- {
- output->crtc_info = best_crtc;
- (void) pick_crtcs_score (outputs);
- }
+ (void) pick_crtcs_score (outputs);
+
return best_score;
}
/*
* Pick crtcs for any changing outputs that don't have one
*/
-void
+static void
pick_crtcs (void)
{
output_t *output;
@@ -1517,11 +2114,18 @@ pick_crtcs (void)
*/
for (output = outputs; output; output = output->next)
{
- if (output->changes && output->mode_info && !output->crtc_info)
+ if (output->changes && output->mode_info)
{
- output->crtc_info = find_crtc_for_output (output);
- if (!output->crtc_info)
- break;
+ if (output->crtc_info) {
+ if (output->crtc_info->crtc_info->noutput > 0 &&
+ (output->crtc_info->crtc_info->noutput > 1 ||
+ output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0])))
+ break;
+ } else {
+ output->crtc_info = find_crtc_for_output (output);
+ if (!output->crtc_info)
+ break;
+ }
}
}
/*
@@ -1545,6 +2149,26 @@ pick_crtcs (void)
}
}
+static int
+check_strtol(char *s)
+{
+ char *endptr;
+ int result = strtol(s, &endptr, 10);
+ if (s == endptr)
+ usage();
+ return result;
+}
+
+static double
+check_strtod(char *s)
+{
+ char *endptr;
+ double result = strtod(s, &endptr);
+ if (s == endptr)
+ usage();
+ return result;
+}
+
int
main (int argc, char **argv)
{
@@ -1555,7 +2179,8 @@ main (int argc, char **argv)
short *rates;
Status status = RRSetConfigFailed;
int rot = -1;
- int query = 0;
+ int query = False;
+ int action_requested = False;
Rotation rotation, current_rotation, rotations;
XRRScreenChangeNotifyEvent event;
XRRScreenChangeNotifyEvent *sce;
@@ -1563,7 +2188,7 @@ main (int argc, char **argv)
int i, j;
SizeID current_size;
short current_rate;
- float rate = -1;
+ double rate = -1;
int size = -1;
int dirind = 0;
Bool setit = False;
@@ -1573,19 +2198,16 @@ main (int argc, char **argv)
int width = 0, height = 0;
Bool have_pixel_size = False;
int ret = 0;
-#if HAS_RANDR_1_2
output_t *output = NULL;
- policy_t policy = cloned;
Bool setit_1_2 = False;
Bool query_1_2 = False;
Bool modeit = False;
Bool propit = False;
Bool query_1 = False;
int major, minor;
-#endif
+ Bool current = False;
program_name = argv[0];
- if (argc == 1) query = True;
for (i = 1; i < argc; i++) {
if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) {
if (++i>=argc) usage ();
@@ -1594,6 +2216,7 @@ main (int argc, char **argv)
}
if (!strcmp("-help", argv[i])) {
usage();
+ action_requested = True;
continue;
}
if (!strcmp ("--verbose", argv[i])) {
@@ -1605,16 +2228,25 @@ main (int argc, char **argv)
verbose = True;
continue;
}
+ if (!strcmp ("--nograb", argv[i])) {
+ grab_server = False;
+ continue;
+ }
+ if (!strcmp("--current", argv[i])) {
+ current = True;
+ continue;
+ }
if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) {
if (++i>=argc) usage ();
- if (sscanf (argv[i], "%dx%d", &width, &height) == 2)
+ if (sscanf (argv[i], "%dx%d", &width, &height) == 2) {
have_pixel_size = True;
- else {
- size = atoi (argv[i]);
- if (size < 0) usage();
- }
+ } else {
+ size = check_strtol(argv[i]);
+ if (size < 0) usage();
+ }
setit = True;
+ action_requested = True;
continue;
}
@@ -1623,38 +2255,39 @@ main (int argc, char **argv)
!strcmp ("--refresh", argv[i]))
{
if (++i>=argc) usage ();
- if (sscanf (argv[i], "%f", &rate) != 1)
- usage ();
+ rate = check_strtod(argv[i]);
setit = True;
-#if HAS_RANDR_1_2
if (output)
{
output->refresh = rate;
output->changes |= changes_refresh;
setit_1_2 = True;
}
-#endif
+ action_requested = True;
continue;
}
if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) {
version = True;
+ action_requested = True;
continue;
}
if (!strcmp ("-x", argv[i])) {
reflection |= RR_Reflect_X;
setit = True;
+ action_requested = True;
continue;
}
if (!strcmp ("-y", argv[i])) {
reflection |= RR_Reflect_Y;
setit = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--screen", argv[i])) {
if (++i>=argc) usage ();
- screen = atoi (argv[i]);
+ screen = check_strtol(argv[i]);
if (screen < 0) usage();
continue;
}
@@ -1665,8 +2298,8 @@ main (int argc, char **argv)
if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) {
char *endptr;
if (++i>=argc) usage ();
- dirind = strtol(argv[i], &endptr, 0);
- if (*endptr != '\0') {
+ dirind = strtol(argv[i], &endptr, 10);
+ if (argv[i] == endptr) {
for (dirind = 0; dirind < 4; dirind++) {
if (strcmp (direction[dirind], argv[i]) == 0) break;
}
@@ -1674,22 +2307,30 @@ main (int argc, char **argv)
}
rot = dirind;
setit = True;
+ action_requested = True;
continue;
}
-#if HAS_RANDR_1_2
- if (!strcmp ("--prop", argv[i]) || !strcmp ("--properties", argv[i]))
+ if (!strcmp ("--prop", argv[i]) ||
+ !strcmp ("--props", argv[i]) ||
+ !strcmp ("--madprops", argv[i]) ||
+ !strcmp ("--properties", argv[i]))
{
query_1_2 = True;
properties = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--output", argv[i])) {
if (++i >= argc) usage();
- output = add_output ();
- set_name (&output->output, argv[i], name_string|name_xid);
+ output = find_output_by_name (argv[i]);
+ if (!output) {
+ output = add_output ();
+ set_name (&output->output, argv[i], name_string|name_xid);
+ }
setit_1_2 = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--crtc", argv[i])) {
@@ -1750,7 +2391,7 @@ main (int argc, char **argv)
if (!strcmp ("--left-of", argv[i])) {
if (++i>=argc) usage ();
if (!output) usage();
- output->relation = left_of;
+ output->relation = relation_left_of;
output->relative_to = argv[i];
output->changes |= changes_relation;
continue;
@@ -1758,7 +2399,7 @@ main (int argc, char **argv)
if (!strcmp ("--right-of", argv[i])) {
if (++i>=argc) usage ();
if (!output) usage();
- output->relation = right_of;
+ output->relation = relation_right_of;
output->relative_to = argv[i];
output->changes |= changes_relation;
continue;
@@ -1766,7 +2407,7 @@ main (int argc, char **argv)
if (!strcmp ("--above", argv[i])) {
if (++i>=argc) usage ();
if (!output) usage();
- output->relation = above;
+ output->relation = relation_above;
output->relative_to = argv[i];
output->changes |= changes_relation;
continue;
@@ -1774,7 +2415,7 @@ main (int argc, char **argv)
if (!strcmp ("--below", argv[i])) {
if (++i>=argc) usage ();
if (!output) usage();
- output->relation = below;
+ output->relation = relation_below;
output->relative_to = argv[i];
output->changes |= changes_relation;
continue;
@@ -1782,11 +2423,72 @@ main (int argc, char **argv)
if (!strcmp ("--same-as", argv[i])) {
if (++i>=argc) usage ();
if (!output) usage();
- output->relation = same_as;
+ output->relation = relation_same_as;
output->relative_to = argv[i];
output->changes |= changes_relation;
continue;
}
+ if (!strcmp ("--panning", argv[i])) {
+ XRRPanning *pan;
+ if (++i>=argc) usage ();
+ if (!output) usage();
+ pan = &output->panning;
+ switch (sscanf (argv[i], "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d",
+ &pan->width, &pan->height, &pan->left, &pan->top,
+ &pan->track_width, &pan->track_height,
+ &pan->track_left, &pan->track_top,
+ &pan->border_left, &pan->border_top,
+ &pan->border_right, &pan->border_bottom)) {
+ case 2:
+ pan->left = pan->top = 0;
+ /* fall through */
+ case 4:
+ pan->track_left = pan->track_top =
+ pan->track_width = pan->track_height = 0;
+ /* fall through */
+ case 8:
+ pan->border_left = pan->border_top =
+ pan->border_right = pan->border_bottom = 0;
+ /* fall through */
+ case 12:
+ break;
+ default:
+ usage ();
+ }
+ output->changes |= changes_panning;
+ continue;
+ }
+ if (!strcmp ("--gamma", argv[i])) {
+ if (!output) usage();
+ if (++i>=argc) usage ();
+ if (sscanf(argv[i], "%f:%f:%f", &output->gamma.red,
+ &output->gamma.green, &output->gamma.blue) != 3)
+ usage ();
+ output->changes |= changes_gamma;
+ setit_1_2 = True;
+ continue;
+ }
+ if (!strcmp ("--brightness", argv[i])) {
+ if (!output) usage();
+ if (++i>=argc) usage();
+ if (sscanf(argv[i], "%f", &output->brightness) != 1)
+ usage ();
+ output->changes |= changes_gamma;
+ setit_1_2 = True;
+ continue;
+ }
+ if (!strcmp ("--primary", argv[i])) {
+ if (!output) usage();
+ output->changes |= changes_primary;
+ output->primary = True;
+ setit_1_2 = True;
+ continue;
+ }
+ if (!strcmp ("--noprimary", argv[i])) {
+ no_primary = True;
+ setit_1_2 = True;
+ continue;
+ }
if (!strcmp ("--set", argv[i])) {
output_prop_t *prop;
if (!output) usage();
@@ -1802,6 +2504,66 @@ main (int argc, char **argv)
setit_1_2 = True;
continue;
}
+ if (!strcmp ("--scale", argv[i]))
+ {
+ double sx, sy;
+ if (!output) usage();
+ if (++i>=argc) usage();
+ if (sscanf (argv[i], "%lfx%lf", &sx, &sy) != 2)
+ usage ();
+ init_transform (&output->transform);
+ output->transform.transform.matrix[0][0] = XDoubleToFixed (sx);
+ output->transform.transform.matrix[1][1] = XDoubleToFixed (sy);
+ output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0);
+ if (sx != 1 || sy != 1)
+ output->transform.filter = "bilinear";
+ else
+ output->transform.filter = "nearest";
+ output->transform.nparams = 0;
+ output->transform.params = NULL;
+ output->changes |= changes_transform;
+ continue;
+ }
+ if (!strcmp ("--scale-from", argv[i]))
+ {
+ int w, h;
+ if (!output) usage();
+ if (++i>=argc) usage();
+ if (sscanf (argv[i], "%dx%d", &w, &h) != 2)
+ usage ();
+ if (w <=0 || h <= 0)
+ usage ();
+ output->scale_from_w = w;
+ output->scale_from_h = h;
+ output->changes |= changes_transform;
+ continue;
+ }
+ if (!strcmp ("--transform", argv[i])) {
+ double transform[3][3];
+ int k, l;
+ if (!output) usage();
+ if (++i>=argc) usage ();
+ init_transform (&output->transform);
+ if (strcmp (argv[i], "none") != 0)
+ {
+ if (sscanf(argv[i], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
+ &transform[0][0],&transform[0][1],&transform[0][2],
+ &transform[1][0],&transform[1][1],&transform[1][2],
+ &transform[2][0],&transform[2][1],&transform[2][2])
+ != 9)
+ usage ();
+ init_transform (&output->transform);
+ for (k = 0; k < 3; k++)
+ for (l = 0; l < 3; l++) {
+ output->transform.transform.matrix[k][l] = XDoubleToFixed (transform[k][l]);
+ }
+ output->transform.filter = "bilinear";
+ output->transform.nparams = 0;
+ output->transform.params = NULL;
+ }
+ output->changes |= changes_transform;
+ continue;
+ }
if (!strcmp ("--off", argv[i])) {
if (!output) usage();
set_name_xid (&output->mode, None);
@@ -1815,6 +2577,7 @@ main (int argc, char **argv)
&fb_width, &fb_height) != 2)
usage ();
setit_1_2 = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--fbmm", argv[i])) {
@@ -1823,26 +2586,20 @@ main (int argc, char **argv)
&fb_width_mm, &fb_height_mm) != 2)
usage ();
setit_1_2 = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--dpi", argv[i])) {
+ char *strtod_error;
if (++i>=argc) usage ();
- if (sscanf (argv[i], "%f", &dpi) != 1)
+ dpi = strtod(argv[i], &strtod_error);
+ if (argv[i] == strtod_error)
{
dpi = 0.0;
dpi_output = argv[i];
}
setit_1_2 = True;
- continue;
- }
- if (!strcmp ("--clone", argv[i])) {
- policy = cloned;
- setit_1_2 = True;
- continue;
- }
- if (!strcmp ("--extend", argv[i])) {
- policy = extend;
- setit_1_2 = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--auto", argv[i])) {
@@ -1854,6 +2611,7 @@ main (int argc, char **argv)
else
automatic = True;
setit_1_2 = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--q12", argv[i]))
@@ -1869,25 +2627,24 @@ main (int argc, char **argv)
if (!strcmp ("--newmode", argv[i]))
{
umode_t *m = malloc (sizeof (umode_t));
- float clock;
+ double clock;
++i;
if (i + 9 >= argc) usage ();
m->mode.name = argv[i];
m->mode.nameLength = strlen (argv[i]);
i++;
- if (sscanf (argv[i++], "%f", &clock) != 1)
- usage ();
+ clock = check_strtod(argv[i++]);
m->mode.dotClock = clock * 1e6;
- if (sscanf (argv[i++], "%d", &m->mode.width) != 1) usage();
- if (sscanf (argv[i++], "%d", &m->mode.hSyncStart) != 1) usage();
- if (sscanf (argv[i++], "%d", &m->mode.hSyncEnd) != 1) usage();
- if (sscanf (argv[i++], "%d", &m->mode.hTotal) != 1) usage();
- if (sscanf (argv[i++], "%d", &m->mode.height) != 1) usage();
- if (sscanf (argv[i++], "%d", &m->mode.vSyncStart) != 1) usage();
- if (sscanf (argv[i++], "%d", &m->mode.vSyncEnd) != 1) usage();
- if (sscanf (argv[i++], "%d", &m->mode.vTotal) != 1) usage();
+ m->mode.width = check_strtol(argv[i++]);
+ m->mode.hSyncStart = check_strtol(argv[i++]);
+ m->mode.hSyncEnd = check_strtol(argv[i++]);
+ m->mode.hTotal = check_strtol(argv[i++]);
+ m->mode.height = check_strtol(argv[i++]);
+ m->mode.vSyncStart = check_strtol(argv[i++]);
+ m->mode.vSyncEnd = check_strtol(argv[i++]);
+ m->mode.vTotal = check_strtol(argv[i++]);
m->mode.modeFlags = 0;
while (i < argc) {
int f;
@@ -1905,6 +2662,7 @@ main (int argc, char **argv)
m->action = umode_create;
umodes = m;
modeit = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--rmmode", argv[i]))
@@ -1917,6 +2675,7 @@ main (int argc, char **argv)
m->next = umodes;
umodes = m;
modeit = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--addmode", argv[i]))
@@ -1931,6 +2690,7 @@ main (int argc, char **argv)
m->next = umodes;
umodes = m;
modeit = True;
+ action_requested = True;
continue;
}
if (!strcmp ("--delmode", argv[i]))
@@ -1945,11 +2705,13 @@ main (int argc, char **argv)
m->next = umodes;
umodes = m;
modeit = True;
+ action_requested = True;
continue;
}
-#endif
usage();
}
+ if (!action_requested)
+ query = True;
if (verbose)
{
query = True;
@@ -1957,6 +2719,11 @@ main (int argc, char **argv)
query_1 = True;
}
+/*
+ if (version)
+ printf("xrandr program version " VERSION "\n");
+*/
+
dpy = XOpenDisplay (display_name);
if (dpy == NULL) {
@@ -1973,20 +2740,22 @@ main (int argc, char **argv)
root = RootWindow (dpy, screen);
-#if HAS_RANDR_1_2
- if (!XRRQueryVersion (dpy, &major, &minor))
+ if (!XRRQueryExtension (dpy, &event_base, &error_base) ||
+ !XRRQueryVersion (dpy, &major, &minor))
{
fprintf (stderr, "RandR extension missing\n");
exit (1);
}
if (major > 1 || (major == 1 && minor >= 2))
has_1_2 = True;
+ if (major > 1 || (major == 1 && minor >= 3))
+ has_1_3 = True;
if (has_1_2 && modeit)
{
umode_t *m;
- get_screen ();
+ get_screen (current);
get_crtcs();
get_outputs();
@@ -2034,7 +2803,7 @@ main (int argc, char **argv)
if (has_1_2 && propit)
{
- get_screen ();
+ get_screen (current);
get_crtcs();
get_outputs();
@@ -2046,9 +2815,9 @@ main (int argc, char **argv)
{
Atom name = XInternAtom (dpy, prop->name, False);
Atom type;
- int format;
- unsigned char *data = NULL;
- int nelements = 0;
+ int format = 0;
+ unsigned char *data;
+ int nelements;
int int_value;
unsigned long ulong_value;
unsigned char *prop_data;
@@ -2058,7 +2827,6 @@ main (int argc, char **argv)
XRRPropertyInfo *propinfo;
type = AnyPropertyType;
- format=0;
if (XRRGetOutputProperty (dpy, output->output.xid, name,
0, 100, False, False,
@@ -2088,7 +2856,6 @@ main (int argc, char **argv)
ulong_value = XInternAtom (dpy, prop->value, False);
data = (unsigned char *) &ulong_value;
nelements = 1;
- format = 32;
}
else if ((type == XA_STRING || type == AnyPropertyType))
{
@@ -2097,6 +2864,8 @@ main (int argc, char **argv)
nelements = strlen (prop->value);
format = 8;
}
+ else
+ continue;
XRRChangeOutputProperty (dpy, output->output.xid,
name, type, format, PropModeReplace,
data, nelements);
@@ -2110,7 +2879,7 @@ main (int argc, char **argv)
}
if (setit_1_2)
{
- get_screen ();
+ get_screen (current);
get_crtcs ();
get_outputs ();
set_positions ();
@@ -2181,6 +2950,16 @@ main (int argc, char **argv)
}
/*
+ * Set panning
+ */
+ set_panning ();
+
+ /*
+ * Set gamma on crtc's that belong to the outputs.
+ */
+ set_gamma ();
+
+ /*
* Now apply all of the changes
*/
apply ();
@@ -2194,7 +2973,7 @@ main (int argc, char **argv)
#define ModeShown 0x80000000
- get_screen ();
+ get_screen (current);
get_crtcs ();
get_outputs ();
@@ -2206,18 +2985,25 @@ main (int argc, char **argv)
for (output = outputs; output; output = output->next)
{
XRROutputInfo *output_info = output->output_info;
+ crtc_t *crtc = output->crtc_info;
+ XRRCrtcInfo *crtc_info = crtc ? crtc->crtc_info : NULL;
XRRModeInfo *mode = output->mode_info;
Atom *props;
int j, k, nprop;
Bool *mode_shown;
+ Rotation rotations = output_rotations (output);
printf (" <output name=\"%s\" connected=\"%s\"", output_info->name, connection[output_info->connection]);
if (mode)
{
- printf (" w=\"%d\" h=\"%d\" x=\"%d\" y=\"%d\"",
- mode_width (mode, output->rotation),
- mode_height (mode, output->rotation),
- output->x, output->y);
+ if (crtc_info) {
+ printf (" w=\"%d\" h=\"%d\" x=\"%d\" y=\"%d\"",
+ crtc_info->width, crtc_info->height,
+ crtc_info->x, crtc_info->y);
+ } else {
+ printf (" w=\"%d\" h=\"%d\" x=\"%d\" y=\"%d\"",
+ mode->width, mode->height, output->x, output->y);
+ }
if (verbose)
printf (" id=\"%lx\"", mode->id);
if (output->rotation != RR_Rotate_0 || verbose)
@@ -2237,7 +3023,6 @@ main (int argc, char **argv)
if ((rotations >> i) & 1) {
if (!first) printf (" "); first = False;
printf("%s", direction[i]);
- first = False;
}
}
if (rotations & RR_Reflect_X)
@@ -2247,30 +3032,58 @@ main (int argc, char **argv)
}
if (rotations & RR_Reflect_Y)
{
- if (!first) printf (" "); first = False;
+ if (!first) printf (" ");
printf ("y axis");
}
printf (")");
}
*/
+
if (mode)
{
- printf (" wmm=\"%lu\" hmm=\"%lu\"",
- output_info->mm_width, output_info->mm_height);
+ printf (" wmm=\"%d\" hmm=\"%d\"",
+ (int)output_info->mm_width, (int)output_info->mm_height);
+ }
+
+ if (crtc && crtc->panning_info && crtc->panning_info->width > 0)
+ {
+ XRRPanning *pan = crtc->panning_info;
+ printf (" panning %dx%d+%d+%d",
+ pan->width, pan->height, pan->left, pan->top);
+ if ((pan->track_width != 0 &&
+ (pan->track_left != pan->left ||
+ pan->track_width != pan->width ||
+ pan->border_left != 0 ||
+ pan->border_right != 0)) ||
+ (pan->track_height != 0 &&
+ (pan->track_top != pan->top ||
+ pan->track_height != pan->height ||
+ pan->border_top != 0 ||
+ pan->border_bottom != 0)))
+ printf (" tracking %dx%d+%d+%d border %d/%d/%d/%d",
+ pan->track_width, pan->track_height,
+ pan->track_left, pan->track_top,
+ pan->border_left, pan->border_top,
+ pan->border_right, pan->border_bottom);
}
printf (">\n");
if (verbose)
{
- printf ("\tIdentifier: 0x%lx\n", output->output.xid);
- printf ("\tTimestamp: %lu\n", output_info->timestamp);
+ printf ("\tIdentifier: 0x%x\n", (int)output->output.xid);
+ printf ("\tTimestamp: %d\n", (int)output_info->timestamp);
printf ("\tSubpixel: %s\n", order[output_info->subpixel_order]);
+ if (output->gamma.red != 0.0 && output->gamma.green != 0.0 && output->gamma.blue != 0.0) {
+ printf ("\tGamma: %#.2g:%#.2g:%#.2g\n",
+ output->gamma.red, output->gamma.green, output->gamma.blue);
+ printf ("\tBrightness: %#.2g\n", output->brightness);
+ }
printf ("\tClones: ");
for (j = 0; j < output_info->nclone; j++)
{
- output_t *cloned = find_output_by_xid (output_info->clones[j]);
+ output_t *clone = find_output_by_xid (output_info->clones[j]);
- if (cloned) printf (" %s", cloned->output.string);
+ if (clone) printf (" %s", clone->output.string);
}
printf ("\n");
if (output->crtc_info)
@@ -2283,6 +3096,33 @@ main (int argc, char **argv)
printf (" %d", crtc->crtc.index);
}
printf ("\n");
+ if (output->crtc_info && output->crtc_info->panning_info) {
+ XRRPanning *pan = output->crtc_info->panning_info;
+ printf ("\tPanning: %dx%d+%d+%d\n",
+ pan->width, pan->height, pan->left, pan->top);
+ printf ("\tTracking: %dx%d+%d+%d\n",
+ pan->track_width, pan->track_height,
+ pan->track_left, pan->track_top);
+ printf ("\tBorder: %d/%d/%d/%d\n",
+ pan->border_left, pan->border_top,
+ pan->border_right, pan->border_bottom);
+ }
+ }
+ if (verbose)
+ {
+ int x, y;
+
+ printf ("\tTransform: ");
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ printf (" %f", XFixedToDouble (output->transform.transform.matrix[y][x]));
+ if (y < 2)
+ printf ("\n\t ");
+ }
+ if (output->transform.filter)
+ printf ("\n\t filter: %s", output->transform.filter);
+ printf ("\n");
}
if (verbose || properties)
{
@@ -2318,26 +3158,35 @@ main (int argc, char **argv)
} else if (actual_type == XA_INTEGER &&
actual_format == 32)
{
- printf("\t%s: %d (0x%08x)",
- XGetAtomName (dpy, props[j]),
- *(int32_t*)prop, *(uint32_t*)prop);
+ printf("\t%s: ", XGetAtomName (dpy, props[j]));
+ for (k = 0; k < nitems; k++) {
+ if (k > 0)
+ printf ("\n\t\t\t");
+ printf("%d (0x%08x)",
+ (int)((INT32 *)prop)[k], (int)((INT32 *)prop)[k]);
+ }
if (propinfo->range && propinfo->num_values > 0) {
- printf(" range%s: ",
+ if (nitems > 1)
+ printf ("\n\t\t");
+ printf("\trange%s: ",
(propinfo->num_values == 2) ? "" : "s");
for (k = 0; k < propinfo->num_values / 2; k++)
- printf(" (%ld,%ld)", propinfo->values[k * 2],
- propinfo->values[k * 2 + 1]);
+ printf(" (%d,%d)", (int)propinfo->values[k * 2],
+ (int)propinfo->values[k * 2 + 1]);
}
printf("\n");
} else if (actual_type == XA_ATOM &&
actual_format == 32)
{
- printf("\t%s: %s",
- XGetAtomName (dpy, props[j]),
- XGetAtomName (dpy, *(Atom *)prop));
+ printf("\t%s:", XGetAtomName (dpy, props[j]));
+ for (k = 0; k < nitems; k++) {
+ if (k > 0 && (k & 1) == 0)
+ printf ("\n\t\t");
+ printf("\t%s", XGetAtomName (dpy, ((Atom *)prop)[k]));
+ }
if (!propinfo->range && propinfo->num_values > 0) {
printf("\n\t\tsupported:");
@@ -2351,17 +3200,18 @@ main (int argc, char **argv)
}
}
printf("\n");
-
} else if (actual_format == 8) {
- printf ("\t\t%s: %s%s\n", XGetAtomName (dpy, props[j]),
+ printf ("\t%s: %s%s\n", XGetAtomName (dpy, props[j]),
prop, bytes_after ? "..." : "");
} else {
- printf ("\t\t%s: ????\n", XGetAtomName (dpy, props[j]));
+ char *type = actual_type ? XGetAtomName (dpy, actual_type) : "none";
+ printf ("\t%s: %s(%d) (format %d items %d) ????\n",
+ XGetAtomName (dpy, props[j]),
+ type, (int)actual_type, actual_format, (int)nitems);
}
free(propinfo);
}
- printf(" </output>\n");
}
if (verbose)
@@ -2371,12 +3221,16 @@ main (int argc, char **argv)
XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]);
int f;
- printf (" %s (0x%lx) %6.1fMHz",
- mode->name, mode->id,
- (float)mode->dotClock / 1000000.0);
+ printf (" %s (0x%x) %6.1fMHz",
+ mode->name, (int)mode->id,
+ (double)mode->dotClock / 1000000.0);
for (f = 0; mode_flags[f].flag; f++)
if (mode->modeFlags & mode_flags[f].flag)
printf (" %s", mode_flags[f].string);
+ if (mode == output->mode_info)
+ printf (" *current");
+ if (j < output_info->npreferred)
+ printf (" +preferred");
printf ("\n");
printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
mode->width, mode->hSyncStart, mode->hSyncEnd,
@@ -2414,40 +3268,36 @@ main (int argc, char **argv)
printf (" preferred=\"true\"");
else
printf (" preferred=\"false\"");
- printf("/>\n");
+ printf("/>\n");
}
}
free (mode_shown);
}
-
printf(" </output>\n");
}
-
-/*
- printf(" <unused>\n");
+
+/*
for (m = 0; m < res->nmode; m++)
{
XRRModeInfo *mode = &res->modes[m];
if (!(mode->modeFlags & ModeShown))
{
- printf (" <modeline name=\"%s\" id=\"%x\" mhz=\"%.1f\"",
- mode->name, mode->id,
- (float)mode->dotClock / 1000000.0);
- printf (" hwidth=\"%d\" hstart=\"%d\" hend=\"%d\" htotal=\"%d\" hskew=\"%d=\" hclock=\"%.1fKHz\"",
+ printf (" %s (0x%x) %6.1fMHz\n",
+ mode->name, (int)mode->id,
+ (double)mode->dotClock / 1000000.0);
+ printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
mode->width, mode->hSyncStart, mode->hSyncEnd,
mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
- printf (" vheight=\"%d\" vstart=\"%d\" vend=\"%d\" vtotal=\"%d\" vclock=\"%.1fHz\"/>\n",
+ printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n",
mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
mode_refresh (mode));
}
}
- printf(" </unused>\n");
*/
- printf("</screen>\n");
+ printf("</screen>\n");
exit (0);
}
-#endif
sc = XRRGetScreenInfo (dpy, root);
@@ -2582,11 +3432,9 @@ main (int argc, char **argv)
if (setit && !dryrun) XRRSelectInput (dpy, root,
RRScreenChangeNotifyMask);
if (setit && !dryrun) status = XRRSetScreenConfigAndRate (dpy, sc,
- DefaultRootWindow (dpy),
+ root,
(SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime);
- XRRQueryExtension(dpy, &event_base, &error_base);
-
if (setit && !dryrun && status == RRSetConfigFailed) {
printf ("Failed to change the screen configuration!\n");
ret = 1;