diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 62da1020facc5..e15afb9561747 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -4042,6 +4042,9 @@ SDL_IsScreenKeyboardShown(SDL_Window *window) #if SDL_VIDEO_DRIVER_X11 #include "x11/SDL_x11messagebox.h" #endif +#if SDL_VIDEO_DRIVER_WAYLAND +#include "wayland/SDL_waylandmessagebox.h" +#endif #if SDL_VIDEO_DRIVER_HAIKU #include "haiku/SDL_bmessagebox.h" #endif @@ -4052,7 +4055,7 @@ SDL_IsScreenKeyboardShown(SDL_Window *window) #include "vita/SDL_vitamessagebox.h" #endif -#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11 || SDL_VIDEO_DRIVER_HAIKU || SDL_VIDEO_DRIVER_OS2 +#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11 || SDL_VIDEO_DRIVER_WAYLAND || SDL_VIDEO_DRIVER_HAIKU || SDL_VIDEO_DRIVER_OS2 static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype) { SDL_SysWMinfo info; @@ -4151,6 +4154,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) retval = 0; } #endif +#if SDL_VIDEO_DRIVER_WAYLAND + if (retval == -1 && + SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WAYLAND) && + Wayland_ShowMessageBox(messageboxdata, buttonid) == 0) { + retval = 0; + } +#endif #if SDL_VIDEO_DRIVER_HAIKU if (retval == -1 && SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_HAIKU) && diff --git a/src/video/wayland/SDL_waylandmessagebox.c b/src/video/wayland/SDL_waylandmessagebox.c new file mode 100644 index 0000000000000..0d99457708ba9 --- /dev/null +++ b/src/video/wayland/SDL_waylandmessagebox.c @@ -0,0 +1,159 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2021 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_WAYLAND + +#include "SDL.h" +#include /* popen/pclose/fgets */ + +int +Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ + #define ZENITY_CONST(name, str) \ + const char *name = str; \ + const size_t name##_len = SDL_strlen(name); + ZENITY_CONST(zenity, "zenity --question --switch --icon-name=dialog-") + ZENITY_CONST(title, "--title=") + ZENITY_CONST(message, "--text=") + ZENITY_CONST(extrabutton, "--extra-button=") + ZENITY_CONST(icon_info, "information") + ZENITY_CONST(icon_warn, "warning") + ZENITY_CONST(icon_error, "error") + #undef ZENITY_CONST + + char *command, *output; + size_t command_len, output_len; + const char *icon; + char *tmp; + FILE *process; + int i; + + /* Start by calculating the lengths of the strings. These commands can get + * pretty long, so we need to dynamically allocate this. + */ + command_len = zenity_len; + output_len = 0; + switch (messageboxdata->flags) + { + case SDL_MESSAGEBOX_ERROR: + icon = icon_error; + command_len += icon_error_len; + break; + case SDL_MESSAGEBOX_WARNING: + icon = icon_warn; + command_len += icon_warn_len; + break; + case SDL_MESSAGEBOX_INFORMATION: + default: + icon = icon_info; + command_len += icon_info_len; + break; + } + #define ADD_ARGUMENT(arg, value) \ + command_len += arg + 3; /* Two " and a space */ \ + if (messageboxdata->value != NULL) { \ + command_len += SDL_strlen(messageboxdata->value); \ + } + ADD_ARGUMENT(title_len, title) + ADD_ARGUMENT(message_len, message) + for (i = 0; i < messageboxdata->numbuttons; i += 1) { + ADD_ARGUMENT(extrabutton_len, buttons[i].text) + } + #undef ADD_ARGUMENT + + /* Don't forget null terminators! */ + command_len += 1; + output_len += 1; + + /* Now that we know the length of the command, allocate! */ + command = (char*) SDL_malloc(command_len + output_len); + if (command == NULL) { + return SDL_OutOfMemory(); + } + output = command + command_len; + command[0] = '\0'; + output[0] = '\0'; + + /* Now we can build the command... */ + SDL_strlcpy(command, zenity, command_len); + SDL_strlcat(command, icon, command_len); + #define ADD_ARGUMENT(arg, value) \ + SDL_strlcat(command, " ", command_len); \ + SDL_strlcat(command, arg, command_len); \ + SDL_strlcat(command, "\"", command_len); \ + if (value != NULL) { \ + SDL_strlcat(command, value, command_len); \ + } \ + SDL_strlcat(command, "\"", command_len) + ADD_ARGUMENT(title, messageboxdata->title); + ADD_ARGUMENT(message, messageboxdata->message); + for (i = 0; i < messageboxdata->numbuttons; i += 1) { + ADD_ARGUMENT(extrabutton, messageboxdata->buttons[i].text); + } + #undef ADD_ARGUMENT + + /* ... then run it, finally. */ + process = popen(command, "r"); + if (process == NULL) { + SDL_free(command); + return SDL_SetError("zenity failed to run"); + } + + /* At this point, if no button ID is needed, we can just bail as soon as the + * process has completed. + */ + if (buttonid == NULL) { + pclose(process); + goto end; + } + *buttonid = -1; + + /* Read the result from stdout */ + tmp = fgets(output, output_len, process); + pclose(process); + if ((tmp == NULL) || (*tmp == '\0') || (*tmp == '\n')) { + goto end; /* User simply closed the dialog */ + } + + /* It likes to add a newline... */ + tmp = SDL_strrchr(output, '\n'); + if (tmp != NULL) { + *tmp = '\0'; + } + + /* Check which button got pressed */ + for (i = 0; i < messageboxdata->numbuttons; i += 1) { + if (SDL_strcmp(output, messageboxdata->buttons[i].text) == 0) { + *buttonid = i; + break; + } + } + +end: + SDL_free(command); + return 0; +} + +#endif /* SDL_VIDEO_DRIVER_WAYLAND */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/wayland/SDL_waylandmessagebox.h b/src/video/wayland/SDL_waylandmessagebox.h new file mode 100644 index 0000000000000..08440d28d5515 --- /dev/null +++ b/src/video/wayland/SDL_waylandmessagebox.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2021 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_waylandmessagebox_h_ +#define SDL_waylandmessagebox_h_ + +#if SDL_VIDEO_DRIVER_WAYLAND + +extern int Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid); + +#endif /* SDL_VIDEO_DRIVER_WAYLAND */ + +#endif /* SDL_waylandmessagebox_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */