summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-01-23 10:56:27 +0100
committerwm4 <wm4@nowhere>2013-01-23 10:56:27 +0100
commitccaed5eb071319f9d412f42610302765b844f978 (patch)
tree33b609c07b56f06992afa92a3205416e7c3ef913 /core
parent4c56baba4048f8a881253d4fe2f49c2715c77376 (diff)
downloadmpv-ccaed5eb071319f9d412f42610302765b844f978.tar.bz2
mpv-ccaed5eb071319f9d412f42610302765b844f978.tar.xz
options: allow using % for width and height in --geometry
Now all numbers in the --geometry specification can take percentages. Rewrite the parsing of --geometry, because adjusting the sscanf() mess would require adding all the combinations of using and not using %. As a side effect, using % and pixel values can be freely mixed. Keep the aspect if only one of width or height is set. This is more useful in general. Note: there is one semantic change: --geometry=num used to mean setting the window X position, but now it means setting the window width. Apparently this was a mplayer-specific feature (not part of standard X geometry specifications), and it doesn't look like an overly useful feature, so we are fine with breaking it. In general, the new parsing should still adhere to standard X geometry specification (as used by XParseGeometry()).
Diffstat (limited to 'core')
-rw-r--r--core/m_option.c145
-rw-r--r--core/m_option.h1
2 files changed, 83 insertions, 63 deletions
diff --git a/core/m_option.c b/core/m_option.c
index 0811e99a79..a55e87a5d3 100644
--- a/core/m_option.c
+++ b/core/m_option.c
@@ -1166,69 +1166,83 @@ const m_option_type_t m_option_type_color = {
};
+// Parse a >=0 number starting at s. Set s to the string following the number.
+// If the number ends with '%', eat that and set *out_per to true, but only
+// if the number is between 0-100; if not, don't eat anything, even the number.
+static bool eat_num_per(bstr *s, int *out_num, bool *out_per)
+{
+ bstr rest;
+ long long v = bstrtoll(*s, &rest, 10);
+ if (s->len == rest.len || v < INT_MIN || v > INT_MAX)
+ return false;
+ *out_num = v;
+ *out_per = false;
+ *s = rest;
+ if (bstr_eatstart0(&rest, "%") && v >= 0 && v <= 100) {
+ *out_per = true;
+ *s = rest;
+ }
+ return true;
+}
-static bool parse_geometry_str(struct m_geometry *gm, char *s)
+static bool parse_geometry_str(struct m_geometry *gm, bstr s)
{
- if (s == NULL)
+ *gm = (struct m_geometry) { .x = INT_MIN, .y = INT_MIN };
+ if (s.len == 0)
return true;
- char xsign[2], ysign[2], dummy[2];
- int width, height, xoff, yoff, xper, yper;
- int ok = 0;
- for (int i = 0; !ok && i < 9; i++) {
- width = height = xoff = yoff = xper = yper = INT_MIN;
- strcpy(xsign, "+");
- strcpy(ysign, "+");
- switch (i) {
- case 0:
- ok = sscanf(s, "%ix%i%1[+-]%i%1[+-]%i%c",
- &width, &height, xsign, &xoff, ysign,
- &yoff, dummy) == 6;
- break;
- case 1:
- ok = sscanf(s, "%ix%i%c", &width, &height, dummy) == 2;
- break;
- case 2:
- ok = sscanf(s, "%1[+-]%i%1[+-]%i%c",
- xsign, &xoff, ysign, &yoff, dummy) == 4;
- break;
- case 3:
- ok = sscanf(s, "%i%%:%i%1[%]%c", &xper, &yper, dummy, dummy) == 3;
- break;
- case 4:
- ok = sscanf(s, "%i:%i%1[%]%c", &xoff, &yper, dummy, dummy) == 3;
- break;
- case 5:
- ok = sscanf(s, "%i%%:%i%c", &xper, &yoff, dummy) == 2;
- break;
- case 6:
- ok = sscanf(s, "%i:%i%c", &xoff, &yoff, dummy) == 2;
- break;
- case 7:
- ok = sscanf(s, "%i%1[%]%c", &xper, dummy, dummy) == 2;
- break;
- case 8:
- ok = sscanf(s, "%i%c", &xoff, dummy) == 1;
- break;
+ // Approximate grammar:
+ // [W[xH]][{+-}X{+-}Y] | [X:Y]
+ // (meaning: [optional] {one character of} one|alternative)
+ // Every number can be followed by '%'
+ int num;
+ bool per;
+
+#define READ_NUM(F, F_PER) do { \
+ if (!eat_num_per(&s, &num, &per)) \
+ goto error; \
+ gm->F = num; \
+ gm->F_PER = per; \
+} while(0)
+
+#define READ_SIGN(F) do { \
+ if (bstr_eatstart0(&s, "+")) { \
+ gm->F = false; \
+ } else if (bstr_eatstart0(&s, "-")) {\
+ gm->F = true; \
+ } else goto error; \
+} while(0)
+
+ if (bstrchr(s, ':') < 0) {
+ gm->wh_valid = true;
+ if (!bstr_startswith0(s, "+") && !bstr_startswith0(s, "-")) {
+ READ_NUM(w, w_per);
+ if (bstr_eatstart0(&s, "x"))
+ READ_NUM(h, h_per);
+ }
+ if (s.len > 0) {
+ gm->xy_valid = true;
+ READ_SIGN(x_sign);
+ READ_NUM(x, x_per);
+ READ_SIGN(y_sign);
+ READ_NUM(y, y_per);
}
+ } else {
+ gm->xy_valid = true;
+ READ_NUM(x, x_per);
+ if (!bstr_eatstart0(&s, ":"))
+ goto error;
+ READ_NUM(y, y_per);
}
- if (!ok)
- return false;
-
- gm->x_per = xper >= 0 && xper <= 100;
- gm->x = gm->x_per ? xper : xoff;
- gm->x_sign = xsign[0] == '-';
- gm->y_per = yper >= 0 && yper <= 100;
- gm->y = gm->y_per ? yper : yoff;
- gm->y_sign = ysign[0] == '-';
- gm->xy_valid = gm->x != INT_MIN || gm->y != INT_MIN;
- gm->w = width;
- gm->h = height;
- gm->wh_valid = gm->w > 0 || gm->h > 0;
+ return s.len == 0;
- return true;
+error:
+ return false;
}
+#undef READ_NUM
+#undef READ_SIGN
+
// xpos,ypos: position of the left upper corner
// widw,widh: width and height of the window
// scrw,scrh: width and height of the current screen
@@ -1237,10 +1251,18 @@ void m_geometry_apply(int *xpos, int *ypos, int *widw, int *widh,
int scrw, int scrh, struct m_geometry *gm)
{
if (gm->wh_valid) {
+ int prew = *widw, preh = *widh;
if (gm->w > 0)
- *widw = gm->w;
+ *widw = gm->w_per ? scrw * (gm->w / 100.0) : gm->w;
if (gm->h > 0)
- *widh = gm->h;
+ *widh = gm->h_per ? scrh * (gm->h / 100.0) : gm->h;
+ // keep aspect if the other value is not set
+ double asp = (double)prew / preh;
+ if (gm->w > 0 && !(gm->h > 0)) {
+ *widh = *widw / asp;
+ } else if (!(gm->w > 0) && gm->h > 0) {
+ *widw = *widh * asp;
+ }
}
if (gm->xy_valid) {
@@ -1255,7 +1277,7 @@ void m_geometry_apply(int *xpos, int *ypos, int *widw, int *widh,
*ypos = gm->y;
if (gm->y_per)
*ypos = (scrh - *widh) * (*ypos / 100.0);
- if (gm->x_sign)
+ if (gm->y_sign)
*ypos = scrh - *widh - *ypos;
}
}
@@ -1264,11 +1286,8 @@ void m_geometry_apply(int *xpos, int *ypos, int *widw, int *widh,
static int parse_geometry(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
- char *s = bstrdup0(NULL, param);
- struct m_geometry gm = {0};
- bool res = parse_geometry_str(&gm, s);
- talloc_free(s);
- if (!res)
+ struct m_geometry gm;
+ if (!parse_geometry_str(&gm, param))
goto error;
if (dst)
@@ -1280,7 +1299,7 @@ error:
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: invalid geometry: '%.*s'\n",
BSTR_P(name), BSTR_P(param));
mp_msg(MSGT_CFGPARSER, MSGL_ERR,
- "Valid format: [WxH][[+-]X[+-]Y] | [X[%%]:[Y[%%]]]\n");
+ "Valid format: [W[%%][xH[%%]]][{+-}X[%%]{+-}Y[%%]] | [X[%%]:Y[%%]]\n");
return M_OPT_INVALID;
}
diff --git a/core/m_option.h b/core/m_option.h
index ca75d494bb..87fa959992 100644
--- a/core/m_option.h
+++ b/core/m_option.h
@@ -81,6 +81,7 @@ struct m_color {
struct m_geometry {
int x, y, w, h;
bool xy_valid : 1, wh_valid : 1;
+ bool w_per : 1, h_per : 1;
bool x_sign : 1, y_sign : 1, x_per : 1, y_per : 1;
};