Running headless (no X) is broken on Linux


#1

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)


#2

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


#3

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


#4

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


#5

OK it’s on develop now!


#6

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.


#7

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();

#8

(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)