This patch adds support for the

  Option "ZoomModes" "1600x1200 1280x1024 1280x1024 640x480"

in a monitor section.  The code tries to match each mode name and 
sets the M_T_USERDEF mode type bit if found.  A mode will not be 
rematched so specifying a name twice selects the next, usually lower 
refresh rate, mode.

The option value is a string of mode names delimited by spaces.  As 
such, name tokenization is done at output enable time.  Ideally 
this should be done when parsing the Xorg.conf file.  A check of 
xserver/hw/xfree86/parser/{Flags.c Monitor.c scan.c xf86Optrec.h} 
shows 2 other possibilities:

1. Allow a new keyword ZoomModes followed by multiple mode names.  This
  would be a port of the Screen/Display/Modes code.

2. Allow generic options to be followed by multiple arguments.  This 
  requires either a char *opt_val[MAXVALS] thus introducing a compile 
  time maximum, a linked list of values, or a flexible array using 
  e.g. a char *opt_val[].  

These alternatives are not forward compatible since an older X server 
will fail to parse such constructs.  The option keyword extension is 
the logical choice but seems not worth the added complexity.  

Since enabling and disabling outputs is not a common event nor time 
critical the subideal form, the string of mode names, seems the best 
choice.  

A patch for the man page is included.

http://bugs.freedesktop.org/show_bug.cgi?id=17954

Signed-off-by: Servaas Vandenberghe
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index c2814d4..74c8d66 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -432,6 +433,7 @@ extern XF86ConfigPtr xf86configptr;
 
 typedef enum {
     OPTION_PREFERRED_MODE,
+    OPTION_ZOOM_MODES,
     OPTION_POSITION,
     OPTION_BELOW,
     OPTION_RIGHT_OF,
@@ -450,6 +452,7 @@ typedef enum {
 
 static OptionInfoRec xf86OutputOptions[] = {
     {OPTION_PREFERRED_MODE, "PreferredMode",   OPTV_STRING,  {0}, FALSE },
+    {OPTION_ZOOM_MODES,     "ZoomModes",       OPTV_STRING,  {0}, FALSE },
     {OPTION_POSITION,      "Position",         OPTV_STRING,  {0}, FALSE },
     {OPTION_BELOW,         "Below",            OPTV_STRING,  {0}, FALSE },
     {OPTION_RIGHT_OF,      "RightOf",          OPTV_STRING,  {0}, FALSE },
@@ -1453,6 +1456,73 @@ preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output)
     return preferred_mode;
 }
 
+/** identify a token
+ * args
+ *   src[]  the string with zero or more tokens, e.g. "tok0 tok1".
+ *   buf[]  used to store a '\0' terminated copy of the first token.
+ * return
+ *   a pointer into src[] at the token terminating character, or
+ *   NULL if no token is found.
+ */
+static const char *
+gettoken(const char *src, char *buf)
+{
+    const char *token, *next, *delim = " \t";
+    int skip, len;
+
+    if (!src)
+       return NULL;
+
+    skip = strspn(src, delim);
+    token = &src[skip];
+
+    /* Support for backslash escaped delimiters could be implemented here. */
+    len = strcspn(token, delim);
+    if (buf) {
+       strncpy(buf, token, len);
+       buf[len] = '\0';
+    }
+
+    /* token[0] != '\0'  <==>  len > 0 */
+    next = len ? &token[len] : NULL;
+
+    return next;
+}
+
+static int
+processZoomModes(xf86OutputPtr output)
+{
+    const char *zoom_modes;
+    int count = 0;
+
+    /* Check for a user configured zoom mode list
+     * e.g. Option "ZoomModes" "1600x1200 1280x1024 1280x1024 640x480"
+     */
+    zoom_modes = xf86GetOptValString(output->options, OPTION_ZOOM_MODES);
+
+    if (zoom_modes) {
+       int bufsiz = strlen(zoom_modes) + 1;
+       char buf[bufsiz];
+       const char *next;
+
+       next = gettoken(zoom_modes, buf);
+       while (next) {
+           DisplayModePtr mode;
+
+           for (mode = output->probed_modes; mode; mode = mode->next)
+               if (!strcmp(buf, mode->name) && !(mode->type & M_T_USERDEF)) {
+                   mode->type |= M_T_USERDEF;
+                   break;
+               }
+
+           count++;
+           next = gettoken(next, buf);
+       }
+    }
+
+    return count;
+}
+
 static void
 GuessRangeFromModes(MonPtr mon, DisplayModePtr mode)
 {
@@ -1734,7 +1804,6 @@ xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int 
maxY)
        
        /* Check for a configured preference for a particular mode */
        preferred_mode = preferredMode(scrn, output);
-
        if (preferred_mode)
        {
            for (mode = output->probed_modes; mode; mode = mode->next)
@@ -1752,12 +1821,15 @@ xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int 
maxY)
                        mode->prev = NULL;
                        output->probed_modes = mode;
                    }
-                   mode->type |= (M_T_PREFERRED|M_T_USERPREF);
+                   mode->type |= (M_T_USERPREF|M_T_PREFERRED);
                    break;
                }
            }
        }
-       
+
+       /* Ctrl+Alt+Keypad-{Plus,Minus} zoom mode M_T_USERDEF */
+       processZoomModes(output);
+
        output->initial_rotation = xf86OutputInitialRotation (output);
 
        if (debug_modes) {
--- xserver/hw/xfree86/man/xorg.conf.man-b      2011-08-28 23:25:27.000000000 
+0200
+++ xserver/hw/xfree86/man/xorg.conf.man        2011-08-30 19:02:50.000000000 
+0200
@@ -1671,6 +1671,18 @@
 of the monitor.
 (RandR 1.2-supporting drivers only)
 .TP 7
+.BI "Option \*qZoomModes\*q \*q" name " " name " " ... \*q
+This optional entry specifies modes to be marked as zoom modes.  
+It is possible to switch to the next and previous mode with
+.B Ctrl+Alt+Keypad\-Plus
+and
+.BR Ctrl+Alt+Keypad\-Minus .
+All these keypad available modes are selected from the screen mode list.  
+This list is a copy of the compatibility output monitor mode list.  
+Since this output is the output connected to the lowest dot\-resolution 
+monitor, as determined from its largest mode, that monitor defines the 
+available zoom modes.  (RandR 1.2-supporting drivers only)
+.TP 7
 .BI "Option \*qPosition\*q \*q" x " " y \*q
 This optional entry specifies the position of the monitor within the X
 screen.
_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to