X11 XOpenDisplay returns null?

having a bit of trouble with my new Jetson Nano, freshly installed with Ubuntu 18.04
None of my OpenGLES2.0 test programs are able to open an X11 window and stall at any attempt to initialise graphics…

Any suggestions? I already did xhost + on the terminal in case that was an issue?

As a bit of extra info, I am using VisualGDB to build. deploy and debug the project which never opens an Xwindow
However if I ./ the build from a terminal on the nano it runs, happily opening an Xwindow.

Any idea what may be wrong?

We are not familiar with VirtualGDB. Forum users may have ever run it and can share more information.

VisualGDB (www.visualgdb.com) is just a plug in for Visual Studio, it allows for a smoother flow of development, its well worth trying it, its made dev on multiple SBC and embedded systems very easy.

But this issue is a bit odd. I’ve had it on a couple of Ubuntu 18.04 systems, though usually found that xhost+ resolved it. The VisualGDB people are adament they don’t have any impact on the XDisplay, they say…

“VisualGDB simply requests the target to enable the X11-over-SSH forwarding. The exact implementation of this logic is provided by the target and is outside VisualGDB’s control. Please refer to the Linux and X11 documentation for more details.”

I just can’t find anything online that can help with this.

Do you happen to have a simple graphic test case where an Xdisplay/EGL/OpenGLES2 triangle can be displayed? Otherwise I’ll knock one up and compare with standard Visual Studio for Linux vs VisualGDB.

I’m just speculating since I’ve never used any of this particular software, but it is typical for X/ssh forwarding to be disabled by default in some cases (there may be both ssh and X11 security components). This is basically the concept of sane security defaults, and then letting the user open whatever is needed, versus simply making it all available (it isn’t particular to this hardware, and it isn’t even just a single Linux distribution…they are all migrating towards this).

I am assuming the forwarding is over ssh, and that it is a security contstraint. “xhost+” is just one part of the security, and if you look at the ssh side, then you might find it wasn’t X alone which was restricting this. In “/etc/ssh/sshd_config” on the Jetson, make sure you have the “X11Forwarding” set to “yes”. Once that is in place, then which user are you logged in as (this would be needed even if not logging in through ssh)? Do you have a display connected to the Nano, and is there an active login to the display by that user?

Does your debug tool have a customization setup for any kind of login or connection settings? If so, what are they set to?

I’ve put the nano away till the weekend as I have things to do at the moment, and its distracting me :D
I’ll check the sshd config

VisualGDB allows for ssh connections to the target, I’m honestly not a linux person so a lot of this is way over my head, which is one reason why I use VisualGDB, it handles all the connection stuff for me, and just lets me treat it as a target to deply to, normally painless and is fine on 95% of SBC targets I use so I never have to actually get my linux head on.

The only options Visual gives me relating to X11 is that I have 3 options
Forward to Windows machine (via XMing)/Show on Target/Disable

When Show on target is selected (the usua; option) I get a warning that brian must be logged on at the target and xauth must nt block connections from other sessions.

I’m logged on as brian, and xhost + should prevent any block…but if indeed X11forwarding is blocked somewhere i need to check that.
yes I do have a display attacked also, and I am logged in as brian and have a nice desktop screen. And as I say if I navigate to the directoryu where the build was built, I can execute with ./ and it runs fine…


And your idea interested me so I just had to check and pulled out the nano again and checked the config, but the X11forwarding is indeed set to yes.

So, its not that, I should have no problem logged in as brian but I just get no xdisplay from XOpenDisplay(NUKK) which returns NULL.

interesting update (I should have gone to bed but once I started I couldn’t stop)

I’ve tried using PuTTY to execute programs that are known to build on the Nano, my own, and the standard OpenGLES3.0 demos…

All run fine when executed with ./ from a teminal on the Jetson

But they don’t work when run ./ from an SSH client. Including Putty, they also fail to get an Xdisplay

Is there something else not set up? It would seem X11Forwarding isn’t working despite being setup in the config?

Some background on how the GPU is used with both a graphical desktop and CUDA might help you, so read on if ambitious…

Under Linux the video display (the GUI) is separate from the kernel. Even command line text-only login is separate from the operating system. The “shell” is the text only interface to the “kernel”, and all operating systems have a kernel, but some integrate graphics or other features directly into the kernel and thus are not separable. In Linux the operating system can be functioning perfectly even without any GUI or text interface.

The GUI on Linux is performed by a server known as the “X server”, and uses the X11 protocol (there are alternatives, but this is the default in most installations, e.g., you might see references to Wayland/Vulkan, but it isn’t unusual these are just layers adapting to X11 protocols). There is an environment variable which identifies the X server in use, the “DISPLAY” environment variable. A user ID and “DISPLAY” are associated together to allow GUI access.

The NVIDIA hardware-accelerated driver plugs in dynamically to the X server, and the X protocols adapt to the binary driver. People often think that X is a GUI, but it isn’t…it is simply a predefined set of protocols for talking to a buffer with certain properties, and almost always that buffer has a computer monitor attached to it. For hardware-acceleration, it is really the NVIDIA driver performing the buffer access. In the case of CUDA, this is also true…CUDA tends to talk to the NVIDIA driver, but usually via talking to the X server and the X server binds to the driver.

No X server, then no GUI. And no CUDA. There are exceptions, but for almost everything you see there won’t be an exception. If you have an X server, but nobody is logged in to it, then you don’t have an X server because a session requires a user ID. If you have a user, but that user isn’t logged in to the server which the DISPLAY environment variable points at, then you don’t have a GUI, and you don’t have CUDA. Ssh may talk to the remote system, but if the command you issue does not name a valid combination of user ID and DISPLAY, then it won’t work.

X is very flexible, in that one Linux system can run an X server (call it the PC), and the remote system can relay X11 protocol messages from a system without a GUI (call it the Nano) to the current system. If the Nano has been given permission, then it can relay the X11 protocol to the host and whatever you run on the Nano will pop up on the host PC. This is not always what you want and may have results you don’t expect, but to start with Windows does not have an X server unless you’ve installed something like a Cygwin emulation. This isn’t what you want (explained later).

When one Linux system forwards X11 protocols to another, then it is this other system doing the actual CUDA or hardware accelerated GUI rendering. So if you run a GUI or CUDA command on a Nano, but display it to the PC, then the Nano never uses its GPU, and the Nano won’t require a display…all of those requirements fall to the displaying PC.

The X server has both “physical” and “virtual” versions available. The physical version, with a user logged in, would display anything the ssh command runs if the the ssh is logged in to the same user name and if the DISPLAY variable is pointed at the Jetson’s display. If you want to operate “headless” (without a real monitor), then you need a virtual X server. The X server does not care if the buffer associated with it is being examined by a real monitor, or by RAM emulating a monitor. If you are not displaying something (or perhaps even if you are), then there is no reason to attach a monitor. The side effects of the CUDA might end up streaming over a web server or to a file and you wouldn’t care about physical display. The virtual X server is perfect for that.

Desktop sharing protocols, such as various VNC servers you hear about, even the ones on Windows, can talk to a virtual server and then even Windows can have a GUI up from the Jetson. Your remote ssh commands would be run on the Nano by associating a user and DISPLAY to the virtual server, and then some custom virtual desktop sharing software can become the desktop on Windows or another Linux system without any CUDA or X server being required on the PC viewing the desktop.

So on your Nano, log in to the GUI. Open a text console, and see what DISPLAY it is like this:


Probably it will be “:0” (the traditional first X server…you can run more than one), or maybe “:1” (some of the recent L4T releases use that). If the user you logged in to is named “ubuntu”, and if DISPLAY is “:0”, then from ssh you can run a command like this:

export DISPLAY=":0"
...any GUI command...


DISPLAY=":0" some_command

The first form stores the environment variable for future commands as well as current. The latter form exists for only one command.

So about X11Forwarding…if Windows doesn’t have an X server, then you can’t forward…well you can forward, but Windows doesn’t know what it is.

One choice: Install a virtual server on the Nano, and a remote desktop client on Windows.
Another choice: Log in to the Nano GUI, and run commands with that associated DISPLAY.

This is a lot less complicated under Linux because by default all of the desktop distributions come with X.

Thank you, I really appreciate the explination, though I’m an experienced coder, on Windows and Consoles, I am a total noob at linux and have treated it as a simple box up until now, never having to actually get too deep into it. So apologies if some of my understanding is off, its been reached from trial and error.

Let me explain a little more… I’m actually not trying to get anything displaying on my Windows machine, My Nano is hooked up to an HDMI monitor, and has keyboar/mouse in place working fine. I only use Visual Studio with the VisualGDB plug in, as an IDE on my Windows PC, and it transfers all files/assets and builds the project on the Nano, (all fine) Normally a run or debug from VS will fire up the Project on the target, and GDB info is sent back to VS/VGDB allowing me to debug on PC, and run display on the target screen. This just isn’t happening on Nano

What I want to do (and can do on 99 out of 100 of my other SBC (yes I do have a lot)) is to send build and execute the program from my Windows machine via VS or SSH, but running on the Nano, since it can’t seem to open a display when executed from an SSH client, does that make any sesne

To detail my issue further

If I open a terminal on the Jetson itself, navigate to the tmp\VisualGDB\c…etc folder where my VisualGDB puts my build

and ./runnablebuild

it runs perfectly, of course its running stand alone here is the code

	     * X11 native display initialization
	x_display = XOpenDisplay(NULL);

		if (x_display == NULL)
			printf("Sorry to say we can't create an Xwindow and this will fail");
			exit(0); //return ; // we need to trap this;

If I use VisualGDB’s usual build and debug options, which rely on ssh, I get no X11 display and project fails trying to use a NULL pointer it got from XOpenDisplay(NULL).
I added a Fail output on no display, and exit if the display is null.

If I use VisualGDB’s SSH manager and a SmarTTY console, I get the same fail

If I use PuTTY to navigate to the folder and do ./runnablebuild it also fails for the same reasons and exits

So any attempt to run from SSH seems to fail… This isn’t just my projects, I have the standard goldbook OpenGLES3.0 builds on the Jetson, built with cmake/make and all run fine on a Jetson Terminal, going to the folder and ./ the executable, but all fail from a client SSH terminal.

Now after reading your message, echo$ display on the Nano Terminal actually gives me :1

Does any of this seem wrong?

So is it correct that while debugging there is a Nano login via the GUI? The fix would be fairly trivial in that case. From that GUI, run the command “echo $DISPLAY”. This tells you which display…perhaps it is “:0”. In that case, from your debugger, have it prepend the command to run the program with:


…so for example, if the program being run is xterm:

DISPLAY=":0" xterm

Now I don’t know for certain about the code you posted, but I suspect this line is trying to figure out DISPLAY:

x_display = XOpenDisplay(NULL);

If you know the “DISPLAY” via the “echo” command mentioned above, then you could issue a fallback like this (I am assuming “x_display” is “std::string” or “char*”…or can be converted from a string):

    	     * X11 native display initialization
    	x_display = XOpenDisplay(NULL);

    		if (x_display == NULL)

    			printf("Sorry to say we can't create an Xwindow and this will fail");
    			exit(0); //return ; // we need to trap this;

The ssh must be as the same user as is logged in to the Jetson.

If there is no login, then you must add a virtual X server for headless operation. Being logged out is the same as being headless for these purposes (the virtual X server can have a login by default).

Btw, it may be that the “XOpenDisplay(NULL)” is trying to inherit the environment variable, and if the environment variable is set (via the DISPLAY=“:0”), then it wouldn’t fail with NULL.

yes I am logged in as brian
and the echo DISPLAY gives :1

I’m not using xterm as I say I am trying to run the code on the Nano’s own screen and monitor, but execute it from a connected PC.

Sadly your solution isn’t correct, and you misunderstand how the C++ code works, x_display is a pointer to a Display struct not a char, which is a fairly complex struct that needs to be aquired by the XOpenDisplay, this is what the struct looks like in the Xlib.h files

	XExtData *ext_data;	/* hook for extension to hang data */
	struct _XPrivate *private1;
	int fd;			/* Network socket. */
	int private2;
	int proto_major_version;/* major version of server's X protocol */
	int proto_minor_version;/* minor version of servers X protocol */
	char *vendor;		/* vendor of the server hardware */
        XID private3;
	XID private4;
	XID private5;
	int private6;
	XID (*resource_alloc)(	/* allocator function */
		struct _XDisplay*
	int byte_order;		/* screen byte order, LSBFirst, MSBFirst */
	int bitmap_unit;	/* padding and data requirements */
	int bitmap_pad;		/* padding requirements on bitmaps */
	int bitmap_bit_order;	/* LeastSignificant or MostSignificant */
	int nformats;		/* number of pixmap formats in list */
	ScreenFormat *pixmap_format;	/* pixmap format list */
	int private8;
	int release;		/* release of the server */
	struct _XPrivate *private9, *private10;
	int qlen;		/* Length of input event queue */
	unsigned long last_request_read; /* seq number of last event read */
	unsigned long request;	/* sequence number of last request. */
	XPointer private11;
	XPointer private12;
	XPointer private13;
	XPointer private14;
	unsigned max_request_size; /* maximum number 32 bit words in request*/
	struct _XrmHashBucketRec *db;
	int (*private15)(
		struct _XDisplay*
	char *display_name;	/* "host:display" string used on this connect*/
	int default_screen;	/* default screen for operations */
	int nscreens;		/* number of screens on this server*/
	Screen *screens;	/* pointer to list of screens */
	unsigned long motion_buffer;	/* size of motion buffer */
	unsigned long private16;
	int min_keycode;	/* minimum defined keycode */
	int max_keycode;	/* maximum defined keycode */
	XPointer private17;
	XPointer private18;
	int private19;
	char *xdefaults;	/* contents of defaults from server */
	/* there is more to this structure, but it is private to Xlib */

So you see quite a complex construct. It would actually be more correct to try something like.
But that won’t work either.

Indeed this line

x_display =XOpenDisplay(NULL)

is C++ code to get the internal address of the Display stucture, Passing NULL forces the function to return the default value that relates the display held by the DISPLAY variable.
As you correctly suggest, it should indeed return the current display settings that the OS is using for the default display, normally as you say, set up in DISPLAY as :0 or :1 in my case DISPLAY is indeed set, to :1. So I do have an internal variable for DISPLAY, but I can only apparently get it to work when I execute the project which relies on this Xwindow set up from a Nano GUI terminal… The SSH terminal on my PC, or via my VisualGDB setup isn’t doing it.

This part of your answer is the key point.

This is exactly the behaviour I expect, and get on almost all other systems, but the Nano fails when I try to execute from an SSH terminal, and I really don’t know why.

found it.

I figured it had to be something to do with access rights somewhere, so I went to the settings and checked the Security and Privacy->Password settings. I didn’t see anything odd there, but while I was in, I switched to automatic login and reset.

Guess what… that solves it… My projects now happily build and run and can be executed from my VisualGDB debug command.

To double check I set auto login back to off and sure enough my VisualGDB failed again

So the secret is… ensure you have automatic login, with your matching ssh username

Bizzare issue…Dunno why this is happening, but very happy I resolved it.

I dislike automatic logins, but the synopsis would be that anything preventing read of the environment variable for DISPLAY (including security) would indeed cause failure. Manual login should work the same as automatic so long as DISPLAY is correctly set. But if it works, and you’re not worried about someone walking up to the GUI and doing something malicious, then there is no problem.

Btw, I see this in the struct:

char *display_name;	/* "host:display" string used on this connect*/

…this is probably the very first thing filled out in the struct and would be the “:1”, or perhaps with the IP address (example “”). I am betting that the function call reads the environment and places this in the struct prior to filling in the other parameters via query to that X server. If it turns out that the latter form with “:1” is used, then remote security issues also exist beyond just the local security issues (ssh is a local login unless X protocol is forwarded…in your case X protocol events are not forwarded).

Yes until the call to the XOpenWindow(NULL) the struct is empty and passing the NULL value fills it in with data relating to the default DISPLAY. I’ve not looked to see what it actually loaded in, it isn’t really of interest as there’s no certainty that it does not create its own format unrelated to the calling request.

Manual Login, does work on almost all other systems, I do have to do a manual login on quite a few of my toys.

I’m personally not at all worried about security in fact its something of a hinderence to my dev cycle, as regular resets are needed. The system is running in a closed network and is not left on for longer than it is in use. So quite happy to do an Automatic Login, but the fact it literally fails to provide a DISPLAY over ssh is something I don’t think I have seen before (I do have couple of other devices which had issues with Display but Xhost + or running as root usually solved that)

Do you think its a bug in the manual log in, or a design I was previously lucky not to encounter?

It would be hard to guess what the case is, but if the ssh itself tries to query for DISPLAY properties prior to the login finishing, then the struct would not be valid. How soon after manual login does the ssh connection attempt to fill in the struct? Or does ssh exist prior to GUI login being complete?

When normal X programs are run they don’t query DISPLAY until the program itself starts (and ssh does not know DISPLAY unless you manually tell it which…a non-GUI session has no way of finding DISPLAY if not told, and if told too soon it would be invalid). If your ssh setup automatically determines that information upon connect, then perhaps it is simply starting too soon. That would be one possibility, but I have no idea how the program you are running deals with filling in its struct.

the machine is logged in and working well before the project is compiled and a run attempted. The filling in of the struct is done by X11.h its just a project that is edited on PC, sent to the target to build and then excuted via SSH using GDB to provide debug info to Visual studio, its a traditional target based dev method.

anyway, its working I can proceed, thanks for ht ehelp.