6684767 Integration of video monitor switch code
authorHenry Zhao <Henry.Zhao@Sun.COM>
Tue, 09 Sep 2008 18:28:39 -0700
changeset 531 e82b1d17088b
parent 530 b1c4df796388
child 532 74a3f3a0f4e9
6684767 Integration of video monitor switch code
open-src/app/xrandr/Makefile
open-src/app/xrandr/dispswitch.patch
open-src/data/Makefile
open-src/data/gnome-launch/Makefile
open-src/data/gnome-launch/gnome-dispswitch.desktop
packages/SUNWxorg-client-docs/prototype
packages/SUNWxorg-client-programs/prototype
packages/SUNWxwplr/prototype_com
--- 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
--- /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 <stdio.h>
++#include <X11/Xlib.h>
++#include <X11/Xlibint.h>
++#include <X11/Xproto.h>
++#include <X11/extensions/Xrandr.h>
++#include <X11/Xos.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdarg.h>
++#include <fcntl.h>
++#include <signal.h>
++#include <sys/proc.h>
++#include <unistd.h>
++
++
++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 <display> or -d <display>\n");
++    fprintf(stderr, "  -key <key> or -k <key>\n");
++    fprintf(stderr, "  -mod <modifier> or -m <modifier>\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 <keysym> or -k <keysym>"
++Define the keysym of hotkey to be <keysym>, 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 <modifier> or -m <modifier>"
++Define the modifier of hotkey to be <modifier>. <modifier> 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)
+ 
--- 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)
--- /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)
--- /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
--- 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
 
--- 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
 
--- 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