Atlas - SDL_zenitymessagebox.c
Home / ext / SDL / src / dialog / unix Lines: 2 | Size: 6602 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22#include "SDL_internal.h" 23 24#include "SDL_zenitymessagebox.h" 25 26#define ZENITY_VERSION_LEN 32 // Number of bytes to read from zenity --version (including NUL) 27 28#define MAX_BUTTONS 8 // Maximum number of buttons supported 29 30static bool parse_zenity_version(const char *version, int *major, int *minor) 31{ 32 /* We expect the version string is in the form of MAJOR.MINOR.MICRO 33 * as described in meson.build. We'll ignore everything after that. 34 */ 35 const char *version_ptr = version; 36 char *end_ptr = NULL; 37 int tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10); 38 if (tmp == 0 && end_ptr == version_ptr) { 39 return SDL_SetError("failed to get zenity major version number"); 40 } 41 *major = tmp; 42 43 if (*end_ptr == '.') { 44 version_ptr = end_ptr + 1; // skip the dot 45 tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10); 46 if (tmp == 0 && end_ptr == version_ptr) { 47 return SDL_SetError("failed to get zenity minor version number"); 48 } 49 *minor = tmp; 50 } else { 51 *minor = 0; 52 } 53 return true; 54} 55 56bool SDL_get_zenity_version(int *major, int *minor) 57{ 58 const char *argv[] = { "zenity", "--version", NULL }; 59 bool result = false; 60 61 SDL_Process *process = SDL_CreateProcess(argv, true); 62 if (!process) { 63 return false; 64 } 65 66 char *output = SDL_ReadProcess(process, NULL, NULL); 67 if (output) { 68 result = parse_zenity_version(output, major, minor); 69 SDL_free(output); 70 } 71 SDL_DestroyProcess(process); 72 73 return result; 74} 75 76bool SDL_Zenity_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID) 77{ 78 int exit_code = -1; 79 int zenity_major = 0, zenity_minor = 0, output_len = 0; 80 int argc = 5, i; 81 const char *argv[5 + 2 /* icon name */ + 2 /* title */ + 2 /* message */ + 2 * MAX_BUTTONS + 1 /* NULL */] = { 82 "zenity", "--question", "--switch", "--no-wrap", "--no-markup" 83 }; 84 SDL_Process *process; 85 86 if (messageboxdata->numbuttons > MAX_BUTTONS) { 87 return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS); 88 } 89 90 // get zenity version so we know which arg to use 91 if (!SDL_get_zenity_version(&zenity_major, &zenity_minor)) { 92 return false; // get_zenity_version() calls SDL_SetError(), so message is already set 93 } 94 95 /* https://gitlab.gnome.org/GNOME/zenity/-/commit/c686bdb1b45e95acf010efd9ca0c75527fbb4dea 96 * This commit removed --icon-name without adding a deprecation notice. 97 * We need to handle it gracefully, otherwise no message box will be shown. 98 */ 99 argv[argc++] = zenity_major > 3 || (zenity_major == 3 && zenity_minor >= 90) ? "--icon" : "--icon-name"; 100 switch (messageboxdata->flags & (SDL_MESSAGEBOX_ERROR | SDL_MESSAGEBOX_WARNING | SDL_MESSAGEBOX_INFORMATION)) { 101 case SDL_MESSAGEBOX_ERROR: 102 argv[argc++] = "dialog-error"; 103 break; 104 case SDL_MESSAGEBOX_WARNING: 105 argv[argc++] = "dialog-warning"; 106 break; 107 case SDL_MESSAGEBOX_INFORMATION: 108 default: 109 argv[argc++] = "dialog-information"; 110 break; 111 } 112 113 if (messageboxdata->title && messageboxdata->title[0]) { 114 argv[argc++] = "--title"; 115 argv[argc++] = messageboxdata->title; 116 } else { 117 argv[argc++] = "--title="; 118 } 119 120 if (messageboxdata->message && messageboxdata->message[0]) { 121 argv[argc++] = "--text"; 122 argv[argc++] = messageboxdata->message; 123 } else { 124 argv[argc++] = "--text="; 125 } 126 127 for (i = 0; i < messageboxdata->numbuttons; ++i) { 128 if (messageboxdata->buttons[i].text && messageboxdata->buttons[i].text[0]) { 129 int len = SDL_strlen(messageboxdata->buttons[i].text); 130 if (len > output_len) { 131 output_len = len; 132 } 133 134 argv[argc++] = "--extra-button"; 135 argv[argc++] = messageboxdata->buttons[i].text; 136 } else { 137 argv[argc++] = "--extra-button="; 138 } 139 } 140 if (messageboxdata->numbuttons == 0) { 141 argv[argc++] = "--extra-button=OK"; 142 } 143 argv[argc] = NULL; 144 145 SDL_PropertiesID props = SDL_CreateProperties(); 146 if (!props) { 147 return false; 148 } 149 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, argv); 150 // If buttonID is set we need to wait and read the results 151 if (buttonID) { 152 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 153 } else { 154 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_NULL); 155 } 156 process = SDL_CreateProcessWithProperties(props); 157 SDL_DestroyProperties(props); 158 if (!process) { 159 return false; 160 } 161 if (buttonID) { 162 char *output = SDL_ReadProcess(process, NULL, &exit_code); 163 if (exit_code < 0 || exit_code == 255) { 164 SDL_free(output); 165 } else if (output) { 166 // It likes to add a newline... 167 char *tmp = SDL_strrchr(output, '\n'); 168 if (tmp) { 169 *tmp = '\0'; 170 } 171 172 // Check which button got pressed 173 for (i = 0; i < messageboxdata->numbuttons; i += 1) { 174 if (messageboxdata->buttons[i].text) { 175 if (SDL_strcmp(output, messageboxdata->buttons[i].text) == 0) { 176 *buttonID = messageboxdata->buttons[i].buttonID; 177 break; 178 } 179 } 180 } 181 SDL_free(output); 182 } 183 } else { 184 SDL_WaitProcess(process, true, &exit_code); 185 } 186 SDL_DestroyProcess(process); 187 188 return !(exit_code < 0 || exit_code == 255); 189} 190[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.