SDL: Implement SDL_SetWindowAlwaysOnTop for X11

From 0838f53d5a651fa14b5caccbae78f5c393299406 Mon Sep 17 00:00:00 2001
From: Cacodemon345 <[EMAIL REDACTED]>
Date: Wed, 21 Apr 2021 11:41:08 +0600
Subject: [PATCH] Implement SDL_SetWindowAlwaysOnTop for X11

---
 src/video/x11/SDL_x11video.c  |  1 +
 src/video/x11/SDL_x11window.c | 30 ++++++++++++++++++++++++++++++
 src/video/x11/SDL_x11window.h |  1 +
 3 files changed, 32 insertions(+)

diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
index 3d601231b..fa543adef 100644
--- a/src/video/x11/SDL_x11video.c
+++ b/src/video/x11/SDL_x11video.c
@@ -222,6 +222,7 @@ X11_CreateDevice(int devindex)
     device->RestoreWindow = X11_RestoreWindow;
     device->SetWindowBordered = X11_SetWindowBordered;
     device->SetWindowResizable = X11_SetWindowResizable;
+    device->SetWindowAlwaysOnTop = X11_SetWindowAlwaysOnTop;
     device->SetWindowFullscreen = X11_SetWindowFullscreen;
     device->SetWindowGammaRamp = X11_SetWindowGammaRamp;
     device->SetWindowMouseGrab = X11_SetWindowMouseGrab;
diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c
index 71e51076b..41d0de567 100644
--- a/src/video/x11/SDL_x11window.c
+++ b/src/video/x11/SDL_x11window.c
@@ -1109,6 +1109,36 @@ X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
     X11_XFlush(display);
 }
 
+void
+X11_SetWindowAlwaysOnTop(_THIS, SDL_Window * window, SDL_bool on_top)
+{
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+    SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
+    Display *display = data->videodata->display;
+    Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
+    Atom _NET_WM_STATE_ABOVE = data->videodata->_NET_WM_STATE_ABOVE;
+
+    if (X11_IsWindowMapped(_this, window)) {
+        XEvent e;
+
+        SDL_zero(e);
+        e.xany.type = ClientMessage;
+        e.xclient.message_type = _NET_WM_STATE;
+        e.xclient.format = 32;
+        e.xclient.window = data->xwindow;
+        e.xclient.data.l[0] =
+            on_top ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+        e.xclient.data.l[1] = _NET_WM_STATE_ABOVE;
+        e.xclient.data.l[3] = 0l;
+
+        X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
+                   SubstructureNotifyMask | SubstructureRedirectMask, &e);
+    } else {
+        X11_SetNetWMState(_this, data->xwindow, window->flags);
+    }
+    X11_XFlush(display);
+}
+
 void
 X11_ShowWindow(_THIS, SDL_Window * window)
 {
diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h
index 88ffc8180..98c150088 100644
--- a/src/video/x11/SDL_x11window.h
+++ b/src/video/x11/SDL_x11window.h
@@ -97,6 +97,7 @@ extern void X11_MinimizeWindow(_THIS, SDL_Window * window);
 extern void X11_RestoreWindow(_THIS, SDL_Window * window);
 extern void X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered);
 extern void X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable);
+extern void X11_SetWindowAlwaysOnTop(_THIS, SDL_Window * window, SDL_bool on_top);
 extern void X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
 extern int X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
 extern void X11_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed);