From 80fab03198854268fc2258d7bdea2013e5d109f7 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:22:01 +0000 Subject: [PATCH] waitforx changes 1) Changed alarm message from "Timed out waiting for RandR outputs" to "Timed out waiting for X display". The former was confusing, and the times where this message was triggered were nothing to do with RandR 2) Don't try to open a display of the form ":n" or ":n.m" directly (n,m >= 0). If the X server hasn't yet opened its local socket, the XOpenDisplay() call can go to the network and possibly block for a long time. Instead, use the (undocumented) "unix:n" display specification, whih never goes to the network, and doesn't block. --- waitforx/waitforx.c | 59 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/waitforx/waitforx.c b/waitforx/waitforx.c index b9dabedfe2..993fd38796 100644 --- a/waitforx/waitforx.c +++ b/waitforx/waitforx.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -21,11 +22,48 @@ alarm_handler(int signal_num) * * Prefix the message with a newline in case another message * has been partly output */ - const char msg[] = "\nTimed out waiting for RandR outputs\n"; + const char msg[] = "\nTimed out waiting for X display\n"; g_file_write(1, msg, g_strlen(msg)); exit(XW_STATUS_TIMED_OUT); } +/*****************************************************************************/ +/*** + * Checks whether display is local. + * + * Local displays are of the form ':n' or ':n.m' where 'n' and 'm' + * are unsigned numbers + * + * @param display Display string + * @return boolean + */ +static int +is_local_display(const char *display) +{ + int result = 0; + if (display != NULL && *display++ == ':' && isdigit(*display)) + { + do + { + ++display; + } + while (isdigit(*display)); + + // Skip the optional screen identifier + if (*display == '.' && isdigit(*(display + 1))) + { + do + { + ++display; + } + while (isdigit(*display)); + } + + result = (*display == '\0'); + } + return result; +} + /*****************************************************************************/ static Display * open_display(const char *display) @@ -36,7 +74,7 @@ open_display(const char *display) for (n = 1; n <= ATTEMPTS; ++n) { - printf("Opening display %s. Attempt %u of %u\n", display, n, wait); + printf("Opening display '%s'. Attempt %u of %u\n", display, n, wait); dpy = XOpenDisplay(display); if (dpy != NULL) { @@ -112,6 +150,7 @@ usage(const char *argv0, int status) int main(int argc, char **argv) { + char unix_display[64]; // Used for local (unix) displays only const char *display_name = NULL; int opt; int status = XW_STATUS_MISC_ERROR; @@ -140,6 +179,22 @@ main(int argc, char **argv) g_set_alarm(alarm_handler, ALARM_WAIT); + if (is_local_display(display_name)) + { + // Don't use the raw display value, as this goes to the + // network if the X server port is not yet open. This can + // block if the network is configured in an unexpected way, + // which leads to use failing to detect the X server starting + // up shortly after. + // + // This code attempts to use a string such as "unix:10" to open + // the display. This is undocumented in the X11 man pages but + // is implemented in _xcb_open() from libxcb + // (which libX11 is now layered on). + snprintf(unix_display, sizeof(unix_display), "unix%s", display_name); + display_name = unix_display; + } + dpy = open_display(display_name); if (!dpy) {