X-Git-Url: http://code.vuplus.com/gitweb/?a=blobdiff_plain;f=xbmc-xrandr.c;h=3c686e20593bab6ee1523d31c3b386b2b084e37a;hb=636ddf5cd77c5e226f5046b147272b3e3eb9f947;hp=db8d438488a9331a4dbb767be1300f2d5c0a7fc9;hpb=45285e8a9300cd754a760560640b75b09f98035e;p=vuplus_xbmc diff --git a/xbmc-xrandr.c b/xbmc-xrandr.c index db8d438..3c686e2 100644 --- a/xbmc-xrandr.c +++ b/xbmc-xrandr.c @@ -32,13 +32,19 @@ #include #include #include /* we share subpixel information */ +#include #include #include #include +#include #include -#if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 2) -#define HAS_RANDR_1_2 1 +#ifndef _X_NORETURN +#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205) +#define _X_NORETURN __attribute((noreturn)) +#else +#define _X_NORETURN +#endif #endif static char *program_name; @@ -48,6 +54,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", @@ -88,7 +96,7 @@ static const struct { { NULL, 0 } }; -static void +static void _X_NORETURN usage(void) { fprintf(stderr, "usage: %s [options]\n", program_name); @@ -105,16 +113,13 @@ usage(void) fprintf(stderr, " -y (reflect in y)\n"); fprintf(stderr, " --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 x\n"); fprintf(stderr, " --fbmm x\n"); fprintf(stderr, " --dpi /\n"); -#if 0 - fprintf(stderr, " --clone\n"); - fprintf(stderr, " --extend\n"); -#endif fprintf(stderr, " --output \n"); fprintf(stderr, " --auto\n"); fprintf(stderr, " --mode \n"); @@ -129,22 +134,30 @@ usage(void) fprintf(stderr, " --below \n"); fprintf(stderr, " --same-as \n"); fprintf(stderr, " --set \n"); + fprintf(stderr, " --scale x\n"); + fprintf(stderr, " --scale-from x\n"); + fprintf(stderr, " --transform ,,,,,,,,\n"); fprintf(stderr, " --off\n"); fprintf(stderr, " --crtc \n"); + fprintf(stderr, " --panning x[++[/x++[////]]]\n"); + fprintf(stderr, " --gamma ::\n"); + fprintf(stderr, " --primary\n"); + fprintf(stderr, " --noprimary\n"); fprintf(stderr, " --newmode \n"); fprintf(stderr, " \n"); fprintf(stderr, " \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 \n"); fprintf(stderr, " --addmode \n"); fprintf(stderr, " --delmode \n"); -#endif exit(1); /*NOTREACHED*/ } -static void +static void _X_NORETURN fatal (const char *format, ...) { va_list ap; @@ -157,6 +170,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) { @@ -187,15 +217,26 @@ reflection_name (Rotation rotation) return "invalid reflection"; } -#if HAS_RANDR_1_2 -typedef enum _policy { - clone, 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), @@ -206,7 +247,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 { @@ -214,7 +259,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 { @@ -226,20 +271,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 { @@ -263,7 +318,7 @@ struct _output { crtc_t *current_crtc_info; name_t mode; - float refresh; + double refresh; XRRModeInfo *mode_info; name_t addmode; @@ -273,8 +328,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 { @@ -326,11 +397,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) @@ -362,28 +434,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; @@ -437,10 +585,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); @@ -450,14 +599,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; @@ -537,11 +735,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++) { @@ -553,7 +751,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); @@ -564,7 +762,6 @@ find_mode (name_t *name, float refresh) bestDist = dist; best = mode; } - break; } } return best; @@ -580,6 +777,7 @@ find_mode_by_xid (RRMode mode) return find_mode (&mode_name, 0); } +#if 0 static XRRModeInfo * find_mode_by_name (char *name) { @@ -588,6 +786,7 @@ find_mode_by_name (char *name) set_name_string (&mode_name, name); return find_mode (&mode_name, 0); } +#endif static XRRModeInfo * @@ -596,12 +795,12 @@ 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) @@ -611,8 +810,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 @@ -627,7 +830,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; @@ -695,6 +898,18 @@ 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; +} + /* * Report only rotations that are supported by all crtcs */ @@ -720,6 +935,7 @@ output_rotations (output_t *output) } return rotation; } +#endif static Bool output_can_use_rotation (output_t *output, Rotation rotation) @@ -741,13 +957,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)) @@ -780,7 +1094,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); @@ -852,10 +1172,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"); @@ -863,7 +1224,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"); } @@ -874,15 +1238,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; @@ -890,7 +1269,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 @@ -905,8 +1297,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; } @@ -922,6 +1315,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) { @@ -934,6 +1427,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) { @@ -944,6 +1451,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, @@ -979,9 +1489,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; } @@ -1040,7 +1560,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; @@ -1060,13 +1580,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 */ @@ -1087,16 +1616,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; @@ -1108,14 +1642,6 @@ apply (void) } /* - * 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 - */ - XGrabServer (dpy); - - /* * Set the screen size */ screen_apply (); @@ -1132,27 +1658,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); @@ -1184,6 +1715,7 @@ get_outputs (void) } } } + output->found = True; /* * Automatic mode -- track connection state and enable/disable outputs @@ -1214,9 +1746,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; @@ -1249,7 +1789,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; @@ -1292,11 +1832,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; @@ -1359,23 +1915,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; } @@ -1424,25 +1980,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; } } @@ -1461,9 +2032,8 @@ set_screen_size (void) } } -#endif - -void + +static void disable_outputs (output_t *outputs) { while (outputs) @@ -1476,7 +2046,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; @@ -1529,21 +2099,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; @@ -1553,11 +2122,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; + } } } /* @@ -1581,6 +2157,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) { @@ -1591,15 +2187,16 @@ 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; - XEvent event; + XRRScreenChangeNotifyEvent event; XRRScreenChangeNotifyEvent *sce; char *display_name = NULL; int i, j; SizeID current_size; short current_rate; - float rate = -1; + double rate = -1; int size = -1; int dirind = 0; Bool setit = False; @@ -1609,19 +2206,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 = clone; 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 (); @@ -1630,6 +2224,7 @@ main (int argc, char **argv) } if (!strcmp("-help", argv[i])) { usage(); + action_requested = True; continue; } if (!strcmp ("--verbose", argv[i])) { @@ -1641,16 +2236,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; } @@ -1659,38 +2263,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; } @@ -1701,8 +2306,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; } @@ -1710,22 +2315,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])) { @@ -1786,7 +2399,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; @@ -1794,7 +2407,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; @@ -1802,7 +2415,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; @@ -1810,7 +2423,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; @@ -1818,11 +2431,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(); @@ -1838,6 +2512,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); @@ -1851,6 +2585,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])) { @@ -1859,26 +2594,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 = clone; - 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])) { @@ -1890,6 +2619,7 @@ main (int argc, char **argv) else automatic = True; setit_1_2 = True; + action_requested = True; continue; } if (!strcmp ("--q12", argv[i])) @@ -1905,25 +2635,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; @@ -1941,6 +2670,7 @@ main (int argc, char **argv) m->action = umode_create; umodes = m; modeit = True; + action_requested = True; continue; } if (!strcmp ("--rmmode", argv[i])) @@ -1953,6 +2683,7 @@ main (int argc, char **argv) m->next = umodes; umodes = m; modeit = True; + action_requested = True; continue; } if (!strcmp ("--addmode", argv[i])) @@ -1967,6 +2698,7 @@ main (int argc, char **argv) m->next = umodes; umodes = m; modeit = True; + action_requested = True; continue; } if (!strcmp ("--delmode", argv[i])) @@ -1981,11 +2713,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; @@ -1993,6 +2727,11 @@ main (int argc, char **argv) query_1 = True; } +/* + if (version) + printf("xrandr program version " VERSION "\n"); +*/ + dpy = XOpenDisplay (display_name); if (dpy == NULL) { @@ -2009,20 +2748,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(); @@ -2070,7 +2811,7 @@ main (int argc, char **argv) if (has_1_2 && propit) { - get_screen (); + get_screen (current); get_crtcs(); get_outputs(); @@ -2082,7 +2823,7 @@ main (int argc, char **argv) { Atom name = XInternAtom (dpy, prop->name, False); Atom type; - int format; + int format = 0; unsigned char *data; int nelements; int int_value; @@ -2094,7 +2835,6 @@ main (int argc, char **argv) XRRPropertyInfo *propinfo; type = AnyPropertyType; - format=0; if (XRRGetOutputProperty (dpy, output->output.xid, name, 0, 100, False, False, @@ -2124,7 +2864,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)) { @@ -2133,6 +2872,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); @@ -2146,7 +2887,7 @@ main (int argc, char **argv) } if (setit_1_2) { - get_screen (); + get_screen (current); get_crtcs (); get_outputs (); set_positions (); @@ -2217,6 +2958,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 (); @@ -2227,11 +2978,10 @@ main (int argc, char **argv) if (query_1_2 || (query && has_1_2 && !query_1)) { output_t *output; - int m; #define ModeShown 0x80000000 - get_screen (); + get_screen (current); get_crtcs (); get_outputs (); @@ -2243,21 +2993,27 @@ 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); +// Rotation rotations = output_rotations (output); printf (" 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=\"%x\"", mode->id); + printf (" id=\"%lx\"", mode->id); if (output->rotation != RR_Rotate_0 || verbose) { printf (" rotation=\"%s\"", @@ -2275,7 +3031,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) @@ -2285,24 +3040,52 @@ 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=\"%d\" hmm=\"%d\"", - output_info->mm_width, output_info->mm_height); + (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%x\n", output->output.xid); - printf ("\tTimestamp: %d\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++) { @@ -2321,6 +3104,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) { @@ -2356,26 +3166,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 *)prop, *(INT32 *)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(" (%d,%d)", 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:"); @@ -2389,17 +3208,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(" \n"); } if (verbose) @@ -2410,11 +3230,15 @@ main (int argc, char **argv) int f; printf (" %s (0x%x) %6.1fMHz", - mode->name, mode->id, - (float)mode->dotClock / 1000000.0); + 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, @@ -2443,7 +3267,7 @@ main (int argc, char **argv) if (strcmp (jmode->name, kmode->name) != 0) continue; mode_shown[k] = True; kmode->modeFlags |= ModeShown; - printf (" id, kmode->name, kmode->width, kmode->height, mode_refresh (kmode)); + printf (" id, kmode->name, kmode->width, kmode->height, mode_refresh (kmode)); if (kmode == output->mode_info) printf (" current=\"true\""); else @@ -2452,40 +3276,36 @@ main (int argc, char **argv) printf (" preferred=\"true\""); else printf (" preferred=\"false\""); - printf("/>\n"); + printf("/>\n"); } } free (mode_shown); } - printf(" \n"); } - -/* - printf(" \n"); + +/* for (m = 0; m < res->nmode; m++) { XRRModeInfo *mode = &res->modes[m]; if (!(mode->modeFlags & ModeShown)) { - printf (" 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(" \n"); */ - printf("\n"); + printf("\n"); exit (0); } -#endif sc = XRRGetScreenInfo (dpy, root); @@ -2620,11 +3440,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; @@ -2640,7 +3458,7 @@ main (int argc, char **argv) printf ("Event received, type = %d\n", event.type); /* update Xlib's knowledge of the event */ - XRRUpdateConfiguration (&event); + XRRUpdateConfiguration ((XEvent*)&event); if (event.type == ConfigureNotify) printf("Received ConfigureNotify Event!\n");