monitor: Add helper to parse simple mode strings

This will be used to extract the resolution and refresh rate from
strings like "1920x1080@60.0" or "1280x720". This aims to replace the
use of the locale dependent sscanf() function.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2902>
This commit is contained in:
Jonas Ådahl 2023-03-07 22:36:57 +01:00 committed by Marge Bot
parent 550a1dadf1
commit 2fd9834d94
3 changed files with 135 additions and 0 deletions

View File

@ -2305,3 +2305,50 @@ meta_monitor_set_hdr_metadata (MetaMonitor *monitor,
return TRUE; return TRUE;
} }
gboolean
meta_parse_monitor_mode (const char *string,
int *out_width,
int *out_height,
float *out_refresh_rate,
float fallback_refresh_rate)
{
char *ptr = (char *) string;
int width, height;
float refresh_rate;
width = g_ascii_strtoull (ptr, &ptr, 10);
if (width == 0)
return FALSE;
if (ptr[0] != 'x')
return FALSE;
ptr++;
height = g_ascii_strtoull (ptr, &ptr, 10);
if (height == 0)
return FALSE;
if (ptr[0] == '\0')
{
refresh_rate = fallback_refresh_rate;
goto out;
}
if (ptr[0] != '@')
return FALSE;
ptr++;
refresh_rate = g_ascii_strtod (ptr, &ptr);
if (refresh_rate == 0.0)
return FALSE;
if (ptr[0] != '\0')
return FALSE;
out:
*out_width = width;
*out_height = height;
*out_refresh_rate = refresh_rate;
return TRUE;
}

View File

@ -318,4 +318,11 @@ gboolean meta_monitor_set_hdr_metadata (MetaMonitor *monitor,
MetaOutputHdrMetadata *metadata, MetaOutputHdrMetadata *metadata,
GError **error); GError **error);
META_EXPORT_TEST
gboolean meta_parse_monitor_mode (const char *string,
int *out_width,
int *out_height,
float *out_refresh_rate,
float fallback_refresh_rate);
#endif /* META_MONITOR_H */ #endif /* META_MONITOR_H */

View File

@ -130,6 +130,85 @@ meta_test_monitor_mode_spec_similar_size (void)
} }
} }
static void
meta_test_monitor_parse_mode (void)
{
const float fallback_refresh_rate = 60.0;
struct {
const char *string;
gboolean expected_pass;
int expected_width;
int expected_height;
float expected_refresh_rate;
} test_cases[] = {
{
.string = "800x600",
.expected_pass = TRUE,
.expected_width = 800,
.expected_height = 600,
.expected_refresh_rate = fallback_refresh_rate,
},
{
.string = "1280x720@30",
.expected_pass = TRUE,
.expected_width = 1280,
.expected_height = 720,
.expected_refresh_rate = 30.0,
},
{
.string = "1920x1080@120.50",
.expected_pass = TRUE,
.expected_width = 1920,
.expected_height = 1080,
.expected_refresh_rate = 120.5,
},
{
.string = "800X600",
.expected_pass = FALSE,
},
{
.string = "800x",
.expected_pass = FALSE,
},
{
.string = "800x600@",
.expected_pass = FALSE,
},
{
.string = "800x600@notanumber",
.expected_pass = FALSE,
},
{
.string = "nonsense",
.expected_pass = FALSE,
},
};
int i;
for (i = 0; i < G_N_ELEMENTS (test_cases); i++)
{
int width, height;
float refresh_rate;
if (meta_parse_monitor_mode (test_cases[i].string,
&width, &height, &refresh_rate,
fallback_refresh_rate))
{
g_assert_true (test_cases[i].expected_pass);
g_assert_cmpint (width, ==, test_cases[i].expected_width);
g_assert_cmpint (height, ==, test_cases[i].expected_height);
g_assert_cmpfloat_with_epsilon (refresh_rate,
test_cases[i].expected_refresh_rate,
FLT_EPSILON);
}
else
{
g_assert_false (test_cases[i].expected_pass);
}
}
}
int int
main (int argc, main (int argc,
char **argv) char **argv)
@ -138,6 +217,8 @@ main (int argc,
g_test_add_func ("/backends/monitor/spec/similar-size", g_test_add_func ("/backends/monitor/spec/similar-size",
meta_test_monitor_mode_spec_similar_size); meta_test_monitor_mode_spec_similar_size);
g_test_add_func ("/backends/monitor/parse-mode",
meta_test_monitor_parse_mode);
return g_test_run (); return g_test_run ();
} }