How to determine from a python application if X server/X forwarding is running?
Check to see that the $DISPLAY
environment variable is set - if they didn't use ssh -X
, it will be empty (instead of containing something like localhost:10
).
How do I know when X server has completed the drawing?
It seems you are expecting XDrawRectangle()
to generate Expose
events, but it will never happen, because this is not how it works. Expose
events are generated when a window is mapped, resized, moved or when an obscuring window is unmapped, but not when drawing into a window. Actually, the only Expose
event you are interesting in is the one generated by XMapWindow()
. After receiving this first Expose
event you know that window is mapped and can be drawn to. You should also call XClearWindow()
before mapping a window to ensure it doesn't contain any garbage. Sometimes you may also want to check if (event.xexpose.count == 0)
to process only the latest event in the queue, but it shouldn't be necessary in your example. Then just draw into the window and probably flush the buffer with XFlush()
or XSync()
after every draw. This should do what you want(I modified coordinates a little bit, but the principle is the same):
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
#include <chrono>
#include <iostream>
#include <thread>
using namespace std;
int main()
{
Display* disp;
int screen;
Window win;
GC gc;
disp = XOpenDisplay(NULL);
screen = DefaultScreen(disp);
XColor color;
Colormap colormap;
char black[] = "#ffffff";
colormap = DefaultColormap(disp, 0);
XParseColor(disp, colormap, black, &color);
XAllocColor(disp, colormap, &color);
win = XCreateSimpleWindow(disp,
RootWindow(disp, screen),
10,
10,
1500,
1500,
0,
WhitePixel(disp, screen),
color.pixel);
XSizeHints my_hints = {0};
my_hints.flags = PPosition | PSize;
my_hints.x = 10;
my_hints.y = 10;
my_hints.width = 1500;
my_hints.height = 1500;
XSetNormalHints(disp, win, &my_hints);
gc = XCreateGC(disp, win, 0, 0);
XColor color1;
Colormap colormap1;
char red[] = "#000000";
colormap1 = DefaultColormap(disp, 0);
XParseColor(disp, colormap1, red, &color1);
XAllocColor(disp, colormap1, &color1);
XSetForeground(disp, gc, color1.pixel);
XSelectInput(disp, win, ExposureMask);
int x = 10;
int y = 10;
int i = 0;
XClearWindow(disp, win); // Clear window from possible garbage
XMapWindow(disp, win);
XEvent event;
while (true)
{
// Wait for window to be mapped
XNextEvent(disp, &event);
if (event.xany.window == win && event.type == Expose)
{
break;
}
}
for (int k = 0; k < 20; ++k)
{
std::cout << i << '\n';
XDrawRectangle(disp, win, gc, x, y, 500, 500);
XFlush(disp);
++i;
x += 10;
y += 10;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
XFreeGC(disp, gc);
XDestroyWindow(disp, win);
XCloseDisplay(disp);
return 0;
}
How to set up working X11 forwarding on WSL2
TL;DR:
Add the following to your ~/.bashrc
:
export DISPLAY=$(ip route list default | awk '{print $3}'):0
export LIBGL_ALWAYS_INDIRECT=1
Enable Public Access on your X11 server for Windows.*
Add a separate inbound rule for TCP port 6000 to the windows firewall in order to allow WSL access to the X server, as described by the wsl-windows-toolbar-launcher people.
As pointed out by WSL_subreddit_mod on reddit and as you can read in Microsoft's documentation on WSL2, the WSL2 architecture uses virtualized network components. This means that WSL2 has a different IP address than the host machine.
This explains why the X11 forwarding settings of WSL1 cannot simply be transferred to WSL2.
On the Ubuntu Wiki page about WSL you can already find a configuration adapted for WSL2 under Running Graphical Applications. A similar configuration is also suggested by the above mentioned Reddit User, who also contributes another part of the solution: Enable Public Access on the X11 server under Windows.
This means add the following to your ~/.bashrc
:
export DISPLAY=$(ip route list default | awk '{print $3}'):0
export LIBGL_ALWAYS_INDIRECT=1
And Enable Public Access on your X11 server for Windows.*
The most important part to enable X11 forwarding for WSL2 on Windows 10 is still missing: the Windows firewall blocks connections via the network interface configured for WSL by default.
A separate inbound rule for TCP port 6000 is required to allow WSL access to the X server. After the rule has been created, as described by the wsl-windows-toolbar-launcher people, the IP address range can be restricted to the WSL subnet in the settings of the newly created rule, under Scope: 172.16.0.0/12.
*: If you use VcXSrv you can enable public access for your X server by disabling Access Control on the Extra Settings:
Or by calling vcxsrv.exe
directly with the ac
flag: vcxsrv.exe -ac
as pointed out by ameeno on the github issue.
Alternatively this SO answer shows how to share keys via .Xauthority files, leaving you with intact access control.
Related Topics
How to Search Contents of Multiple PDF Files
How to Get Child Process from Parent Process
Joining Multiple Fields in Text Files on Unix
Linux Time Command Microseconds or Better Accuracy
Location of Ini/Config Files in Linux/Unix
Docker in Docker Cannot Mount Volume
What Is Path on a MAC (Unix) System
Find and Delete File or Folder Older Than X Days
Why Doesn't "Sort File1 > File1" Work
Command to Change the Default Home Directory of a User
How Is the Linux Kernel Tested
How to Monitor a Complete Directory Tree for Changes in Linux
Sorting on the Last Field of a Line
What's the Point of Eval/Bash -C as Opposed to Just Evaluating a Variable
Using 'Date' Command to Get Previous, Current and Next Month
Redirecting Stdout with Find -Exec and Without Creating New Shell