Running headless (no X) is broken on Linux

If XOpenDisplay fails on Linux, it will crash when trying to access the display variable (which is a nullptr). I’ve attached a patch to fix the crash we encountered.

JUCE_X_linux_headless.txt (1.2 KB)

This is a known bug and something we wanted to fix for a long while now.

Hi, intending to do some headless dev this week. Is this still an issue?

Sorry, this is not on develop yet. But on it’s way…

OK it’s on develop now!

I think it would be nice if we were able to call Desktop::getInstance().getDisplays() when running headless (and it would of course return an empty list of displays when x11 is not available).

A lot of juce classes are calling getDisplays during their initialisation (ApplicationCommandManager constructor, setDefaultLookAndFeel, etc), so right now if I build any of those classes in a headless situation, the application is terminated with a ‘Failed to connect to the X Server.’ message.

2 Likes

here is the patch I am using to allow the getDisplays() call to not kill the application when running headless.

juce-git/modules/juce_gui_basics/native/juce_linux_X11.cpp

@@ -119,6 +119,19 @@
     clearSingletonInstance();
 }

+bool XWindowSystem::canOpenXDisplay() {
+    if (displayCount.get() > 0) return true;
+    String displayName (getenv ("DISPLAY"));
+    if (displayName.isEmpty())
+        displayName = ":0.0";
+
+    ::Display *d = XOpenDisplay (displayName.toUTF8());
+    if (d) XCloseDisplay(d);
+    if (d != 0) return true;
+    else return false;
+}

modules/juce_gui_basics/native/juce_linux_X11.h

@@ -44,6 +44,9 @@
     ::_XDisplay* displayUnref() noexcept;
     juce_DeclareSingleton (XWindowSystem, false)

+     bool canOpenXDisplay();
 private:
     ::_XDisplay* display;
     Atomic<int> displayCount;

modules/juce_gui_basics/native/juce_linux_X11_Windowing.cpp

@@ -3730,6 +3730,10 @@
 //==============================================================================
 void Desktop::Displays::findDisplays (float masterScale)
 {
+    if (!XWindowSystem::getInstance()->canOpenXDisplay()) return;
+
     ScopedXDisplay xDisplay;
     ::Display* display = xDisplay.get();

(moved this previously uncategorized topic to the Linux category where it seems to belong, to make it easier for others with the same issue to find it)