xserver: Branch 'master' - 5 commits

Keith Packard keithp at kemper.freedesktop.org
Sun Mar 18 08:39:10 EET 2007


 hw/xfree86/ddc/xf86DDC.c       |    7 +
 hw/xfree86/modes/xf86RandR12.c |  133 ++++++++++++++++++++++---
 randr/mirandr.c                |   17 +++
 randr/randrstr.h               |   36 ++++++
 randr/rrcrtc.c                 |   13 +-
 randr/rrinfo.c                 |    6 -
 randr/rrmode.c                 |  217 +++++++++++++++++++++++++++++++++++------
 randr/rroutput.c               |  101 +++++++++++++++++--
 randr/rrscreen.c               |   16 ++-
 9 files changed, 482 insertions(+), 64 deletions(-)

New commits:
diff-tree 720f302d241e88e6e9f2962207da1aa9a79728b7 (from b5a8a71e64c76b8dd42962cbd7984215c6ce4aa8)
Author: Keith Packard <keithp at neko.keithp.com>
Date:   Sat Mar 17 20:14:05 2007 -0700

    Slow down DDC I2C bus using a RiseFallTime of 20us for old monitors.
    
    This time value makes the bus run slowly enough for even the least reliable
    of monitors. Thanks to Pavel Troller for finding the necessary change.

diff --git a/hw/xfree86/ddc/xf86DDC.c b/hw/xfree86/ddc/xf86DDC.c
index 0f24c52..8080c8d 100644
--- a/hw/xfree86/ddc/xf86DDC.c
+++ b/hw/xfree86/ddc/xf86DDC.c
@@ -337,6 +337,12 @@ DDCRead_DDC2(int scrnIndex, I2CBusPtr pB
     unsigned char *R_Buffer;
     int i;
     
+    /*
+     * Slow down the bus so that older monitors don't 
+     * miss things.
+     */
+    pBus->RiseFallTime = 20;
+    
     if (!(dev = xf86I2CFindDev(pBus, 0x00A0))) {
 	dev = xf86CreateI2CDevRec();
 	dev->DevName = "ddc2";
diff-tree b5a8a71e64c76b8dd42962cbd7984215c6ce4aa8 (from 2489dae9f7def788910eee5733931392df83a0d6)
Author: Keith Packard <keithp at neko.keithp.com>
Date:   Sat Mar 17 17:26:11 2007 -0700

    Remove extra (and wrong) I2C ByteTimeout setting in DDC code.
    
    The DDC code sets the I2C timeouts to VESA standards, except that it had an
    extra setting of the ByteTimeout value which was wrong (off by a factor of
    50). Removing this should help DDC work on many more monitors. Note that the
    Intel driver duplicated these settings, along with the error. Yay for cult
    and paste coding.

diff --git a/hw/xfree86/ddc/xf86DDC.c b/hw/xfree86/ddc/xf86DDC.c
index 4ce585c..0f24c52 100644
--- a/hw/xfree86/ddc/xf86DDC.c
+++ b/hw/xfree86/ddc/xf86DDC.c
@@ -344,7 +344,6 @@ DDCRead_DDC2(int scrnIndex, I2CBusPtr pB
 	dev->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
 	dev->StartTimeout = 550;
 	dev->BitTimeout = 40;
-	dev->ByteTimeout = 40;
 	dev->AcknTimeout = 40;
 
 	dev->pI2CBus = pBus;
diff-tree 2489dae9f7def788910eee5733931392df83a0d6 (from 9d0c3b52f25df89738fb1a62ccffda8c8cbb4689)
Author: Keith Packard <keithp at guitar.keithp.com>
Date:   Thu Mar 15 20:26:07 2007 -0700

    Correct ref counting of RRMode structures
    
    RRModes are referenced by the resource db, RROutput and RRCrtc structures.
    Ensure that the mode reference count is decremented each time a reference is
    lost from one of these sources. The missing destroys were in
    RRCrtcDestroyResource and RROutputDestroyResource, which only happen at
    server reset time, so modes would be unavailable in subsequent server
    generations.

diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index 315dd6c..ecf5bb2 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -361,6 +361,8 @@ RRCrtcDestroyResource (pointer value, XI
     }
     if (crtc->gammaRed)
 	xfree (crtc->gammaRed);
+    if (crtc->mode)
+	RRModeDestroy (crtc->mode);
     xfree (crtc);
     return 1;
 }
diff --git a/randr/rroutput.c b/randr/rroutput.c
index 6e95c95..160071b 100644
--- a/randr/rroutput.c
+++ b/randr/rroutput.c
@@ -406,9 +406,12 @@ RROutputDestroyResource (pointer value, 
 	    }
 	}
     }
-    /* XXX destroy all modes? */
     if (output->modes)
+    {
+	for (m = 0; m < output->numModes; m++)
+	    RRModeDestroy (output->modes[m]);
 	xfree (output->modes);
+    }
     
     for (m = 0; m < output->numUserModes; m++)
 	RRModeDestroy (output->userModes[m]);
diff-tree 9d0c3b52f25df89738fb1a62ccffda8c8cbb4689 (from 2c93083edd29a65e73bb2e8eff9d353e92845c9b)
Author: Keith Packard <keithp at guitar.keithp.com>
Date:   Tue Feb 20 23:04:26 2007 -0800

    Eliminate RRModeRec devPrivate field.
    
    The xf86 mode setting code was mis-using this field to try and store a
    pointer to a DisplayModeRec, however, each output has its own copy of every
    DisplayModeRec leaving the one in in the RRModeRec devPrivate field pointing
    at a random DisplayModeRec.
    
    Instead of attempting to rectify this, eliminating the devPrivate entirely
    turned out to be very easy; the DDX code now accepts an arbitrary RRModeRec
    structure and set that to the hardware, converting it on the fly to a
    DisplayModeRec as needed.
    (cherry picked from commit 3506b9376c2b0db09bfff58d64e07af88a6e8195)

diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index 73647a6..4213fea 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -556,6 +556,56 @@ xf86RandR12GetOriginalVirtualSize(ScrnIn
 }
 
 #if RANDR_12_INTERFACE
+
+#define FLAG_BITS (RR_HSyncPositive | \
+		   RR_HSyncNegative | \
+		   RR_VSyncPositive | \
+		   RR_VSyncNegative | \
+		   RR_Interlace | \
+		   RR_DoubleScan | \
+		   RR_CSync | \
+		   RR_CSyncPositive | \
+		   RR_CSyncNegative | \
+		   RR_HSkewPresent | \
+		   RR_BCast | \
+		   RR_PixelMultiplex | \
+		   RR_DoubleClock | \
+		   RR_ClockDivideBy2)
+
+static Bool
+xf86RandRModeMatches (RRModePtr		randr_mode,
+		      DisplayModePtr	mode)
+{
+#if 0
+    if (match_name)
+    {
+	/* check for same name */
+	int	len = strlen (mode->name);
+	if (randr_mode->mode.nameLength != len)			return FALSE;
+	if (memcmp (randr_mode->name, mode->name, len) != 0)	return FALSE;
+    }
+#endif
+    
+    /* check for same timings */
+    if (randr_mode->mode.dotClock / 1000 != mode->Clock)    return FALSE;
+    if (randr_mode->mode.width        != mode->HDisplay)    return FALSE;
+    if (randr_mode->mode.hSyncStart   != mode->HSyncStart)  return FALSE;
+    if (randr_mode->mode.hSyncEnd     != mode->HSyncEnd)    return FALSE;
+    if (randr_mode->mode.hTotal       != mode->HTotal)	    return FALSE;
+    if (randr_mode->mode.hSkew        != mode->HSkew)	    return FALSE;
+    if (randr_mode->mode.height       != mode->VDisplay)    return FALSE;
+    if (randr_mode->mode.vSyncStart   != mode->VSyncStart)  return FALSE;
+    if (randr_mode->mode.vSyncEnd     != mode->VSyncEnd)    return FALSE;
+    if (randr_mode->mode.vTotal       != mode->VTotal)	    return FALSE;
+    
+    /* check for same flags (using only the XF86 valid flag bits) */
+    if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS))
+	return FALSE;
+    
+    /* everything matches */
+    return TRUE;
+}
+
 static Bool
 xf86RandR12CrtcNotify (RRCrtcPtr	randr_crtc)
 {
@@ -594,12 +644,15 @@ xf86RandR12CrtcNotify (RRCrtcPtr	randr_c
 	     * We make copies of modes, so pointer equality 
 	     * isn't sufficient
 	     */
-	    for (j = 0; j < randr_output->numModes; j++)
+	    for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++)
 	    {
-		DisplayModePtr	outMode = randr_output->modes[j]->devPrivate;
-		if (xf86ModesEqual(mode, outMode))
+		RRModePtr   m = (j < randr_output->numModes ?
+				 randr_output->modes[j] :
+				 randr_output->userModes[j-randr_output->numModes]);
+					 
+		if (xf86RandRModeMatches (m, mode))
 		{
-		    randr_mode = randr_output->modes[j];
+		    randr_mode = m;
 		    break;
 		}
 	    }
@@ -611,6 +664,39 @@ xf86RandR12CrtcNotify (RRCrtcPtr	randr_c
     return ret;
 }
 
+/*
+ * Convert a RandR mode to a DisplayMode
+ */
+static void
+xf86RandRModeConvert (ScrnInfoPtr	scrn,
+		      RRModePtr		randr_mode,
+		      DisplayModePtr	mode)
+{
+    mode->prev = NULL;
+    mode->next = NULL;
+    mode->name = NULL;
+    mode->status = MODE_OK;
+    mode->type = 0;
+
+    mode->Clock = randr_mode->mode.dotClock / 1000;
+    
+    mode->HDisplay = randr_mode->mode.width;
+    mode->HSyncStart = randr_mode->mode.hSyncStart;
+    mode->HSyncEnd = randr_mode->mode.hSyncEnd;
+    mode->HTotal = randr_mode->mode.hTotal;
+    mode->HSkew = randr_mode->mode.hSkew;
+    
+    mode->VDisplay = randr_mode->mode.height;
+    mode->VSyncStart = randr_mode->mode.vSyncStart;
+    mode->VSyncEnd = randr_mode->mode.vSyncEnd;
+    mode->VTotal = randr_mode->mode.vTotal;
+    mode->VScan = 0;
+
+    mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS;
+
+    xf86SetModeCrtc (mode, scrn->adjustFlags);
+}
+
 static Bool
 xf86RandR12CrtcSet (ScreenPtr	pScreen,
 		  RRCrtcPtr	randr_crtc,
@@ -624,16 +710,15 @@ xf86RandR12CrtcSet (ScreenPtr	pScreen,
     ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
     xf86CrtcPtr		crtc = randr_crtc->devPrivate;
-    DisplayModePtr	mode = randr_mode ? randr_mode->devPrivate : NULL;
     Bool		changed = FALSE;
     int			o, ro;
     xf86CrtcPtr		*save_crtcs;
     Bool		save_enabled = crtc->enabled;
 
     save_crtcs = ALLOCATE_LOCAL(config->num_crtc * sizeof (xf86CrtcPtr));
-    if ((mode != NULL) != crtc->enabled)
+    if ((randr_mode != NULL) != crtc->enabled)
 	changed = TRUE;
-    else if (mode && !xf86ModesEqual (&crtc->mode, mode))
+    else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode))
 	changed = TRUE;
     
     if (rotation != crtc->rotation)
@@ -667,11 +752,14 @@ xf86RandR12CrtcSet (ScreenPtr	pScreen,
     /* XXX need device-independent mode setting code through an API */
     if (changed)
     {
-	crtc->enabled = mode != NULL;
+	crtc->enabled = randr_mode != NULL;
 
-	if (mode)
+	if (randr_mode)
 	{
-	    if (!xf86CrtcSetMode (crtc, mode, rotation, x, y))
+	    DisplayModeRec  mode;
+
+	    xf86RandRModeConvert (pScrn, randr_mode, &mode);
+	    if (!xf86CrtcSetMode (crtc, &mode, rotation, x, y))
 	    {
 		crtc->enabled = save_enabled;
 		for (o = 0; o < config->num_output; o++)
@@ -685,7 +773,7 @@ xf86RandR12CrtcSet (ScreenPtr	pScreen,
 	    /*
 	     * Save the last successful setting for EnterVT
 	     */
-	    crtc->desiredMode = *mode;
+	    crtc->desiredMode = mode;
 	    crtc->desiredRotation = rotation;
 	    crtc->desiredX = x;
 	    crtc->desiredY = y;
@@ -733,33 +821,12 @@ xf86RandR12OutputValidateMode (ScreenPtr
 			       RROutputPtr  randr_output,
 			       RRModePtr    randr_mode)
 {
+    ScrnInfoPtr	    pScrn = xf86Screens[pScreen->myNum];
     xf86OutputPtr   output = randr_output->devPrivate;
-    DisplayModePtr  mode = randr_mode->devPrivate;
+    DisplayModeRec  mode;
 
-    if (!mode)
-    {
-	mode = xalloc (sizeof (DisplayModeRec) + randr_mode->mode.nameLength + 1);
-	if (!mode)
-	    return FALSE;
-	mode->name = (char *) mode + 1;
-	memcpy (mode->name, randr_mode->name, randr_mode->mode.nameLength);
-	mode->name[randr_mode->mode.nameLength] = '\0';
-	mode->Clock = randr_mode->mode.dotClock / 1000;
-	mode->HDisplay = randr_mode->mode.width;
-	mode->HSyncStart = randr_mode->mode.hSyncStart;
-	mode->HSyncEnd = randr_mode->mode.hSyncEnd;
-	mode->HTotal = randr_mode->mode.hTotal;
-	mode->HSkew = randr_mode->mode.hSkew;
-	
-	mode->VDisplay = randr_mode->mode.height;
-	mode->VSyncStart = randr_mode->mode.vSyncStart;
-	mode->VSyncEnd = randr_mode->mode.vSyncEnd;
-	mode->VTotal = randr_mode->mode.vTotal;
-    
-	mode->Flags = randr_mode->mode.modeFlags;
-	randr_mode->devPrivate = mode;
-    }
-    if (!output->funcs->mode_valid (output, mode))
+    xf86RandRModeConvert (pScrn, randr_mode, &mode);
+    if (output->funcs->mode_valid (output, &mode) != MODE_OK)
 	return FALSE;
     return TRUE;
 }
@@ -767,13 +834,6 @@ xf86RandR12OutputValidateMode (ScreenPtr
 static void
 xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode)
 {
-    DisplayModePtr  mode = randr_mode->devPrivate;
-
-    if (mode)
-    {
-	xfree (mode);
-	randr_mode->devPrivate = NULL;
-    }
 }
 
 /**
@@ -822,7 +882,6 @@ xf86RROutputSetModes (RROutputPtr randr_
 
 		    rrmode = RRModeGet (&modeInfo, mode->name);
 		    if (rrmode) {
-			rrmode->devPrivate = mode;
 			rrmodes[nmode++] = rrmode;
 			npreferred += pref;
 		    }
diff --git a/randr/randrstr.h b/randr/randrstr.h
index f6d35cf..0dee999 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -79,7 +79,6 @@ struct _rrMode {
     int		    refcnt;
     xRRModeInfo	    mode;
     char	    *name;
-    void	    *devPrivate;
     ScreenPtr	    userScreen;
 };
 
diff-tree 2c93083edd29a65e73bb2e8eff9d353e92845c9b (from 3bffb281260476d2f74f0bf451d85d2f7cacd6c4)
Author: Keith Packard <keithp at guitar.keithp.com>
Date:   Sun Feb 18 23:49:38 2007 -0800

    Add support for user-defined modelines in RandR.
    
    The RandR protocol spec has several requests in support of user-defined
    modes, but the implementation was stubbed out inside the X server. Fill out
    the DIX portion and start on the xf86 DDX portion. It might be necessary to
    add more code to the DDX to insert the user-defined modes into the output
    mode list.
    (cherry picked from commit 63cc2a51ef87130c632a874672a8c9167f14314e)
    
    Conflicts:
    
    	randr/randrstr.h
    
    Updated code to work in master with recent security API changes.

diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index ce780b6..73647a6 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -728,6 +728,54 @@ xf86RandR12OutputSetProperty (ScreenPtr 
     return output->funcs->set_property(output, property, value);
 }
 
+static Bool
+xf86RandR12OutputValidateMode (ScreenPtr    pScreen,
+			       RROutputPtr  randr_output,
+			       RRModePtr    randr_mode)
+{
+    xf86OutputPtr   output = randr_output->devPrivate;
+    DisplayModePtr  mode = randr_mode->devPrivate;
+
+    if (!mode)
+    {
+	mode = xalloc (sizeof (DisplayModeRec) + randr_mode->mode.nameLength + 1);
+	if (!mode)
+	    return FALSE;
+	mode->name = (char *) mode + 1;
+	memcpy (mode->name, randr_mode->name, randr_mode->mode.nameLength);
+	mode->name[randr_mode->mode.nameLength] = '\0';
+	mode->Clock = randr_mode->mode.dotClock / 1000;
+	mode->HDisplay = randr_mode->mode.width;
+	mode->HSyncStart = randr_mode->mode.hSyncStart;
+	mode->HSyncEnd = randr_mode->mode.hSyncEnd;
+	mode->HTotal = randr_mode->mode.hTotal;
+	mode->HSkew = randr_mode->mode.hSkew;
+	
+	mode->VDisplay = randr_mode->mode.height;
+	mode->VSyncStart = randr_mode->mode.vSyncStart;
+	mode->VSyncEnd = randr_mode->mode.vSyncEnd;
+	mode->VTotal = randr_mode->mode.vTotal;
+    
+	mode->Flags = randr_mode->mode.modeFlags;
+	randr_mode->devPrivate = mode;
+    }
+    if (!output->funcs->mode_valid (output, mode))
+	return FALSE;
+    return TRUE;
+}
+
+static void
+xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode)
+{
+    DisplayModePtr  mode = randr_mode->devPrivate;
+
+    if (mode)
+    {
+	xfree (mode);
+	randr_mode->devPrivate = NULL;
+    }
+}
+
 /**
  * Given a list of xf86 modes and a RandR Output object, construct
  * RandR modes and assign them to the output
@@ -958,6 +1006,8 @@ xf86RandR12Init12 (ScreenPtr pScreen)
     rp->rrCrtcSet = xf86RandR12CrtcSet;
     rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma;
     rp->rrOutputSetProperty = xf86RandR12OutputSetProperty;
+    rp->rrOutputValidateMode = xf86RandR12OutputValidateMode;
+    rp->rrModeDestroy = xf86RandR12ModeDestroy;
     rp->rrSetConfig = NULL;
     pScrn->PointerMoved = xf86RandR12PointerMoved;
     if (!xf86RandR12CreateObjects12 (pScreen))
diff --git a/randr/mirandr.c b/randr/mirandr.c
index 0b763e1..47136fb 100644
--- a/randr/mirandr.c
+++ b/randr/mirandr.c
@@ -73,6 +73,20 @@ miRROutputSetProperty (ScreenPtr	    pSc
     return TRUE;
 }
 
+Bool
+miRROutputValidateMode (ScreenPtr	    pScreen,
+			RROutputPtr	    output,
+			RRModePtr	    mode)
+{
+    return FALSE;
+}
+
+void
+miRRModeDestroy (ScreenPtr  pScreen,
+		 RRModePtr  mode)
+{
+}
+
 /*
  * This function assumes that only a single depth can be
  * displayed at a time, but that all visuals of that depth
@@ -102,7 +116,8 @@ miRandRInit (ScreenPtr pScreen)
     pScrPriv->rrCrtcSet = miRRCrtcSet;
     pScrPriv->rrCrtcSetGamma = miRRCrtcSetGamma;
     pScrPriv->rrOutputSetProperty = miRROutputSetProperty;
-    
+    pScrPriv->rrOutputValidateMode = miRROutputValidateMode;
+    pScrPriv->rrModeDestroy = miRRModeDestroy;
     
     RRScreenSetSizeRange (pScreen,
 			  pScreen->width, pScreen->height,
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 5058212..f6d35cf 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -80,7 +80,7 @@ struct _rrMode {
     xRRModeInfo	    mode;
     char	    *name;
     void	    *devPrivate;
-    Bool	    userDefined;
+    ScreenPtr	    userScreen;
 };
 
 struct _rrPropertyValue {
@@ -135,6 +135,8 @@ struct _rrOutput {
     int		    numModes;
     int		    numPreferred;
     RRModePtr	    *modes;
+    int		    numUserModes;
+    RRModePtr	    *userModes;
     Bool	    changed;
     RRPropertyPtr   properties;
     void	    *devPrivate;
@@ -164,6 +166,13 @@ typedef Bool (*RROutputSetPropertyProcPt
 					    Atom		property,
 					    RRPropertyValuePtr	value);
 
+typedef Bool (*RROutputValidateModeProcPtr) (ScreenPtr		pScreen,
+					     RROutputPtr	output,
+					     RRModePtr		mode);
+
+typedef void (*RRModeDestroyProcPtr) (ScreenPtr	    pScreen,
+				      RRModePtr	    mode);
+
 #endif
 
 typedef Bool (*RRGetInfoProcPtr) (ScreenPtr pScreen, Rotation *rotations);
@@ -208,6 +217,8 @@ typedef struct _rrScrPriv {
     RRCrtcSetProcPtr	    rrCrtcSet;
     RRCrtcSetGammaProcPtr   rrCrtcSetGamma;
     RROutputSetPropertyProcPtr	rrOutputSetProperty;
+    RROutputValidateModeProcPtr	rrOutputValidateMode;
+    RRModeDestroyProcPtr	rrModeDestroy;
 #endif
     
     /*
@@ -394,6 +405,15 @@ miRROutputSetProperty (ScreenPtr	    pSc
 		       Atom		    property,
 		       RRPropertyValuePtr   value);
 
+Bool
+miRROutputValidateMode (ScreenPtr	    pScreen,
+			RROutputPtr	    output,
+			RRModePtr	    mode);
+
+void
+miRRModeDestroy (ScreenPtr  pScreen,
+		 RRModePtr  mode);
+
 /* randr.c */
 /*
  * Send all pending events
@@ -549,6 +569,11 @@ Bool
 RRCrtcSetRotations (RRCrtcPtr crtc,
 		    Rotation rotations);
 
+/*
+ * Return the area of the frame buffer scanned out by the crtc,
+ * taking into account the current mode and rotation
+ */
+
 void
 RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height);
 
@@ -672,6 +697,14 @@ RROutputSetModes (RROutputPtr	output,
 		  int		numModes,
 		  int		numPreferred);
 
+int
+RROutputAddUserMode (RROutputPtr    output,
+		     RRModePtr	    mode);
+
+int
+RROutputDeleteUserMode (RROutputPtr output,
+			RRModePtr   mode);
+
 Bool
 RROutputSetCrtcs (RROutputPtr	output,
 		  RRCrtcPtr	*crtcs,
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index db506f4..315dd6c 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -666,10 +666,15 @@ ProcRRSetCrtcConfig (ClientPtr client)
 	    return BadMatch;
 	}
 	/* validate mode for this output */
-	for (j = 0; j < outputs[i]->numModes; j++)
-	    if (outputs[i]->modes[j] == mode)
+	for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
+	{
+	    RRModePtr	m = (j < outputs[i]->numModes ? 
+			     outputs[i]->modes[j] :
+			     outputs[i]->userModes[j - outputs[i]->numModes]);
+	    if (m == mode)
 		break;
-	if (j == outputs[i]->numModes)
+	}
+	if (j == outputs[i]->numModes + outputs[i]->numUserModes)
 	{
 	    if (outputs)
 		xfree (outputs);
diff --git a/randr/rrinfo.c b/randr/rrinfo.c
index 797cdb1..549d501 100644
--- a/randr/rrinfo.c
+++ b/randr/rrinfo.c
@@ -157,9 +157,11 @@ RRScanOldConfig (ScreenPtr pScreen, Rota
     pScrPriv->nSizes = 0;
 	    
     /* find size bounds */
-    for (i = 0; i < output->numModes; i++) 
+    for (i = 0; i < output->numModes + output->numUserModes; i++) 
     {
-	RRModePtr   mode = output->modes[i];
+	RRModePtr   mode = (i < output->numModes ? 
+			    output->modes[i] : 
+			    output->userModes[i-output->numModes]);
         CARD16	    width = mode->mode.width;
         CARD16	    height = mode->mode.height;
 	
diff --git a/randr/rrmode.c b/randr/rrmode.c
index 261e1b7..1117581 100644
--- a/randr/rrmode.c
+++ b/randr/rrmode.c
@@ -48,25 +48,13 @@ RRModeEqual (xRRModeInfo *a, xRRModeInfo
 static int	    num_modes;
 static RRModePtr    *modes;
 
-RRModePtr
-RRModeGet (xRRModeInfo	*modeInfo,
-	   const char	*name)
+static RRModePtr
+RRModeCreate (xRRModeInfo   *modeInfo,
+	      const char    *name,
+	      ScreenPtr	    userScreen)
 {
-    int	i;
-    RRModePtr	mode;
-    RRModePtr	*newModes;
-
-    for (i = 0; i < num_modes; i++)
-    {
-	mode = modes[i];
-	if (RRModeEqual (&mode->mode, modeInfo) &&
-	    !memcmp (name, mode->name, modeInfo->nameLength))
-	{
-	    ++mode->refcnt;
-	    return mode;
-	}
-    }
-
+    RRModePtr	mode, *newModes;
+    
     if (!RRInit ())
 	return NULL;
 
@@ -78,7 +66,7 @@ RRModeGet (xRRModeInfo	*modeInfo,
     mode->name = (char *) (mode + 1);
     memcpy (mode->name, name, modeInfo->nameLength);
     mode->name[modeInfo->nameLength] = '\0';
-    mode->userDefined = FALSE;
+    mode->userScreen = userScreen;
 
     if (num_modes)
 	newModes = xrealloc (modes, (num_modes + 1) * sizeof (RRModePtr));
@@ -104,11 +92,75 @@ RRModeGet (xRRModeInfo	*modeInfo,
     return mode;
 }
 
+static RRModePtr
+RRModeFindByName (const char	*name,
+		  CARD16    	nameLength)
+{
+    int		i;
+    RRModePtr	mode;
+
+    for (i = 0; i < num_modes; i++)
+    {
+	mode = modes[i];
+	if (mode->mode.nameLength == nameLength &&
+	    !memcmp (name, mode->name, nameLength))
+	{
+	    return mode;
+	}
+    }
+    return NULL;
+}
+
+RRModePtr
+RRModeGet (xRRModeInfo	*modeInfo,
+	   const char	*name)
+{
+    int	i;
+
+    for (i = 0; i < num_modes; i++)
+    {
+	RRModePtr   mode = modes[i];
+	if (RRModeEqual (&mode->mode, modeInfo) &&
+	    !memcmp (name, mode->name, modeInfo->nameLength))
+	{
+	    ++mode->refcnt;
+	    return mode;
+	}
+    }
+
+    return RRModeCreate (modeInfo, name, NULL);
+}
+
+static RRModePtr
+RRModeCreateUser (ScreenPtr	pScreen,
+		  xRRModeInfo	*modeInfo,
+		  const char	*name,
+		  int		*error)
+{
+    RRModePtr	mode;
+
+    mode = RRModeFindByName (name, modeInfo->nameLength);
+    if (mode)
+    {
+	*error = BadName;
+	return NULL;
+    }
+    
+    mode = RRModeCreate (modeInfo, name, pScreen);
+    if (!mode)
+    {
+	*error = BadAlloc;
+	return NULL;
+    }
+    *error = Success;
+    return mode;
+}
+
 RRModePtr *
 RRModesForScreen (ScreenPtr pScreen, int *num_ret)
 {
     rrScrPriv(pScreen);
-    int	o, c;
+    int		o, c, m;
     RRModePtr	*screen_modes;
     int		num_screen_modes = 0;
 
@@ -122,9 +174,11 @@ RRModesForScreen (ScreenPtr pScreen, int
 	RROutputPtr	output = pScrPriv->outputs[o];
 	int		m, n;
 
-	for (m = 0; m < output->numModes; m++)
+	for (m = 0; m < output->numModes + output->numUserModes; m++)
 	{
-	    RRModePtr	mode = output->modes[m];
+	    RRModePtr   mode = (m < output->numModes ? 
+				output->modes[m] : 
+				output->userModes[m-output->numModes]);
 	    for (n = 0; n < num_screen_modes; n++)
 		if (screen_modes[n] == mode)
 		    break;
@@ -150,6 +204,23 @@ RRModesForScreen (ScreenPtr pScreen, int
 	if (n == num_screen_modes)
 	    screen_modes[num_screen_modes++] = mode;
     }
+    /*
+     * Add all user modes for this screen
+     */
+    for (m = 0; m < num_modes; m++)
+    {
+	RRModePtr	mode = modes[m];
+	int		n;
+
+	if (mode->userScreen != pScreen)
+	    continue;
+	for (n = 0; n < num_screen_modes; n++)
+	    if (screen_modes[n] == mode)
+		break;
+	if (n == num_screen_modes)
+	    screen_modes[num_screen_modes++] = mode;
+    }
+    
     *num_ret = num_screen_modes;
     return screen_modes;
 }
@@ -205,38 +276,122 @@ int
 ProcRRCreateMode (ClientPtr client)
 {
     REQUEST(xRRCreateModeReq);
+    xRRCreateModeReply	rep;
+    WindowPtr		pWin;
+    ScreenPtr		pScreen;
+    rrScrPrivPtr	pScrPriv;
+    xRRModeInfo		*modeInfo;
+    long		units_after;
+    char		*name;
+    int			error, rc;
+    RRModePtr		mode;
+    
+    REQUEST_AT_LEAST_SIZE (xRRCreateModeReq);
+    rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
+    if (rc != Success)
+	return rc;
+
+    pScreen = pWin->drawable.pScreen;
+    pScrPriv = rrGetScrPriv(pScreen);
+    
+    modeInfo = &stuff->modeInfo;
+    name = (char *) (stuff + 1);
+    units_after = (stuff->length - (sizeof (xRRCreateModeReq) >> 2));
+
+    /* check to make sure requested name fits within the data provided */
+    if ((int) (modeInfo->nameLength + 3) >> 2 > units_after)
+	return BadLength;
+
+    mode = RRModeCreateUser (pScreen, modeInfo, name, &error);
+    if (!mode)
+	return error;
+
+    rep.type = X_Reply;
+    rep.pad0 = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.length = 0;
+    rep.mode = mode->mode.id;
+    if (client->swapped)
+    {
+	int n;
+    	swaps(&rep.sequenceNumber, n);
+    	swapl(&rep.length, n);
+	swapl(&rep.mode, n);
+    }
+    WriteToClient(client, sizeof(xRRCreateModeReply), (char *)&rep);
     
-    REQUEST_SIZE_MATCH(xRRCreateModeReq);
-    (void) stuff;
-    return BadImplementation; 
+    return client->noClientException;
 }
 
 int
 ProcRRDestroyMode (ClientPtr client)
 {
     REQUEST(xRRDestroyModeReq);
+    RRModePtr	mode;
     
     REQUEST_SIZE_MATCH(xRRDestroyModeReq);
-    (void) stuff;
-    return BadImplementation; 
+    mode = LookupIDByType (stuff->mode, RRModeType);
+    if (!mode)
+    {
+	client->errorValue = stuff->mode;
+	return RRErrorBase + BadRRMode;
+    }
+    if (!mode->userScreen)
+	return BadMatch;
+    if (mode->refcnt > 1)
+	return BadAccess;
+    FreeResource (stuff->mode, 0);
+    return Success;
 }
 
 int
 ProcRRAddOutputMode (ClientPtr client)
 {
     REQUEST(xRRAddOutputModeReq);
+    RRModePtr	mode;
+    RROutputPtr	output;
     
     REQUEST_SIZE_MATCH(xRRAddOutputModeReq);
-    (void) stuff;
-    return BadImplementation; 
+    output = LookupOutput(client, stuff->output, DixReadAccess);
+
+    if (!output)
+    {
+	client->errorValue = stuff->output;
+	return RRErrorBase + BadRROutput;
+    }
+    
+    mode = LookupIDByType (stuff->mode, RRModeType);
+    if (!mode)
+    {
+	client->errorValue = stuff->mode;
+	return RRErrorBase + BadRRMode;
+    }
+    
+    return RROutputAddUserMode (output, mode);
 }
 
 int
 ProcRRDeleteOutputMode (ClientPtr client)
 {
     REQUEST(xRRDeleteOutputModeReq);
+    RRModePtr	mode;
+    RROutputPtr	output;
     
     REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq);
-    (void) stuff;
-    return BadImplementation; 
+    output = LookupOutput(client, stuff->output, DixReadAccess);
+
+    if (!output)
+    {
+	client->errorValue = stuff->output;
+	return RRErrorBase + BadRROutput;
+    }
+    
+    mode = LookupIDByType (stuff->mode, RRModeType);
+    if (!mode)
+    {
+	client->errorValue = stuff->mode;
+	return RRErrorBase + BadRRMode;
+    }
+    
+    return RROutputDeleteUserMode (output, mode);
 }
diff --git a/randr/rroutput.c b/randr/rroutput.c
index df1741f..6e95c95 100644
--- a/randr/rroutput.c
+++ b/randr/rroutput.c
@@ -76,6 +76,8 @@ RROutputCreate (const char  *name,
     output->numModes = 0;
     output->numPreferred = 0;
     output->modes = NULL;
+    output->numUserModes = 0;
+    output->userModes = NULL;
     output->properties = NULL;
     output->changed = FALSE;
     output->devPrivate = devPrivate;
@@ -192,6 +194,74 @@ RROutputSetModes (RROutputPtr	output,
     return TRUE;
 }
 
+int
+RROutputAddUserMode (RROutputPtr    output,
+		     RRModePtr	    mode)
+{
+    int		m;
+    ScreenPtr	pScreen = output->pScreen;
+    rrScrPriv(pScreen);
+    RRModePtr	*newModes;
+
+    /* Check to see if this mode is already listed for this output */
+    for (m = 0; m < output->numModes + output->numUserModes; m++)
+    {
+	RRModePtr   e = (m < output->numModes ?
+			 output->modes[m] :
+			 output->userModes[m - output->numModes]);
+	if (mode == e)
+	    return Success;
+    }
+
+    /* Check with the DDX to see if this mode is OK */
+    if (pScrPriv->rrOutputValidateMode)
+	if (!pScrPriv->rrOutputValidateMode (pScreen, output, mode))
+	    return BadMatch;
+
+    if (output->userModes)
+	newModes = xrealloc (output->userModes,
+			     (output->numUserModes + 1) * sizeof (RRModePtr));
+    else
+	newModes = xalloc (sizeof (RRModePtr));
+    if (!newModes)
+	return BadAlloc;
+
+    output->userModes = newModes;
+    output->userModes[output->numUserModes++] = mode;
+    ++mode->refcnt;
+    RROutputChanged (output, TRUE);
+    RRTellChanged (pScreen);
+    return Success;
+}
+
+int
+RROutputDeleteUserMode (RROutputPtr output,
+			RRModePtr   mode)
+{
+    int		m;
+    
+    /* Find this mode in the user mode list */
+    for (m = 0; m < output->numUserModes; m++)
+    {
+	RRModePtr   e = output->userModes[m];
+
+	if (mode == e)
+	    break;
+    }
+    /* Not there, access error */
+    if (m == output->numUserModes)
+	return BadAccess;
+
+    /* make sure the mode isn't active for this output */
+    if (output->crtc && output->crtc->mode == mode)
+	return BadMatch;
+
+    memmove (output->userModes + m, output->userModes + m + 1,
+	     (output->numUserModes - m - 1) * sizeof (RRModePtr));
+    RRModeDestroy (mode);
+    return Success;
+}
+
 Bool
 RROutputSetCrtcs (RROutputPtr	output,
 		  RRCrtcPtr	*crtcs,
@@ -308,9 +378,9 @@ RRDeliverOutputEvent(ClientPtr client, W
  * Destroy a Output at shutdown
  */
 void
-RROutputDestroy (RROutputPtr crtc)
+RROutputDestroy (RROutputPtr output)
 {
-    FreeResource (crtc->id, 0);
+    FreeResource (output->id, 0);
 }
 
 static int
@@ -318,6 +388,7 @@ RROutputDestroyResource (pointer value, 
 {
     RROutputPtr	output = (RROutputPtr) value;
     ScreenPtr	pScreen = output->pScreen;
+    int		m;
 
     if (pScreen)
     {
@@ -335,8 +406,15 @@ RROutputDestroyResource (pointer value, 
 	    }
 	}
     }
+    /* XXX destroy all modes? */
     if (output->modes)
 	xfree (output->modes);
+    
+    for (m = 0; m < output->numUserModes; m++)
+	RRModeDestroy (output->userModes[m]);
+    if (output->userModes)
+	xfree (output->userModes);
+
     if (output->crtcs)
 	xfree (output->crtcs);
     if (output->clones)
@@ -383,7 +461,10 @@ ProcRRGetOutputInfo (ClientPtr client)
     output = LookupOutput(client, stuff->output, DixReadAccess);
 
     if (!output)
+    {
+	client->errorValue = stuff->output;
 	return RRErrorBase + BadRROutput;
+    }
 
     pScreen = output->pScreen;
     pScrPriv = rrGetScrPriv(pScreen);
@@ -398,13 +479,13 @@ ProcRRGetOutputInfo (ClientPtr client)
     rep.connection = output->connection;
     rep.subpixelOrder = output->subpixelOrder;
     rep.nCrtcs = output->numCrtcs;
-    rep.nModes = output->numModes;
+    rep.nModes = output->numModes + output->numUserModes;
     rep.nPreferred = output->numPreferred;
     rep.nClones = output->numClones;
     rep.nameLength = output->nameLength;
     
     extraLen = ((output->numCrtcs + 
-		 output->numModes + 
+		 output->numModes + output->numUserModes +
 		 output->numClones +
 		 ((rep.nameLength + 3) >> 2)) << 2);
 
@@ -420,7 +501,7 @@ ProcRRGetOutputInfo (ClientPtr client)
 
     crtcs = (RRCrtc *) extra;
     modes = (RRMode *) (crtcs + output->numCrtcs);
-    clones = (RROutput *) (modes + output->numModes);
+    clones = (RROutput *) (modes + output->numModes + output->numUserModes);
     name = (char *) (clones + output->numClones);
     
     for (i = 0; i < output->numCrtcs; i++)
@@ -429,9 +510,12 @@ ProcRRGetOutputInfo (ClientPtr client)
 	if (client->swapped)
 	    swapl (&crtcs[i], n);
     }
-    for (i = 0; i < output->numModes; i++)
+    for (i = 0; i < output->numModes + output->numUserModes; i++)
     {
-	modes[i] = output->modes[i]->mode.id;
+	if (i < output->numModes)
+	    modes[i] = output->modes[i]->mode.id;
+	else
+	    modes[i] = output->userModes[i - output->numModes]->mode.id;
 	if (client->swapped)
 	    swapl (&modes[i], n);
     }
diff --git a/randr/rrscreen.c b/randr/rrscreen.c
index 1680003..ad74ac3 100644
--- a/randr/rrscreen.c
+++ b/randr/rrscreen.c
@@ -473,7 +473,7 @@ RR10GetData (ScreenPtr pScreen, RROutput
 {
     RR10DataPtr	    data;
     RRScreenSizePtr size;
-    int		    nmode = output->numModes;
+    int		    nmode = output->numModes + output->numUserModes;
     int		    o, os, l, r;
     RRScreenRatePtr refresh;
     CARD16	    vRefresh;
@@ -500,11 +500,14 @@ RR10GetData (ScreenPtr pScreen, RROutput
     /*
      * find modes not yet listed
      */
-    for (o = 0; o < output->numModes; o++)
+    for (o = 0; o < output->numModes + output->numUserModes; o++)
     {
 	if (used[o]) continue;
 	
-	mode = output->modes[o];
+	if (o < output->numModes)
+	    mode = output->modes[o];
+	else
+	    mode = output->userModes[o - output->numModes];
 	
 	l = data->nsize;
 	size[l].id = data->nsize;
@@ -524,9 +527,12 @@ RR10GetData (ScreenPtr pScreen, RROutput
 	/*
 	 * Find all modes with matching size
 	 */
-	for (os = o; os < output->numModes; os++)
+	for (os = o; os < output->numModes + output->numUserModes; os++)
 	{
-	    mode = output->modes[os];
+	    if (os < output->numModes)
+		mode = output->modes[os];
+	    else
+		mode = output->userModes[os - output->numModes];
 	    if (mode->mode.width == size[l].width &&
 		mode->mode.height == size[l].height)
 	    {



More information about the xorg-commit mailing list