Is it possible for a c application using libwayland-client.so
to get the name of the compositor / display server it opened a connection to (e.g. KWin, Sway, …)? I fail to find it in the docs.
For reference, in X11 this is possible using XProps specified by EWMH: _NET_SUPPORTING_WM_CHECK
to get the window id of the window manager and then using _NET_WM_NAME
.
Im fine with anything giving me a way to identify it, for example a pretty name, the process name, the pid or similar.
Current solution is to detect which socket file wayland will be using (${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY:-wayland-0}
), detecting which process are listening on it and picking the one which is most probably the compositor (similar to what neofetch does in bash). But since i need to open a connection anyway, and this method is very bug prone, i think you can see why i want to have a cleaner solution.
Advertisement
Answer
Requirements:
- determine the PID of the peer compositor process for a display connection on the client side
- must run under Linux
- optionally determines the process name
Since this is not directly supported by the API, you can
- get the file descriptor of the display context (
wl_display_get_fd
) - use the file descriptor to read the associated PID of the peer process (
getsockopt
with theSO_PEERCRED
option, see e.g. this nice SO answer) - finally, you can get the process name by reading
/proc/<pid>/comm
.
You could also retrieve the process command line if you need more information.
However, the output of the following test program would look like this under Ubuntu 22.04 LTS
:
pid: 1733, process name: gnome-shell
Self-contained Example in C
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <wayland-client.h> #include <sys/socket.h> #include <errno.h> #define PROCESS_NAME_MAX_LENGTH 1024 static pid_t pid_from_fd(int fd) { struct ucred ucred; socklen_t len = sizeof(struct ucred); if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) { perror("getsockopt failed"); exit(-1); } return ucred.pid; } static char *process_name_from_pid(const pid_t pid) { char *name = malloc(PROCESS_NAME_MAX_LENGTH); if (!name) { perror("malloc failed"); exit(-1); } char proc_buf[64]; sprintf(proc_buf, "/proc/%d/comm", pid); FILE *fp; if ((fp = fopen(proc_buf, "r")) == NULL) { fprintf(stderr, "opening '%s' failed: %sn", proc_buf, strerror(errno)); exit(-1); } if (fgets(name, PROCESS_NAME_MAX_LENGTH, fp) == NULL) { fprintf(stderr, "reading '%s' failedn", proc_buf); exit(-1); } name[strcspn(name, "n")] = 0; fclose(fp); return name; } int main(void) { struct wl_display *display = wl_display_connect(NULL); if (display == NULL) { fprintf(stderr, "can't connect to displayn"); exit(-1); } int fd = wl_display_get_fd(display); pid_t pid = pid_from_fd(fd); char *process_name = process_name_from_pid(pid); printf("pid: %d, process name: %sn", pid, process_name); free(process_name); wl_display_disconnect(display); return 0; }