# HG changeset patch # User Henry Zhao # Date 1221010119 25200 # Node ID e82b1d17088be0e496aa1e3edfd3bc310fea7408 # Parent b1c4df796388b2a2d408d4f2eefca8bfefa1ebc5 6684767 Integration of video monitor switch code diff -r b1c4df796388 -r e82b1d17088b open-src/app/xrandr/Makefile --- a/open-src/app/xrandr/Makefile Tue Sep 09 17:37:22 2008 -0700 +++ b/open-src/app/xrandr/Makefile Tue Sep 09 18:28:39 2008 -0700 @@ -30,7 +30,7 @@ # or other dealings in this Software without prior written authorization # of the copyright holder. # -# @(#)Makefile 1.4 08/08/08 +# @(#)Makefile 1.5 08/09/05 # # Package name used in tarballs @@ -40,7 +40,10 @@ MODULE_VERSION=1.2.3 # Patches to apply to source after unpacking, in order -SOURCE_PATCHES = +SOURCE_PATCHES = dispswitch.patch + +# Need to regenerate autoconf/automake files after patching +AUTORECONF=yes # Man pages to apply Sun footer to & attributes to list SUNTOUCHED_MANPAGES=*.man diff -r b1c4df796388 -r e82b1d17088b open-src/app/xrandr/dispswitch.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/open-src/app/xrandr/dispswitch.patch Tue Sep 09 18:28:39 2008 -0700 @@ -0,0 +1,1948 @@ +diff -urN old/dispswitch.c new/dispswitch.c +--- dispswitch.c 1969-12-31 16:00:00.000000000 -0800 ++++ dispswitch.c 2008-09-07 21:45:43.578226000 -0700 +@@ -0,0 +1,1847 @@ ++/* ++ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. ++ * Copyright © 2002 Hewlett Packard Company, Inc. ++ * Copyright © 2006 Intel Corporation ++ * Copyright © 2008 Sun Microsystems, Inc. ++ * ++ * Permission to use, copy, modify, distribute, and sell this software and its ++ * documentation for any purpose is hereby granted without fee, provided that ++ * the above copyright notice appear in all copies and that both that copyright ++ * notice and this permission notice appear in supporting documentation, and ++ * that the name of the copyright holders not be used in advertising or ++ * publicity pertaining to distribution of the software without specific, ++ * written prior permission. The copyright holders make no representations ++ * about the suitability of this software for any purpose. It is provided "as ++ * is" without express or implied warranty. ++ * ++ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO ++ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR ++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, ++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE ++ * OF THIS SOFTWARE. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++static char *program_name; ++static Display *dpy = NULL; ++static Window root; ++static int screen; ++static Bool nosideview = False; ++static Bool verbose = False; ++static Bool testrun = False; ++static int haderror = 0; ++static struct timeval time_val; ++static Rotation init_rotation; ++static int init_x; ++static int init_y; ++static Bool use_init_pos = False; ++ ++static void ++usage(void) ++{ ++ fprintf(stderr, "usage: %s [options]\n", program_name); ++ fprintf(stderr, " where options are:\n"); ++ fprintf(stderr, " -display or -d \n"); ++ fprintf(stderr, " -key or -k \n"); ++ fprintf(stderr, " -mod or -m \n"); ++ fprintf(stderr, " -help\n"); ++ fprintf(stderr, " -nosideview\n"); ++ fprintf(stderr, " -verbose or -v\n"); ++ fprintf(stderr, " -testrun\n"); ++ exit(1); ++ /*NOTREACHED*/ ++} ++ ++static void ++fatal (const char *format, ...) ++{ ++ va_list ap; ++ ++ va_start (ap, format); ++ fprintf (stderr, "%s exiting: ", program_name); ++ vfprintf (stderr, format, ap); ++ va_end (ap); ++ exit (1); ++ /*NOTREACHED*/ ++} ++ ++static int ++curhandler ( ++ Display *const errdisplay, ++ XErrorEvent *const errevent) ++{ ++ haderror = errevent -> error_code; ++ return (0); ++} ++ ++typedef enum _relation { ++ left_of, right_of, above, below, same_as, ++} relation_t; ++ ++typedef enum _changes { ++ changes_none = 0, ++ changes_crtc = (1 << 0), ++ changes_mode = (1 << 1), ++ changes_relation = (1 << 2), ++ changes_position = (1 << 3), ++} changes_t; ++ ++typedef enum _name_kind { ++ name_none = 0, ++ name_string = (1 << 0), ++ name_xid = (1 << 1), ++ name_index = (1 << 2), ++} name_kind_t; ++ ++typedef struct { ++ name_kind_t kind; ++ char *string; ++ XID xid; ++ int index; ++} name_t; ++ ++typedef struct _crtc crtc_t; ++typedef struct _output output_t; ++ ++struct _crtc { ++ name_t crtc; ++ XRRCrtcInfo *crtc_info; ++ ++ XRRModeInfo *mode_info; ++ int x; ++ int y; ++ Rotation rotation; ++ output_t **outputs; ++ int noutput; ++}; ++ ++struct _output { ++ struct _output *next; ++ ++ changes_t changes; ++ ++ name_t output; ++ XRROutputInfo *output_info; ++ ++ name_t crtc; ++ crtc_t *crtc_info; ++ crtc_t *current_crtc_info; ++ ++ name_t mode; ++ float refresh; ++ XRRModeInfo *mode_info; ++ ++ name_t addmode; ++ ++ relation_t relation; ++ struct _output *relative_to; ++ ++ int x, y; ++ Rotation rotation; ++}; ++ ++static output_t *outputs = NULL; ++static output_t **outputs_tail = &outputs; ++static crtc_t *crtcs = NULL; ++static int num_crtcs; ++static XRRScreenResources *res = NULL; ++static int fb_width = 0, fb_height = 0; ++static int fb_width_mm = 0, fb_height_mm = 0; ++static float dpi = 0.0; ++static Bool dryrun = False; ++static int minWidth, maxWidth, minHeight, maxHeight; ++ ++#define MAX_OUTPUT 3 ++#define MAX_MODIFIERS 10 ++ ++typedef struct _con_output con_output_t; ++ ++struct _con_output { ++ output_t *output; ++ XRRModeInfo **smodes; ++ int nsmodes; ++ Bool on; ++}; ++ ++typedef struct _mod_key_table mod_key_table_t; ++ ++struct _mod_key_table { ++ char *modname; ++ unsigned int mod; ++}; ++ ++static con_output_t con_outputs[MAX_OUTPUT]; ++static con_output_t dis_con_outputs[MAX_OUTPUT]; ++static XRRModeInfo *start_mode[MAX_OUTPUT]; ++static XRRModeInfo *new_mode[MAX_OUTPUT]; ++static int start = 0; ++static int ncon; ++static int dis_ncon; ++static Bool do_not_switch = False; ++static Bool did_init = False; ++ ++static mod_key_table_t mod_key_table [MAX_MODIFIERS] = { ++ {"none", 0}, ++ {"shift", ShiftMask}, ++ {"lock", LockMask}, ++ {"control", ControlMask}, ++ {"mod1", Mod1Mask}, ++ {"mod2", Mod2Mask}, ++ {"mod3", Mod3Mask}, ++ {"mod4", Mod4Mask}, ++ {"mod5", Mod5Mask}, ++ {"any", AnyModifier} ++}; ++ ++static int ++mode_height (XRRModeInfo *mode_info, Rotation rotation) ++{ ++ switch (rotation & 0xf) { ++ case RR_Rotate_0: ++ case RR_Rotate_180: ++ return mode_info->height; ++ case RR_Rotate_90: ++ case RR_Rotate_270: ++ return mode_info->width; ++ default: ++ return 0; ++ } ++} ++ ++static int ++mode_width (XRRModeInfo *mode_info, Rotation rotation) ++{ ++ switch (rotation & 0xf) { ++ case RR_Rotate_0: ++ case RR_Rotate_180: ++ return mode_info->width; ++ case RR_Rotate_90: ++ case RR_Rotate_270: ++ return mode_info->height; ++ default: ++ return 0; ++ } ++} ++ ++/* v refresh frequency in Hz */ ++static float ++mode_refresh (XRRModeInfo *mode_info) ++{ ++ float rate; ++ ++ if (mode_info->hTotal && mode_info->vTotal) ++ rate = ((float) mode_info->dotClock / ++ ((float) mode_info->hTotal * (float) mode_info->vTotal)); ++ else ++ rate = 0; ++ return rate; ++} ++ ++ ++static void ++init_name (name_t *name) ++{ ++ name->kind = name_none; ++} ++ ++static void ++set_name_string (name_t *name, char *string) ++{ ++ name->kind |= name_string; ++ name->string = string; ++} ++ ++static void ++set_name_xid (name_t *name, XID xid) ++{ ++ name->kind |= name_xid; ++ name->xid = xid; ++} ++ ++static void ++set_name_index (name_t *name, int index) ++{ ++ name->kind |= name_index; ++ name->index = index; ++} ++ ++static void ++set_name_all (name_t *name, name_t *old) ++{ ++ if (old->kind & name_xid) ++ name->xid = old->xid; ++ if (old->kind & name_string) ++ name->string = old->string; ++ if (old->kind & name_index) ++ name->index = old->index; ++ name->kind |= old->kind; ++} ++ ++static output_t * ++add_output (void) ++{ ++ output_t *output = calloc (1, sizeof (output_t)); ++ ++ if (!output) ++ fatal ("out of memory"); ++ output->next = NULL; ++ *outputs_tail = output; ++ outputs_tail = &output->next; ++ return output; ++} ++ ++static output_t * ++find_output (name_t *name) ++{ ++ output_t *output; ++ ++ for (output = outputs; output; output = output->next) ++ { ++ name_kind_t common = name->kind & output->output.kind; ++ ++ if ((common & name_xid) && name->xid == output->output.xid) ++ break; ++ if ((common & name_string) && !strcmp (name->string, output->output.string)) ++ break; ++ if ((common & name_index) && name->index == output->output.index) ++ break; ++ } ++ return output; ++} ++ ++static output_t * ++find_output_by_xid (RROutput output) ++{ ++ name_t output_name; ++ ++ init_name (&output_name); ++ set_name_xid (&output_name, output); ++ return find_output (&output_name); ++} ++ ++static crtc_t * ++find_crtc (name_t *name) ++{ ++ int c; ++ crtc_t *crtc = NULL; ++ ++ for (c = 0; c < num_crtcs; c++) ++ { ++ name_kind_t common; ++ ++ crtc = &crtcs[c]; ++ common = name->kind & crtc->crtc.kind; ++ ++ if ((common & name_xid) && name->xid == crtc->crtc.xid) ++ break; ++ if ((common & name_string) && !strcmp (name->string, crtc->crtc.string)) ++ break; ++ if ((common & name_index) && name->index == crtc->crtc.index) ++ break; ++ crtc = NULL; ++ } ++ return crtc; ++} ++ ++static crtc_t * ++find_crtc_by_xid (RRCrtc crtc) ++{ ++ name_t crtc_name; ++ ++ init_name (&crtc_name); ++ set_name_xid (&crtc_name, crtc); ++ return find_crtc (&crtc_name); ++} ++ ++static XRRModeInfo * ++find_mode (name_t *name) ++{ ++ int m; ++ XRRModeInfo *best = NULL; ++ ++ for (m = 0; m < res->nmode; m++) ++ { ++ XRRModeInfo *mode = &res->modes[m]; ++ if ((name->kind & name_xid) && name->xid == mode->id) ++ { ++ best = mode; ++ break; ++ } ++ } ++ return best; ++} ++ ++static XRRModeInfo * ++find_mode_by_xid (RRMode mode) ++{ ++ name_t mode_name; ++ ++ init_name (&mode_name); ++ set_name_xid (&mode_name, mode); ++ return find_mode (&mode_name); ++} ++ ++static void ++set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info) ++{ ++ crtc_t *crtc; ++ ++ /* 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); ++ ++ /* set output name and info */ ++ if (!(output->output.kind & name_xid)) ++ set_name_xid (&output->output, xid); ++ if (!(output->output.kind & name_string)) ++ set_name_string (&output->output, output_info->name); ++ output->output_info = output_info; ++ ++ crtc = find_crtc_by_xid (output->output_info->crtc); ++ /* set position */ ++ if (crtc && crtc->crtc_info) { ++ output->x = crtc->crtc_info->x; ++ output->y = crtc->crtc_info->y; ++ } ++ ++ /* set rotation */ ++ output->rotation &= ~0xf; ++ if (crtc && crtc->crtc_info) ++ output->rotation |= (crtc->crtc_info->rotation & 0xf); ++ else ++ output->rotation = RR_Rotate_0; ++ ++} ++ ++static void ++get_crtcs (void) ++{ ++ int c; ++ ++ num_crtcs = res->ncrtc; ++ if (crtcs) ++ { ++ for (c = 0; c < res->ncrtc; c++) ++ { ++ if (crtcs[c].crtc_info) ++ XRRFreeCrtcInfo (crtcs[c].crtc_info); ++ } ++ free (crtcs); ++ crtcs = NULL; ++ } ++ ++ crtcs = calloc (num_crtcs, sizeof (crtc_t)); ++ if (!crtcs) fatal ("out of memory"); ++ ++ for (c = 0; c < res->ncrtc; c++) ++ { ++ XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]); ++ 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]); ++ crtcs[c].crtc_info = crtc_info; ++ if (crtc_info->mode == None) ++ { ++ crtcs[c].mode_info = NULL; ++ crtcs[c].x = 0; ++ crtcs[c].y = 0; ++ crtcs[c].rotation = RR_Rotate_0; ++ } ++ } ++} ++ ++static void ++crtc_add_output (crtc_t *crtc, output_t *output) ++{ ++ if (crtc->outputs) ++ crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *)); ++ else ++ { ++ crtc->outputs = calloc (1, sizeof (output_t *)); ++ crtc->x = output->x; ++ crtc->y = output->y; ++ crtc->rotation = output->rotation; ++ crtc->mode_info = output->mode_info; ++ } ++ if (!crtc->outputs) fatal ("out of memory"); ++ crtc->outputs[crtc->noutput++] = output; ++} ++ ++static void ++set_crtcs (void) ++{ ++ output_t *output; ++ int i; ++ ++ for (i = 0; i < ncon; i++) { ++ output = con_outputs[i].output; ++ if (!output->mode_info) continue; ++ if (output->crtc_info) ++ crtc_add_output (output->crtc_info, output); ++ } ++} ++ ++static void ++reset_crtcs_for_outputs (void) ++{ ++ output_t *output; ++ ++ for (output = outputs; output; output = output->next) ++ { ++ if ((output->crtc_info) && (output->crtc_info->outputs)) { ++ free (output->crtc_info->outputs); ++ output->crtc_info = NULL; ++ } ++ } ++} ++ ++static Status ++crtc_disable (crtc_t *crtc) ++{ ++ if (verbose) ++ fprintf (stderr, "crtc %d (%x) : disable\n", crtc->crtc.index, crtc->crtc.xid); ++ ++ if (dryrun) ++ return RRSetConfigSuccess; ++ ++ return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, ++ 0, 0, None, RR_Rotate_0, NULL, 0); ++} ++ ++static Status ++crtc_revert (crtc_t *crtc) ++{ ++ XRRCrtcInfo *crtc_info = crtc->crtc_info; ++ ++ if (verbose) ++ fprintf (stderr, "crtc %d: revert\n", crtc->crtc.index); ++ ++ if (dryrun) ++ return RRSetConfigSuccess; ++ return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, ++ crtc_info->x, crtc_info->y, ++ crtc_info->mode, crtc_info->rotation, ++ crtc_info->outputs, crtc_info->noutput); ++} ++ ++static Status ++crtc_apply (crtc_t *crtc) ++{ ++ RROutput *rr_outputs; ++ int o; ++ Status s; ++ RRMode mode = None; ++ ++ if (!crtc->mode_info) ++ return RRSetConfigSuccess; ++ ++ rr_outputs = calloc (crtc->noutput, sizeof (RROutput)); ++ if (!rr_outputs) ++ return BadAlloc; ++ for (o = 0; o < crtc->noutput; o++) ++ rr_outputs[o] = crtc->outputs[o]->output.xid; ++ mode = crtc->mode_info->id; ++ if (verbose) { ++ fprintf (stderr, "crtc %d (%x) : %12s %6.1f +%d+%d", crtc->crtc.index, ++ crtc->crtc.xid, ++ crtc->mode_info->name, mode_refresh (crtc->mode_info), ++ crtc->x, crtc->y); ++ for (o = 0; o < crtc->noutput; o++) ++ fprintf (stderr, " \"%s\"", crtc->outputs[o]->output.string); ++ fprintf (stderr, "\n"); ++ } ++ if (dryrun) ++ s = RRSetConfigSuccess; ++ else ++ s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, ++ crtc->x, crtc->y, mode, crtc->rotation, ++ rr_outputs, crtc->noutput); ++ free (rr_outputs); ++ return s; ++} ++ ++static void ++screen_revert (void) ++{ ++ if (verbose) ++ fprintf (stderr, "screen %d: revert\n", screen); ++ ++ if (dryrun) ++ return; ++ XRRSetScreenSize (dpy, root, ++ DisplayWidth (dpy, screen), ++ DisplayHeight (dpy, screen), ++ DisplayWidthMM (dpy, screen), ++ DisplayHeightMM (dpy, screen)); ++} ++ ++static void ++screen_apply (void) ++{ ++ /* comment it out because DisplayWidth() does not reflect the ++ change of fb_width and fb_height previously set by ++ XRRSetScreenSize() ++ */ ++ /* ++ if (fb_width == DisplayWidth (dpy, screen) && ++ fb_height == DisplayHeight (dpy, screen) && ++ fb_width_mm == DisplayWidthMM (dpy, screen) && ++ fb_height_mm == DisplayHeightMM (dpy, screen)) ++ { ++ return; ++ } ++ */ ++ ++ if (verbose) ++ fprintf (stderr, "screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen, ++ fb_width, fb_height, fb_width_mm, fb_height_mm, dpi); ++ if (dryrun) ++ return; ++ XRRSetScreenSize (dpy, root, fb_width, fb_height, ++ fb_width_mm, fb_height_mm); ++ ++} ++ ++static void ++revert (void) ++{ ++ int c; ++ ++ /* first disable all crtcs */ ++ for (c = 0; c < res->ncrtc; c++) ++ crtc_disable (&crtcs[c]); ++ /* next reset screen size */ ++ screen_revert (); ++ /* now restore all crtcs */ ++ for (c = 0; c < res->ncrtc; c++) ++ crtc_revert (&crtcs[c]); ++} ++ ++/* ++ * uh-oh, something bad happened in the middle of changing ++ * the configuration. Revert to the previous configuration ++ * and bail ++ */ ++static void ++panic (Status s, crtc_t *crtc) ++{ ++ int c = crtc->crtc.index; ++ char *message; ++ ++ switch (s) { ++ case RRSetConfigSuccess: message = "succeeded"; break; ++ case BadAlloc: message = "out of memory"; break; ++ case RRSetConfigFailed: message = "failed"; break; ++ case RRSetConfigInvalidConfigTime: message = "invalid config time"; break; ++ case RRSetConfigInvalidTime: message = "invalid time"; break; ++ default: message = "unknown failure"; break; ++ } ++ ++ fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message); ++ revert (); ++ exit (1); ++} ++ ++static void ++apply (void) ++{ ++ Status s; ++ int c; ++ ++ /* ++ * Turn off any crtcs which are to be disabled or which are ++ * larger than the target size ++ */ ++ for (c = 0; c < res->ncrtc; c++) ++ { ++ crtc_t *crtc = &crtcs[c]; ++ XRRCrtcInfo *crtc_info = crtc->crtc_info; ++ ++ /* ++ * if this crtc is already disabled, skip it ++ * Note server sets crtc_info->mode (before change) ++ */ ++ if (crtc_info->mode == None) ++ continue; ++ ++ /* ++ * If this crtc is to be left enabled, make ++ * sure the old size fits then new screen ++ * When crtc->mode_info is null, the crtc is to be ++ * disabled. Note set_crtcs () sets crtc->mode_info for ++ * new mode (to be changed to). ++ */ ++ if (crtc->mode_info) ++ { ++ XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode); ++ int x, y, w, h; ++ ++ 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); ++ ++ /* if it fits, skip it */ ++ if (x + w <= fb_width && y + h <= fb_height) ++ continue; ++ } ++ s = crtc_disable (crtc); ++ if (s != RRSetConfigSuccess) ++ panic (s, crtc); ++ } ++ ++ /* ++ * 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 (); ++ ++ /* ++ * Set crtcs ++ */ ++ ++ for (c = 0; c < res->ncrtc; c++) ++ { ++ crtc_t *crtc = &crtcs[c]; ++ ++ s = crtc_apply (crtc); ++ if (s != RRSetConfigSuccess) ++ panic (s, crtc); ++ } ++ /* ++ * Release the server grab and let all clients ++ * respond to the updated state ++ */ ++ XUngrabServer (dpy); ++} ++ ++/* ++ * Use current output state to complete the output list ++ */ ++static void ++get_outputs (void) ++{ ++ int o; ++ ++ 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]); ++ set_name_xid (&output_name, res->outputs[o]); ++ set_name_index (&output_name, o); ++ set_name_string (&output_name, output_info->name); ++ output = find_output (&output_name); ++ if (!output) ++ { ++ output = add_output (); ++ set_name_all (&output->output, &output_name); ++ } ++ ++ set_output_info (output, res->outputs[o], output_info); ++ } ++} ++ ++ ++/* ++ * Test whether 'crtc' can be used for 'output' ++ */ ++static Bool ++check_crtc_for_output (crtc_t *crtc, output_t *output) ++{ ++ int i; ++ int l; ++ output_t *other; ++ ++ for (i = 0; i < ncon; i++) ++ { ++ other = con_outputs[i].output; ++ ++ if (other == output) ++ continue; ++ ++ if (other->mode_info == NULL) ++ continue; ++ ++ if (other->crtc_info != crtc) ++ continue; ++ ++ /* see if the output connected to the crtc can clone to this output */ ++ for (l = 0; l < output->output_info->nclone; l++) ++ if (output->output_info->clones[l] == other->output.xid) ++ break; ++ /* not on the list, can't clone */ ++ if (l == output->output_info->nclone) ++ return False; ++ } ++ ++ if (crtc->noutput) ++ { ++ for (i = 0; i < crtc->noutput; i++) ++ /* Check if the output is to be turned on */ ++ if (crtc->outputs[i]->mode_info) { ++ /* make sure the state matches */ ++ if (crtc->mode_info != output->mode_info) ++ return False; ++ if (crtc->x != output->x) ++ return False; ++ if (crtc->y != output->y) ++ return False; ++ if (crtc->rotation != output->rotation) ++ return False; ++ } ++ } ++ return True; ++} ++ ++static crtc_t * ++find_crtc_for_output (output_t *output) ++{ ++ int c; ++ ++ for (c = 0; c < output->output_info->ncrtc; c++) ++ { ++ crtc_t *crtc; ++ ++ crtc = find_crtc_by_xid (output->output_info->crtcs[c]); ++ if (!crtc) fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); ++ ++ if (check_crtc_for_output (crtc, output)) ++ return crtc; ++ } ++ return NULL; ++} ++ ++static void ++set_positions (void) ++{ ++ Bool keep_going; ++ Bool any_set; ++ int min_x, min_y; ++ int i; ++ ++ for (;;) ++ { ++ any_set = False; ++ keep_going = False; ++ for (i = 0; i < ncon; i++) ++ { ++ output_t *output = con_outputs[i].output; ++ output_t *relation; ++ ++ if (!(output->changes & changes_relation)) continue; ++ ++ if (output->mode_info == NULL) continue; ++ ++ relation = output->relative_to; ++ ++ if (relation->mode_info == NULL) ++ { ++ output->x = 0; ++ output->y = 0; ++ output->changes |= changes_position; ++ any_set = True; ++ continue; ++ } ++ /* ++ * Make sure the dependent object has been set in place ++ */ ++ if ((relation->changes & changes_relation) && ++ !(relation->changes & changes_position)) ++ { ++ keep_going = True; ++ continue; ++ } ++ ++ switch (output->relation) { ++ case left_of: ++ output->y = relation->y; ++ output->x = relation->x - mode_width (output->mode_info, output->rotation); ++ break; ++ case right_of: ++ output->y = relation->y; ++ output->x = relation->x + mode_width (relation->mode_info, relation->rotation); ++ break; ++ case above: ++ output->x = relation->x; ++ output->y = relation->y - mode_height (output->mode_info, output->rotation); ++ break; ++ case below: ++ output->x = relation->x; ++ output->y = relation->y + mode_height (relation->mode_info, relation->rotation); ++ break; ++ case same_as: ++ output->x = relation->x; ++ output->y = relation->y; ++ } ++ output->changes |= changes_position; ++ relation->changes |= changes_position; ++ any_set = True; ++ } ++ if (!keep_going) ++ break; ++ if (!any_set) ++ fatal ("loop in relative position specifications\n"); ++ } ++ ++ /* ++ * Now normalize positions so the upper left corner of all outputs is at 0,0 ++ */ ++ min_x = 32768; ++ min_y = 32768; ++ for (i = 0; i < ncon; i++) ++ { ++ output_t *output = con_outputs[i].output; ++ ++ if (output->mode_info == NULL) continue; ++ ++ if (output->x < min_x) min_x = output->x; ++ if (output->y < min_y) min_y = output->y; ++ } ++ if (min_x || min_y) ++ { ++ /* move all outputs */ ++ for (i = 0; i < ncon; i++) ++ { ++ output_t *output = con_outputs[i].output; ++ ++ if (output->mode_info == NULL) continue; ++ ++ output->x -= min_x; ++ output->y -= min_y; ++ output->changes |= changes_position; ++ } ++ } ++} ++ ++static Bool ++set_screen_size (void) ++{ ++ int i; ++ ++ fb_width = fb_height = 0; ++ ++ for (i = 0; i < ncon; i++) ++ { ++ output_t *output = con_outputs[i].output; ++ XRRModeInfo *mode_info = output->mode_info; ++ int x, y, w, h; ++ ++ if (!mode_info) continue; ++ ++ x = output->x; ++ y = output->y; ++ w = mode_width (mode_info, output->rotation); ++ h = mode_height (mode_info, output->rotation); ++ if (x + w > fb_width) fb_width = x + w; ++ if (y + h > fb_height) fb_height = y + h; ++ } ++ ++ if (fb_width > maxWidth || fb_height > maxHeight) { ++ if (verbose) ++ fprintf (stderr, "screen cannot be larger than %dx%d (desired size %dx%d)\n", ++ maxWidth, maxHeight, fb_width, fb_height); ++ return False; ++ } ++ ++ if (fb_width < minWidth) fb_width = minWidth; ++ if (fb_height < minHeight) fb_height = minHeight; ++ ++ return True; ++} ++ ++static void ++disable_outputs (output_t *outputs) ++{ ++ while (outputs) ++ { ++ outputs->crtc_info = NULL; ++ outputs = outputs->next; ++ } ++} ++ ++/* ++ * find the best mapping from output to crtc available ++ */ ++static int ++pick_crtcs_score (output_t *outputs) ++{ ++ output_t *output; ++ int best_score; ++ int my_score; ++ int score; ++ crtc_t *best_crtc; ++ int c; ++ ++ if (!outputs) ++ return 0; ++ ++ output = outputs; ++ outputs = outputs->next; ++ /* ++ * Score with this output disabled ++ */ ++ output->crtc_info = NULL; ++ best_score = pick_crtcs_score (outputs); ++ if (output->mode_info == NULL) ++ return best_score; ++ ++ best_crtc = NULL; ++ /* ++ * Now score with this output any valid crtc ++ */ ++ for (c = 0; c < output->output_info->ncrtc; c++) ++ { ++ crtc_t *crtc; ++ ++ crtc = find_crtc_by_xid (output->output_info->crtcs[c]); ++ if (!crtc) ++ fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); ++ ++ /* reset crtc allocation for following outputs */ ++ disable_outputs (outputs); ++ if (!check_crtc_for_output (crtc, output)) ++ continue; ++ ++ my_score = 1000; ++ /* slight preference for existing connections */ ++ if (crtc == output->current_crtc_info) ++ my_score++; ++ ++ output->crtc_info = crtc; ++ score = my_score + pick_crtcs_score (outputs); ++ if (score > best_score) ++ { ++ best_crtc = crtc; ++ 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 ++ */ ++ (void) pick_crtcs_score (outputs); ++ ++ return best_score; ++} ++ ++/* ++ * Pick crtcs for any changing outputs that don't have one ++ */ ++static Bool ++pick_crtcs (void) ++{ ++ output_t *output; ++ int i; ++ ++ /* ++ * First try to match up newly enabled outputs with spare crtcs ++ */ ++ for (i = 0; i < ncon; i++) ++ { ++ output = con_outputs[i].output; ++ ++ if (output->mode_info) ++ { ++ 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; ++ else { ++ if (verbose) ++ fprintf(stderr, "picked crtc %x for output %d (%s)\n", ++ output->crtc_info->crtc.xid, i, output->output_info->name); ++ } ++ } ++ } ++ } ++ ++ /* ++ * Everyone is happy ++ */ ++ if (i == ncon) ++ return True; ++ /* ++ * When the simple way fails, see if there is a way ++ * to swap crtcs around and make things work ++ */ ++ for (output = outputs; output; output = output->next) ++ output->current_crtc_info = output->crtc_info; ++ pick_crtcs_score (outputs); ++ for (output = outputs; output; output = output->next) ++ { ++ if (output->mode_info && !output->crtc_info) { ++ if (verbose) ++ fprintf (stderr, "cannot find crtc for output %s\n", ++ output->output.string); ++ return False; ++ } ++ } ++ ++ return True; ++} ++ ++static Bool ++probe_and_check_output_changes (void) { ++ XRRScreenResources *new_res = NULL; ++ int changed = False; ++ int i; ++ ++ new_res = XRRGetScreenResources (dpy, root); ++ if (!new_res) ++ fatal ("could not get screen resources"); ++ ++ if ((new_res->noutput != res->noutput) || (new_res->nmode != res->nmode) || ++ (new_res->ncrtc != res->ncrtc)) ++ changed = True; ++ else { ++ for (i = 0; i < new_res->noutput; i++) ++ if (new_res->outputs[i] != res->outputs[i]) { ++ changed = True; ++ break; ++ } ++ for (i = 0; i < new_res->nmode; i++) ++ if (new_res->modes[i].id != res->modes[i].id) { ++ changed = True; ++ break; ++ } ++ for (i = 0; i < new_res->ncrtc; i++) { ++ crtc_t *crtc = NULL; /* old */ ++ XRRCrtcInfo *crtc_info = NULL; /* new */ ++ ++ crtc = find_crtc_by_xid (res->crtcs[i]); ++ crtc_info = XRRGetCrtcInfo (dpy, new_res, ++ new_res->crtcs[i]); ++ ++ if (!crtc || !crtc_info) { ++ changed = True; ++ break; ++ } ++ if (!crtc->mode_info && !find_mode_by_xid (crtc_info->mode)) ++ continue; ++ if ((crtc_info->x != crtc->x) || ++ (crtc_info->y != crtc->y) || ++ (find_mode_by_xid (crtc_info->mode) != crtc->mode_info) || ++ (crtc_info->rotation != crtc->rotation)) { ++ changed = True; ++ break; ++ } ++ } ++ } ++ ++ if (changed) { ++ if (res) ++ XRRFreeScreenResources(res); ++ res = new_res; ++ ++ if (verbose) ++ fprintf(stderr, "probed: output status changed\n"); ++ return True; ++ } ++ ++ if (verbose) ++ fprintf(stderr, "probed: no output status change\n"); ++ return False; ++} ++ ++static Bool ++need_probe (void) { ++ struct timeval cur_time_val; ++ long long cur, prev; ++ ++ X_GETTIMEOFDAY(&cur_time_val); ++ cur = (long long) cur_time_val.tv_sec * 1000000 + cur_time_val.tv_usec; ++ prev =(long long) time_val.tv_sec * 1000000 + time_val.tv_usec; ++ if (((cur - prev) < 0) || ((cur - prev) > 5000000)) ++ return True; ++ else ++ return False; ++} ++ ++static int ++mode_sort (const void *p1, void *p2) ++{ ++ XRRModeInfo *mi1 = * (XRRModeInfo **) p1; ++ XRRModeInfo *mi2 = * (XRRModeInfo **) p2; ++ ++ if ((mi1->width == mi2->width) && (mi1->height == mi2->height)) { ++ if (mode_refresh(mi1) && mode_refresh(mi2)) { ++ if (mode_refresh(mi1) < mode_refresh(mi2)) ++ return 1; ++ if (mode_refresh(mi1) > mode_refresh(mi2)) ++ return -1; ++ } else ++ return 0; ++ } ++ ++ if ((mi1->width == mi2->width) && (mi1->height < mi2->height)) ++ return 1; ++ if ((mi1->width == mi2->width) && (mi1->height > mi2->height)) ++ return -1; ++ if (mi1->width < mi2->width) ++ return 1; ++ if (mi1->width > mi2->width) ++ return -1; ++ ++ return 0; ++} ++ ++static int ++output_sort (const void *p1, const void *p2) { ++ con_output_t co1 = * (con_output_t *) p1; ++ con_output_t co2 = * (con_output_t *) p2; ++ int ncrtc1 = co1.output->output_info->ncrtc; ++ int ncrtc2 = co2.output->output_info->ncrtc; ++ char *name1 = co1.output->output_info->name; ++ char *name2 = co2.output->output_info->name; ++ ++ if (ncrtc1 == ncrtc2) ++ return (strcmp(name1, name2)); ++ if (ncrtc1 < ncrtc2) ++ return -1; ++ ++ return 1; ++} ++ ++static Bool ++get_common_mode(con_output_t *c0, con_output_t *c1, int *m0, int *m1) { ++ int i, j; ++ int i1 = -1, j1 = -1, i2 = -1, j2 = -1; ++ int x, y, w, h; ++ output_t *output = c0->output; ++ ++ *m0 = -1; ++ *m0 = -1; ++ if (!c0 ||!c1 || !c0->smodes || !c1->smodes) ++ return False; ++ ++ /* first try to find mode with common same size */ ++ for (i = 0; i < c0->nsmodes; i ++) { ++ for (j = 0; j < c1->nsmodes; j ++) ++ if ((c0->smodes[i]->width == c1->smodes[j]->width) && ++ (c0->smodes[i]->height == c1->smodes[j]->height)) { ++ x = output->x; ++ y = output->y; ++ w = mode_width (c0->smodes[i], output->rotation); ++ h = mode_height (c0->smodes[i], output->rotation); ++ if ((x + w <= maxWidth) && (y + h <= maxHeight)) { ++ i1 = i; j1 = j; ++ break; ++ } ++ } ++ if ((i1 != -1) && (j1 != -1)) ++ break; ++ } ++ ++ if ((i1 == -1) && (j1 == -1)) ++ return False; ++ ++ /* then try to find mode with common id for possible cloning */ ++ for (i = 0; i < c0->nsmodes; i ++) { ++ for (j = 0; j < c1->nsmodes; j ++) ++ if (c0->smodes[i] == c1->smodes[j]) { ++ x = output->x; ++ y = output->y; ++ w = mode_width (c0->smodes[i], output->rotation); ++ h = mode_height (c0->smodes[i], output->rotation); ++ if ((x + w <= maxWidth) && (y + h <= maxHeight)) { ++ i2 = i; j2 = j; ++ break; ++ } ++ } ++ if ((i2 != -1) && (j2 != -1)) ++ break; ++ } ++ ++ if ((i2 == -1) && (j2 == -1)) { ++ *m0 = i1; ++ *m1 = j1; ++ } else { ++ /* use common id if it is not smaller */ ++ if ((mode_width (c0->smodes[i1], output->rotation) > ++ mode_width (c0->smodes[i2], output->rotation)) && ++ (mode_height (c0->smodes[i1], output->rotation) > ++ mode_height (c0->smodes[i2], output->rotation))) { ++ *m0 = i1; ++ *m1 = j1; ++ } else { ++ *m0 = i2; ++ *m1 = j2; ++ } ++ } ++ ++ return True; ++} ++ ++static XRRModeInfo * ++get_largest_mode (con_output_t *c, XRRModeInfo *start_mode) { ++ int i, found = False; ++ output_t *output = c->output; ++ ++ for (i = 0; i < c->nsmodes; i++) { ++ XRRModeInfo *mode_info = c->smodes[i]; ++ int x, y, w, h; ++ ++ if (!found && (start_mode != mode_info)) ++ continue; ++ else ++ found = True; ++ ++ if (mode_info) { ++ x = output->x; ++ y = output->y; ++ w = mode_width (mode_info, output->rotation); ++ h = mode_height (mode_info, output->rotation); ++ if ((x + w <= maxWidth) && (y + h <= maxHeight)) ++ break; ++ } ++ } ++ ++ if (i < c->nsmodes) ++ return c->smodes[i]; ++ else ++ fatal("cannot find mode"); ++ ++} ++ ++static void ++do_init (void) ++{ ++ int i, j; ++ output_t *output; ++ ++ /* Initialize con_outputs array */ ++ for (i = 0; i < MAX_OUTPUT; i++) { ++ con_outputs[i].output = NULL; ++ con_outputs[i].on = False; ++ start_mode[i] = NULL; ++ new_mode[i] = NULL; ++ } ++ ++ ncon = 0; ++ dis_ncon = 0; ++ init_rotation = RR_Rotate_0; ++ init_x = 0; ++ init_y = 0; ++ get_crtcs (); ++ get_outputs (); ++ ++ for (output = outputs; output; output = output->next) { ++ XRROutputInfo *output_info = output->output_info; ++ ++ if (output_info->connection == RR_Connected) { ++ con_outputs[ncon].output = output; ++ con_outputs[ncon].nsmodes = 0; ++ for (j = 0; j < output_info->nmode; j++) { ++ XRRModeInfo *rmode = find_mode_by_xid (output_info->modes[j]); ++ ++ con_outputs[ncon].smodes = ++ realloc(con_outputs[ncon].smodes, ++ (con_outputs[ncon].nsmodes + 1) * sizeof (XRRModeInfo *)); ++ con_outputs[ncon].smodes[j] = rmode; ++ con_outputs[ncon].nsmodes ++; ++ } ++ ++ /* Sort the modes */ ++ qsort((void *) con_outputs[ncon].smodes, ++ con_outputs[ncon].nsmodes, sizeof(XRRModeInfo *), ++ (int (*) (const void *, const void *)) mode_sort); ++ ++ if (output_info->crtc) { ++ crtc_t *crtc; ++ ++ con_outputs[ncon].on = True; ++ for (j = 0; j < output_info->ncrtc; j++) { ++ if (output_info->crtcs[j] == output_info->crtc) ++ break; ++ if (j == output_info->ncrtc) { ++ if (verbose) ++ fatal ("crtc does not match for output\n"); ++ } ++ } ++ /* set initial mode_info */ ++ crtc = find_crtc_by_xid (output_info->crtc); ++ if (crtc) ++ con_outputs[ncon].output->mode_info = ++ find_mode_by_xid (crtc->crtc_info->mode); ++ } ++ else ++ con_outputs[ncon].on = False; ++ ncon ++; ++ } else if (output_info->connection == RR_Disconnected) { ++ dis_con_outputs[dis_ncon].output = output; ++ dis_ncon ++; ++ } ++ } ++ ++ qsort((void **) con_outputs, ncon, ++ sizeof(con_output_t), (int (*) (const void *, const void *)) output_sort); ++ ++ if (verbose) { ++ fprintf(stderr, "Total connected outputs = %d :\n", ncon); ++ for (j = 0; j < ncon; j++) { ++ fprintf(stderr, "%d (%s): top mode = %s, rotation = %d, crtcs =", j, ++ con_outputs[j].output->output_info->name, ++ con_outputs[j].smodes[0]->name, ++ con_outputs[j].output->rotation); ++ for (i = 0; i < con_outputs[j].output->output_info->ncrtc; i++) ++ fprintf(stderr, " %x", con_outputs[j].output->output_info->crtcs[i]); ++ fprintf(stderr, ", using %x", con_outputs[j].output->output_info->crtc); ++ fprintf(stderr, "\n"); ++ } ++ fprintf(stderr, "Total disconnected outputs = %d :\n", dis_ncon); ++ for (j = 0; j < dis_ncon; j++) { ++ fprintf(stderr, "%d (%s) : number of crtcs %d =", j, ++ dis_con_outputs[j].output->output_info->name, ++ dis_con_outputs[j].output->output_info->ncrtc); ++ for (i = 0; i < dis_con_outputs[j].output->output_info->ncrtc; i++) ++ fprintf(stderr, " %x", dis_con_outputs[j].output->output_info->crtcs[i]); ++ fprintf(stderr, ", using %x", dis_con_outputs[j].output->output_info->crtc); ++ fprintf(stderr, "\n"); ++ } ++ } ++ ++ i = con_outputs[2].on * 4 + con_outputs[1].on * 2 + con_outputs[0].on; ++ ++ if ((i == 1) || (i == 2) || (i == 4)) { ++ use_init_pos = True; ++ j = i >> 1; ++ ++ /* remember position and mode info in single state */ ++ start_mode[j] = con_outputs[j].output->mode_info; ++ init_rotation = con_outputs[j].output->rotation; ++ init_x = con_outputs[j].output->x; ++ init_y = con_outputs[j].output->y; ++ } else ++ use_init_pos = False; ++ ++ if ((ncon != 2) || (start < 3)) ++ start = i; ++ ++ if ((ncon < 2) || (ncon > 3)) { ++ if (ncon < 2) ++ fprintf (stderr, "warn: too few (less than 2) connections: %d: can't switch\n", ncon); ++ else ++ fprintf (stderr, "warn: too many (more than 3) connections: %d: can't switch\n", ncon); ++ do_not_switch = True; ++ } else ++ do_not_switch = False; ++ ++ did_init = True; ++ ++ return; ++} ++ ++static Bool ++do_switch (void) ++{ ++ int i, j; ++ int single; ++ ++ for (i = 0; i < ncon; i++) ++ new_mode[i] = NULL; ++ ++ for (i = 0; i < ncon; i++) { ++ output_t *output = con_outputs[i].output; ++ ++ output->relation = same_as; ++ output->relative_to = NULL; ++ if (use_init_pos) { ++ output->x = init_x; ++ output->y = init_y; ++ output->rotation = init_rotation; ++ } else { ++ output->x = 0; ++ output->y = 0; ++ } ++ } ++ ++ if (ncon == 2) { ++ if (!nosideview) { ++ if (++start > 5) start = 1; ++ } ++ else { ++ if (++start > 3) start = 1; ++ } ++ ++ if (verbose) ++ fprintf(stderr, "current state = %d\n", start); ++ if (start >= 3) { ++ int m0, m1; ++ ++ if (get_common_mode(&con_outputs[0], &con_outputs[1], &m0, &m1)) { ++ new_mode[0] = con_outputs[0].smodes[m0]; ++ new_mode[1] = con_outputs[1].smodes[m1]; ++ } else { ++ new_mode[0] = get_largest_mode (&con_outputs[0], ++ con_outputs[0].smodes[0]); ++ new_mode[1] = get_largest_mode (&con_outputs[1], ++ con_outputs[1].smodes[0]); ++ } ++ } else { ++ if (start_mode[start -1]) ++ new_mode[start -1] = start_mode[start -1]; ++ else { ++ if (con_outputs[start -1].smodes[0]) ++ new_mode[start -1] = ++ get_largest_mode (&con_outputs[start-1], ++ con_outputs[start -1].smodes[0]); ++ } ++ } ++ } ++ ++ if (ncon == 3) { ++ if (++start > 6) start = 1; ++ if (verbose) ++ fprintf(stderr, "current state = %d\n", start); ++ if ((start == 1) || (start == 2) || (start == 4)) { ++ single = 1; ++ i = start >> 1; ++ j = 0; ++ } ++ else { ++ single = 0; ++ if (start > 4) ++ j = 2; ++ else ++ j = 1; ++ if (start > 5) ++ i = 1; ++ else ++ i = 0; ++ } ++ ++ if (single) { ++ if (start_mode[i]) ++ new_mode[i] = start_mode[i]; ++ else { ++ if (con_outputs[i].smodes[0]) ++ new_mode[i] = get_largest_mode (&con_outputs[i], ++ con_outputs[i].smodes[0]); ++ } ++ } ++ else { ++ int m0, m1; ++ ++ if (get_common_mode(&con_outputs[i], &con_outputs[j], &m0, &m1)) { ++ new_mode[i] = con_outputs[i].smodes[m0]; ++ new_mode[j] = con_outputs[j].smodes[m1]; ++ } else { ++ new_mode[i] = get_largest_mode (&con_outputs[i], ++ con_outputs[i].smodes[0]); ++ new_mode[j] = get_largest_mode (&con_outputs[j], ++ con_outputs[j].smodes[0]); ++ } ++ } ++ } ++ ++ /* Set mode */ ++ for (i = 0; i < ncon; i++) { ++ output_t *output; ++ ++ output = con_outputs[i].output; ++ if (new_mode[i]) { ++ if ((!output->mode_info) || (output->mode_info != new_mode[i])) { ++ output->mode_info = new_mode[i]; ++ con_outputs[i].on = True; ++ if (verbose) ++ fprintf(stderr, "set output %d (%s) to mode %s rotation %d\n", i, ++ con_outputs[i].output->output_info->name, ++ con_outputs[i].output->mode_info->name, ++ con_outputs[i].output->rotation); ++ } ++ } else if (con_outputs[i].on ) { ++ output->mode_info = NULL; ++ con_outputs[i].on = False; ++ if (verbose) ++ fprintf(stderr, "turn off output %d (%s) \n", ++ i, con_outputs[i].output->output_info->name); ++ } ++ } ++ ++ if ((ncon == 2) && (start >= 4)) { ++ if (start == 4) { ++ con_outputs[1].output->relative_to = con_outputs[0].output; ++ con_outputs[1].output->relation = right_of; ++ con_outputs[1].output->changes = changes_relation; ++ con_outputs[0].output->changes = 0; ++ } ++ else if (start == 5) { ++ con_outputs[0].output->relative_to = con_outputs[1].output; ++ con_outputs[0].output->relation = right_of; ++ con_outputs[0].output->changes = changes_relation; ++ con_outputs[1].output->changes = 0; ++ } ++ ++ set_positions(); ++ } ++ ++ if (!set_screen_size ()) ++ return False; ++ ++ ++ /* reset crtcs before allocation */ ++ reset_crtcs_for_outputs(); ++ ++ if (!did_init) ++ get_crtcs(); ++ ++ if (!pick_crtcs()) { ++ if (verbose) ++ fprintf(stderr, "pick_crtcs failed\n"); ++ return True; ++ } ++ ++ set_crtcs (); ++ apply(); ++ XSync (dpy, False); ++ ++ did_init = False; ++ ++ return True; ++ ++} ++ ++int ++main (int argc, char **argv) ++{ ++ char *display_name = NULL; ++ int major, minor; ++ int i; ++ char msg[256]; ++ XEvent ev; ++ unsigned int modifier = 0; ++ Bool keygiven = False; ++ Bool modgiven = False; ++ int keysym = 0; ++ XErrorHandler prevhandler; ++ ++ program_name = argv[0]; ++ ++ for (i = 1; i < argc; i++) { ++ if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) { ++ if (++i>=argc) usage (); ++ display_name = argv[i]; ++ continue; ++ } ++ if (!strcmp ("-key", argv[i]) || !strcmp ("-k", argv[i])) { ++ if (++i>=argc) usage (); ++ if ((keysym = XStringToKeysym(argv[i])) == NoSymbol) { ++ fprintf(stderr, "invalid keysym: -key %s\n", argv[i]); ++ usage(); ++ } ++ keygiven = True; ++ continue; ++ } ++ if (!strcmp ("-mod", argv[i]) || !strcmp ("-m", argv[i])) { ++ int j; ++ char *s, *p, *q; ++ int end = 0; ++ ++ if (++i>=argc) usage (); ++ s = strdup (argv[i]); ++ if (!s) { ++ if (verbose) ++ fprintf(stderr, "modifier failed, will use default modifier\n"); ++ continue; ++ } ++ while (*s == ' ') s++; ++ p = s + strlen(s) - 1; ++ while (*p == ' ') *p-- = 0; ++ q = s; ++ for (; ;) { ++ if (p = strchr(s, '+')) { ++ *p = ' '; ++ while ((p > s) && (*(p-1) == ' ')) p--; ++ *p = 0; ++ } ++ else ++ end = 1; ++ for (j = 0; j < MAX_MODIFIERS; j++) { ++ if (!strcmp(mod_key_table[j].modname, s)) { ++ modifier |= mod_key_table[j].mod; ++ break; ++ } ++ } ++ if (j == MAX_MODIFIERS) { ++ fprintf(stderr, "invalid modifier: -mod %s\n", q); ++ usage(); ++ } ++ if (end) ++ break; ++ else { ++ s = ++p; ++ while (*s == ' ') s++; ++ } ++ } ++ modgiven = True; ++ free (q); ++ continue; ++ } ++ if (!strcmp ("-nosideview", argv[i])) { ++ nosideview = True; ++ continue; ++ } ++ if (!strcmp ("-verbose", argv[i]) || !strcmp ("-v", argv[i])) { ++ verbose = True; ++ continue; ++ } ++ if (!strcmp ("-testrun", argv[i])) { ++ testrun = True; ++ verbose = True; ++ continue; ++ } ++ usage(); ++ } ++ ++ dpy = XOpenDisplay (display_name); ++ ++ if (dpy == NULL) ++ fatal ("can't open display %s\n", XDisplayName(display_name)); ++ ++ screen = DefaultScreen (dpy); ++ root = RootWindow (dpy, screen); ++ ++ if (!XRRQueryVersion (dpy, &major, &minor)) ++ fatal ("randr extension missing\n"); ++ ++ if ((major <= 1) && (major != 1 || minor < 2)) ++ fatal ("wrong randr version: %d.%d\n", major, minor); ++ ++ haderror = 0; ++ prevhandler = XSetErrorHandler (curhandler); ++ ++ /* set default key and modifier if not given in command */ ++ if (!keygiven) ++ keysym = XStringToKeysym ("F5"); ++ if (!modgiven) ++ modifier = ShiftMask; ++ ++ if (!testrun) { ++ XGrabKey(dpy, ++ XKeysymToKeycode(dpy, keysym), ++ modifier, ++ root, True, GrabModeAsync, GrabModeAsync); ++ XSync (dpy, False); ++ } ++ ++ XSetErrorHandler (prevhandler); ++ if (haderror) { ++ XGetErrorText (dpy, haderror, msg, sizeof (msg)); ++ fatal ("XGrabKey: %s\n", msg); ++ } ++ ++ XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, ++ &maxWidth, &maxHeight); ++ ++ fb_width_mm = DisplayWidthMM (dpy, screen); ++ fb_height_mm = DisplayHeightMM (dpy, screen); ++ dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen); ++ ++ res = XRRGetScreenResources (dpy, root); ++ if (!res) ++ fatal ("could not get screen resources\n"); ++ if (res->ncrtc != 2) ++ fatal ("too few (less than 2) or too many (more than 2) crtcs: %d\n", res->ncrtc); ++ ++ do_init(); ++ ++ X_GETTIMEOFDAY(&time_val); ++ ++ for(;;) ++ { ++ if (testrun) { ++ usleep(4000000); ++ fprintf(stderr, "\n"); ++ } else ++ XNextEvent(dpy, &ev); ++ ++ if (testrun || (ev.type == KeyPress)) { ++ if (verbose) ++ fprintf(stderr, "\na key press event was grabbed ...\n"); ++ ++ if (testrun || need_probe()) { ++ /* Too long since last switch, need to check output changes */ ++ if (probe_and_check_output_changes ()) { ++ output_t *output, *next; ++ ++ output = outputs; ++ while (output) { ++ if (output->output_info) ++ XRRFreeOutputInfo (output->output_info); ++ if (output->crtc_info && output->crtc_info->outputs) { ++ free(output->crtc_info->outputs); ++ output->crtc_info->outputs = NULL; ++ } ++ next = output->next; ++ free(output); ++ output = next; ++ } ++ outputs = NULL; ++ outputs_tail = &outputs; ++ for (i = 0; i < ncon; i++) { ++ con_outputs[i].output = NULL; ++ con_outputs[i].on = False; ++ if (con_outputs[i].smodes) { ++ free(con_outputs[i].smodes); ++ con_outputs[i].smodes = NULL; ++ } ++ con_outputs[i].nsmodes = 0; ++ } ++ ++ do_init(); ++ } ++ } ++ ++ if (!do_not_switch) ++ if (!do_switch()) { ++ if ((ncon == 2) && (start == 4)) { ++ start = 5; ++ if (verbose) ++ fprintf(stderr, "too small screen, skipping side view\n"); ++ (void) do_switch(); ++ } ++ } ++ ++ X_GETTIMEOFDAY(&time_val); ++ } ++ } ++} ++ +diff -urN old/dispswitch.man new/dispswitch.man +--- dispswitch.man 1969-12-31 16:00:00.000000000 -0800 ++++ dispswitch.man 2008-09-03 12:14:03.013107000 -0700 +@@ -0,0 +1,66 @@ ++'\" t ++.\" ++.\" Copyright 2001 Keith Packard.\" ++.\" Copyright 2008 Sun Microsystems.\" ++.\" Permission to use, copy, modify, distribute, and sell this software and its ++.\" documentation for any purpose is hereby granted without fee, provided that ++.\" the above copyright notice appear in all copies and that both that ++.\" copyright notice and this permission notice appear in supporting ++.\" documentation, and that the name of Keith Packard not be used in ++.\" advertising or publicity pertaining to distribution of the software without ++.\" specific, written prior permission. Keith Packard makes no ++.\" representations about the suitability of this software for any purpose. It ++.\" is provided "as is" without express or implied warranty. ++.\" ++.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ++.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO ++.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR ++.\" CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, ++.\" DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ++.\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++.\" PERFORMANCE OF THIS SOFTWARE. ++.\" ++.\" ++.\" $XFree86: xc/programs/xrandr/dispswitch.man,v 1.1 2008/07/25 14:12:39 eich Exp $ ++.\" ++.TH DISPSWITCH __appmansuffix__ __vendorversion__ ++.SH NAME ++dispswitch \- Display Device Switch ++.SH SYNOPSIS ++.B "dispswitch" ++[\-display \fIdisplay\fP] ++[\-key \fIkeysym\fP] ++[\-mod \fImodifier\fP] ++[\-help] ++[\-verbose] ++[\-nosideview] ++[\-testrun] ++.SH DESCRIPTION ++.I Dispswitch ++uses hotkey to switch/rotate on/off of display devices up to 3 devices. Side-by-side views are included when two devices are connected. It works on systems where both server and driver support RandR version 1.2 (or above). ++User can define a hotkey with -key and -mod options (see below), the default is "Shift + F5". ++ ++If a key stroke is hit 5 seconds or longer after the previous switch, display devices are re-probed so that any changes such as adding or removing devices, can be detected and adapted to. ++ ++If a new display device is added whose mode size is larger than the one with which X server is started, or a side-by-side view is switched into that needs a larger mode to cover both screens, a config file specifying larger virtual screen size (Virtual field in Screen Section) will be needed during X server startup. Otherwise the larger mode will not be realized, or the side-by-side view will be skipped. ++ ++.IP \-help ++Print out a summary of the usage and exit. ++.IP "\-verbose or -v" ++Print out debug messages when run. ++.IP \-nosideview ++Skip side-by-side views in two devices rotating. ++.IP \-testrun ++Switch/rotate display device states repeatedly without hotkey strokes. ++.IP "\-key or -k " ++Define the keysym of hotkey to be , which can be any entry defined in ++defined in /usr/X11/include/X11/keysymdef.h, with prefix XK_ removed, such as F5, F8, Escape. ++.IP "\-mod or -m " ++Define the modifier of hotkey to be . is any or combination of modifiers on your system. Run /usr/X11/bin/xmodmap to find all available modifiers on your system. They can be none, shift, control, mod1, mod3, mod4, mod5, any. ++.SH ++Examples: ++ ++dispswitch -key Escape -mod shift defines hotkey to be 'shift + Esc' ++.sp ++dispswitch -key F2 -mod "shift+control" defines hotkey to be 'shift + control + F2' ++ +diff -urN old/Makefile.am new/Makefile.am +--- Makefile.am 2008-03-07 13:35:37.000000000 -0800 ++++ Makefile.am 2008-08-07 18:31:32.391601000 -0700 +@@ -19,16 +19,21 @@ + # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + # PERFORMANCE OF THIS SOFTWARE. + +-bin_PROGRAMS = xrandr ++bin_PROGRAMS = xrandr dispswitch + + AM_CFLAGS = $(XRANDR_CFLAGS) + xrandr_LDADD = $(XRANDR_LIBS) ++dispswitch_LDADD = $(XRANDR_LIBS) + + xrandr_SOURCES = \ + xrandr.c + ++dispswitch_SOURCES = \ ++ dispswitch.c ++ + appman_PRE = \ +- xrandr.man ++ xrandr.man \ ++ dispswitch.man + + appmandir = $(APP_MAN_DIR) + diff -r b1c4df796388 -r e82b1d17088b open-src/data/Makefile --- a/open-src/data/Makefile Tue Sep 09 17:37:22 2008 -0700 +++ b/open-src/data/Makefile Tue Sep 09 18:28:39 2008 -0700 @@ -28,14 +28,15 @@ # or other dealings in this Software without prior written authorization # of the copyright holder. # -# @(#)Makefile 1.4 08/08/08 +# @(#)Makefile 1.5 08/09/05 # ############################################################################### OS_SUBDIRS_common = \ smf-rbac \ workspace-patterns \ - xcursor-themes + xcursor-themes \ + gnome-launch OS_SUBDIRS_sparc = $(OS_SUBDIRS_common) OS_SUBDIRS_i386 = $(OS_SUBDIRS_common) diff -r b1c4df796388 -r e82b1d17088b open-src/data/gnome-launch/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/open-src/data/gnome-launch/Makefile Tue Sep 09 18:28:39 2008 -0700 @@ -0,0 +1,57 @@ +############################################################################### +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use subject to license terms. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, and/or sell copies of the Software, and to permit persons +# to whom the Software is furnished to do so, provided that the above +# copyright notice(s) and this permission notice appear in all copies of +# the Software and that both the above copyright notice(s) and this +# permission notice appear in supporting documentation. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +# OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL +# INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING +# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# Except as contained in this notice, the name of a copyright holder +# shall not be used in advertising or otherwise to promote the sale, use +# or other dealings in this Software without prior written authorization +# of the copyright holder. +# +#pragma ident "@(#)Makefile 1.1 08/09/05 SMI" +# + +MODULE_NAME=workspace-patterns + +# No upstream sources for these files, since they're Solaris-specific +MODULE_VERSION=NONE +SOURCE_TARBALL_NAME=NONE +SOURCE_TARBALL_NAME_SET=yes + +BUILD_TARGETS = +BUILD_TARGETS_SET=yes + +INSTALL_TARGETS = +INSTALL_TARGETS_SET=yes + +### Include common rulesets +include ../Makefile.inc + +INSTALL_PATH=etc/xdg/autostart +DESTDIR=$(PROTODIR) +INSTDIR=$(DESTDIR)/$(INSTALL_PATH) + + +install_gen:: + mkdir -p $(INSTDIR) + cp -pf gnome-dispswitch.desktop $(INSTDIR) diff -r b1c4df796388 -r e82b1d17088b open-src/data/gnome-launch/gnome-dispswitch.desktop --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/open-src/data/gnome-launch/gnome-dispswitch.desktop Tue Sep 09 18:28:39 2008 -0700 @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Display Switch Daemon +Comment=Handles switching of displays devices +Icon=display +Exec=/usr/X11/bin/dispswitch +Terminal=false +Type=Application +Categories= +X-GNOME-Autostart-enabled=true diff -r b1c4df796388 -r e82b1d17088b packages/SUNWxorg-client-docs/prototype --- a/packages/SUNWxorg-client-docs/prototype Tue Sep 09 17:37:22 2008 -0700 +++ b/packages/SUNWxorg-client-docs/prototype Tue Sep 09 18:28:39 2008 -0700 @@ -29,7 +29,7 @@ # ########################################################################## # -# ident "@(#)prototype 1.5 07/10/02 SMI" +# ident "@(#)prototype 1.6 08/09/03 SMI" # # X.Org Foundation X clients for Solaris @@ -52,6 +52,7 @@ f none X11/share/man/man1/glxinfo.1 0444 root bin f none X11/share/man/man1/xgamma.1 0444 root bin f none X11/share/man/man1/xrandr.1 0444 root bin +f none X11/share/man/man1/dispswitch.1 0444 root bin f none X11/share/man/man1/xvidtune.1 0444 root bin f none X11/share/man/man1/xvinfo.1 0444 root bin diff -r b1c4df796388 -r e82b1d17088b packages/SUNWxorg-client-programs/prototype --- a/packages/SUNWxorg-client-programs/prototype Tue Sep 09 17:37:22 2008 -0700 +++ b/packages/SUNWxorg-client-programs/prototype Tue Sep 09 18:28:39 2008 -0700 @@ -29,7 +29,7 @@ # ########################################################################## # -# ident "@(#)prototype 1.3 05/11/07 SMI" +# ident "@(#)prototype 1.4 08/09/03 SMI" # # X.Org Foundation X client programs for Solaris @@ -45,6 +45,7 @@ d none X11/bin 0755 root bin f none X11/bin/xgamma 0755 root bin f none X11/bin/xrandr 0755 root bin +f none X11/bin/dispswitch 0755 root bin f none X11/bin/xvidtune 0755 root bin f none X11/bin/xvinfo 0755 root bin diff -r b1c4df796388 -r e82b1d17088b packages/SUNWxwplr/prototype_com --- a/packages/SUNWxwplr/prototype_com Tue Sep 09 17:37:22 2008 -0700 +++ b/packages/SUNWxwplr/prototype_com Tue Sep 09 18:28:39 2008 -0700 @@ -25,7 +25,7 @@ # or other dealings in this Software without prior written authorization # of the copyright holder. # -# ident "@(#)prototype_com 1.6 07/10/10 SMI" +# ident "@(#)prototype_com 1.7 08/09/09 SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -54,6 +54,10 @@ d none lib 755 root bin d none lib/svc 755 root bin d none lib/svc/method 755 root bin +!search ../etc/xdg/autostart +d none etc/xdg 0755 root sys +d none etc/xdg/autostart 0755 root sys +f none etc/xdg/autostart/gnome-dispswitch.desktop 0644 root sys !search ../lib/svc/method f none lib/svc/method/x11-server 755 root bin d none var 755 root sys