Commit 736a624df0e4f2043d45915d3870de90b1b36115

Bastien Nocera 2016-09-01T01:22:58

Wayland: Set "class" for each window we create This will be used by Wayland compositors to match the application ID and .desktop file to the SDL window(s). Applications can set the SDL_VIDEO_WAYLAND_WMCLASS environemnt variable early in the process to override using the binary name as a fallback. Note that we also support the SDL_VIDEO_X11_WMCLASS in the Wayland backend so that if a program correctly associated the desktop file with the window under X11, only a newer SDL would be needed for it to work under Wayland. https://bugzilla.libsdl.org/show_bug.cgi?id=3376

diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index a377a8d..fbd4f8e 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -35,6 +35,8 @@
 #include "SDL_waylandmouse.h"
 #include "SDL_waylandtouch.h"
 
+#include <sys/types.h>
+#include <unistd.h>
 #include <fcntl.h>
 #include <xkbcommon/xkbcommon.h>
 
@@ -55,6 +57,56 @@ Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
 static void
 Wayland_VideoQuit(_THIS);
 
+/* Find out what class name we should use
+ * Based on src/video/x11/SDL_x11video.c */
+static char *
+get_classname()
+{
+    char *spot;
+#if defined(__LINUX__) || defined(__FREEBSD__)
+    char procfile[1024];
+    char linkfile[1024];
+    int linksize;
+#endif
+
+    /* First allow environment variable override */
+    spot = SDL_getenv("SDL_VIDEO_WAYLAND_WMCLASS");
+    if (spot) {
+        return SDL_strdup(spot);
+    } else {
+        /* Fallback to the "old" envvar */
+        spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
+        if (spot) {
+            return SDL_strdup(spot);
+        }
+    }
+
+    /* Next look at the application's executable name */
+#if defined(__LINUX__) || defined(__FREEBSD__)
+#if defined(__LINUX__)
+    SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
+#elif defined(__FREEBSD__)
+    SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
+                 getpid());
+#else
+#error Where can we find the executable name?
+#endif
+    linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
+    if (linksize > 0) {
+        linkfile[linksize] = '\0';
+        spot = SDL_strrchr(linkfile, '/');
+        if (spot) {
+            return SDL_strdup(spot + 1);
+        } else {
+            return SDL_strdup(linkfile);
+        }
+    }
+#endif /* __LINUX__ || __FREEBSD__ */
+
+    /* Finally use the default we've used forever */
+    return SDL_strdup("SDL_App");
+}
+
 /* Wayland driver bootstrap functions */
 static int
 Wayland_Available(void)
@@ -307,6 +359,9 @@ Wayland_VideoInit(_THIS)
 
     Wayland_InitMouse();
 
+    /* Get the surface class name, usually the name of the application */
+    data->classname = get_classname();
+
     WAYLAND_wl_display_flush(data->display);
 
     return 0;
@@ -375,6 +430,7 @@ Wayland_VideoQuit(_THIS)
         WAYLAND_wl_display_disconnect(data->display);
     }
 
+    SDL_free(data->classname);
     free(data);
     _this->driverdata = NULL;
 }
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index 8744d36..cf4b5db 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -57,6 +57,8 @@ typedef struct {
     struct qt_surface_extension *surface_extension;
     struct qt_windowmanager *windowmanager;
 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
+
+    char *classname;
 } SDL_VideoData;
 
 #endif /* _SDL_waylandvideo_h */
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index b59759a..82b4062 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -178,6 +178,7 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
     wl_surface_set_user_data(data->surface, data);
     data->shell_surface = wl_shell_get_shell_surface(c->shell,
                                                      data->surface);
+    wl_shell_surface_set_class (data->shell_surface, c->classname);
 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH    
     if (c->surface_extension) {
         data->extended_surface = qt_surface_extension_get_extended_surface(