Atlas - SDL_x11messagebox.c

Home / ext / SDL / src / video / x11 Lines: 1 | Size: 13032 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#ifdef SDL_VIDEO_DRIVER_X11 25 26#include "../../dialog/unix/SDL_zenitymessagebox.h" 27#include "SDL_x11messagebox.h" 28#include "SDL_x11toolkit.h" 29 30#ifndef SDL_FORK_MESSAGEBOX 31#define SDL_FORK_MESSAGEBOX 0 32#endif 33 34#if SDL_FORK_MESSAGEBOX 35#include <sys/types.h> 36#include <sys/wait.h> 37#include <unistd.h> 38#include <errno.h> 39#endif 40 41typedef struct SDL_MessageBoxX11 42{ 43 SDL_ToolkitWindowX11 *window; 44 SDL_ToolkitControlX11 *icon; 45 SDL_ToolkitControlX11 *message; 46 SDL_ToolkitControlX11 **buttons; 47 const SDL_MessageBoxData *messageboxdata; 48 int *buttonID; 49} SDL_MessageBoxX11; 50 51static void X11_MessageBoxButtonCallback(SDL_ToolkitControlX11 *control, void *data) 52{ 53 SDL_MessageBoxX11 *cbdata; 54 55 cbdata = data; 56 *cbdata->buttonID = X11Toolkit_GetButtonControlData(control)->buttonID; 57 X11Toolkit_SignalWindowClose(cbdata->window); 58} 59 60static void X11_PositionMessageBox(SDL_MessageBoxX11 *controls, int *wp, int *hp) { 61 int first_line_width; 62 int first_line_height; 63 int second_line_width; 64 int second_line_height; 65 int max_button_width; 66 int max_button_height; 67 int window_width; 68 int window_height; 69 int i; 70 bool rtl; 71 72 /* window size */ 73 window_width = 1; 74 window_height = 1; 75 76 /* rtl */ 77 if (controls->messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) { 78 rtl = true; 79 } else if (controls->messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT) { 80 rtl = false; 81 } else { 82 rtl = controls->window->flip_interface; 83 } 84 85 /* first line */ 86 first_line_width = first_line_height = 0; 87 if (controls->icon && controls->message) { 88 controls->icon->rect.y = 0; 89 90 first_line_width = controls->icon->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale + controls->message->rect.w; 91 92 if (!controls->window->flip_interface) { 93 controls->message->rect.x = controls->icon->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale; 94 controls->icon->rect.x = 0; 95 } else { 96 controls->message->rect.x = 0; 97 controls->icon->rect.x = controls->message->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;; 98 } 99 100 if (controls->message->rect.h > controls->icon->rect.h) { 101 controls->message->rect.y = (controls->icon->rect.h - X11Toolkit_GetLabelControlFirstLineHeight(controls->message))/2; 102 first_line_height = controls->message->rect.y + controls->message->rect.h; 103 } else { 104 controls->message->rect.y = (controls->icon->rect.h - controls->message->rect.h)/2; 105 first_line_height = controls->icon->rect.h; 106 } 107 } else if (!controls->icon && controls->message) { 108 first_line_width = controls->message->rect.w; 109 first_line_height = controls->message->rect.h; 110 controls->message->rect.x = 0; 111 controls->message->rect.y = 0; 112 } else if (controls->icon && !controls->message) { 113 first_line_width = controls->icon->rect.w; 114 first_line_height = controls->icon->rect.h; 115 controls->icon->rect.x = 0; 116 controls->icon->rect.y = 0; 117 } 118 119 /* second line */ 120 max_button_width = 50; 121 max_button_height = 0; 122 second_line_width = second_line_height = 0; 123 124 for (i = 0; i < controls->messageboxdata->numbuttons; i++) { 125 max_button_width = SDL_max(max_button_width, controls->buttons[i]->rect.w); 126 max_button_height = SDL_max(max_button_height, controls->buttons[i]->rect.h); 127 controls->buttons[i]->rect.x = 0; 128 controls->buttons[i]->rect.y = 0; 129 } 130 131 if (rtl) { 132 for (i = (controls->messageboxdata->numbuttons - 1); i != -1; i--) { 133 controls->buttons[i]->rect.w = max_button_width; 134 controls->buttons[i]->rect.h = max_button_height; 135 X11Toolkit_NotifyControlOfSizeChange(controls->buttons[i]); 136 137 if (first_line_height) { 138 controls->buttons[i]->rect.y = first_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale; 139 second_line_height = max_button_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale; 140 } else { 141 second_line_height = max_button_height; 142 } 143 144 if ((i + 1) < controls->messageboxdata->numbuttons) { 145 controls->buttons[i]->rect.x = controls->buttons[i + 1]->rect.x + controls->buttons[i + 1]->rect.w + (SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * controls->window->iscale); 146 } 147 } 148 } else { 149 for (i = 0; i < controls->messageboxdata->numbuttons; i++) { 150 controls->buttons[i]->rect.w = max_button_width; 151 controls->buttons[i]->rect.h = max_button_height; 152 X11Toolkit_NotifyControlOfSizeChange(controls->buttons[i]); 153 154 if (first_line_height) { 155 controls->buttons[i]->rect.y = first_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale; 156 second_line_height = max_button_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale; 157 } else { 158 second_line_height = max_button_height; 159 } 160 161 if (i) { 162 controls->buttons[i]->rect.x = controls->buttons[i-1]->rect.x + controls->buttons[i-1]->rect.w + (SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * controls->window->iscale); 163 } 164 } 165 } 166 167 if (controls->messageboxdata->numbuttons) { 168 if (rtl) { 169 second_line_width = controls->buttons[0]->rect.x + controls->buttons[0]->rect.w; 170 } else { 171 second_line_width = controls->buttons[controls->messageboxdata->numbuttons - 1]->rect.x + controls->buttons[controls->messageboxdata->numbuttons - 1]->rect.w; 172 } 173 } 174 175 /* center lines */ 176 if (second_line_width > first_line_width) { 177 int pad; 178 179 pad = (second_line_width - first_line_width)/2; 180 if (controls->message) { 181 controls->message->rect.x += pad; 182 } 183 if (controls->icon) { 184 controls->icon->rect.x += pad; 185 } 186 } else { 187 int pad; 188 189 pad = (first_line_width - second_line_width)/2; 190 for (i = 0; i < controls->messageboxdata->numbuttons; i++) { 191 controls->buttons[i]->rect.x += pad; 192 } 193 } 194 195 /* window size and final padding */ 196 window_width = SDL_max(first_line_width, second_line_width) + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * 2 * controls->window->iscale; 197 window_height = first_line_height + second_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * 2 * controls->window->iscale; 198 *wp = window_width; 199 *hp = window_height; 200 if (controls->message) { 201 controls->message->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale; 202 controls->message->rect.y += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale; 203 } 204 if (controls->icon) { 205 controls->icon->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale; 206 controls->icon->rect.y += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale; 207 } 208 for (i = 0; i < controls->messageboxdata->numbuttons; i++) { 209 controls->buttons[i]->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale; 210 controls->buttons[i]->rect.y += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale; 211 } 212} 213 214static void X11_OnMessageBoxScaleChange(SDL_ToolkitWindowX11 *window, void *data) { 215 SDL_MessageBoxX11 *controls; 216 int w; 217 int h; 218 219 controls = data; 220 X11_PositionMessageBox(controls, &w, &h); 221 X11Toolkit_ResizeWindow(window, w, h); 222} 223 224static bool X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonID) 225{ 226 SDL_VideoDevice *video = SDL_GetVideoDevice(); 227 SDL_Window *parent_window = NULL; 228 SDL_MessageBoxX11 controls; 229 const SDL_MessageBoxColor *colorhints; 230 int i; 231 int w; 232 int h; 233 234 controls.messageboxdata = messageboxdata; 235 236 /* Color scheme */ 237 if (messageboxdata->colorScheme) { 238 colorhints = messageboxdata->colorScheme->colors; 239 } else { 240 colorhints = NULL; 241 } 242 243 /* Create window */ 244 if (messageboxdata->window && video && SDL_strcmp(video->name, "x11") == 0) { 245 // Only use the window as a parent if it is from the X11 driver. 246 parent_window = messageboxdata->window; 247 } 248#if SDL_FORK_MESSAGEBOX 249 controls.window = X11Toolkit_CreateWindowStruct(parent_window, NULL, SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG, colorhints, true); 250#else 251 controls.window = X11Toolkit_CreateWindowStruct(parent_window, NULL, SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG, colorhints, false); 252#endif 253 controls.window->cb_data = &controls; 254 controls.window->cb_on_scale_change = X11_OnMessageBoxScaleChange; 255 if (!controls.window) { 256 return false; 257 } 258 259 /* Create controls */ 260 controls.buttonID = buttonID; 261 controls.buttons = SDL_calloc(messageboxdata->numbuttons, sizeof(SDL_ToolkitControlX11 *)); 262 controls.icon = X11Toolkit_CreateIconControl(controls.window, messageboxdata->flags); 263 controls.message = X11Toolkit_CreateLabelControl(controls.window, (char *)messageboxdata->message); 264 for (i = 0; i < messageboxdata->numbuttons; i++) { 265 controls.buttons[i] = X11Toolkit_CreateButtonControl(controls.window, &messageboxdata->buttons[i]); 266 X11Toolkit_RegisterCallbackForButtonControl(controls.buttons[i], &controls, X11_MessageBoxButtonCallback); 267 } 268 269 /* Positioning */ 270 X11_PositionMessageBox(&controls, &w, &h); 271 272 /* Actually create window, do event loop, cleanup */ 273 X11Toolkit_CreateWindowRes(controls.window, w, h, 0, 0, (char *)messageboxdata->title); 274 X11Toolkit_DoWindowEventLoop(controls.window); 275 X11Toolkit_DestroyWindow(controls.window); 276 SDL_free(controls.buttons); 277 return true; 278} 279 280// Display an x11 message box. 281bool X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID) 282{ 283 if (SDL_Zenity_ShowMessageBox(messageboxdata, buttonID)) { 284 return true; 285 } 286 287#if SDL_FORK_MESSAGEBOX 288 // Use a child process to protect against setlocale(). Annoying. 289 pid_t pid; 290 int fds[2]; 291 int status = 0; 292 bool result = true; 293 294 if (pipe(fds) == -1) { 295 return X11_ShowMessageBoxImpl(messageboxdata, buttonID); // oh well. 296 } 297 298 pid = fork(); 299 if (pid == -1) { // failed 300 close(fds[0]); 301 close(fds[1]); 302 return X11_ShowMessageBoxImpl(messageboxdata, buttonID); // oh well. 303 } else if (pid == 0) { // we're the child 304 int exitcode = 0; 305 close(fds[0]); 306 result = X11_ShowMessageBoxImpl(messageboxdata, buttonID); 307 if (write(fds[1], &result, sizeof(result)) != sizeof(result)) { 308 exitcode = 1; 309 } else if (write(fds[1], buttonID, sizeof(*buttonID)) != sizeof(*buttonID)) { 310 exitcode = 1; 311 } 312 close(fds[1]); 313 _exit(exitcode); // don't run atexit() stuff, static destructors, etc. 314 } else { // we're the parent 315 pid_t rc; 316 close(fds[1]); 317 do { 318 rc = waitpid(pid, &status, 0); 319 } while ((rc == -1) && (errno == EINTR)); 320 321 SDL_assert(rc == pid); // not sure what to do if this fails. 322 323 if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) { 324 result = SDL_SetError("msgbox child process failed"); 325 } else if ((read(fds[0], &result, sizeof(result)) != sizeof(result)) || 326 (read(fds[0], buttonID, sizeof(*buttonID)) != sizeof(*buttonID))) { 327 result = SDL_SetError("read from msgbox child process failed"); 328 *buttonID = 0; 329 } 330 close(fds[0]); 331 332 return result; 333 } 334#else 335 return X11_ShowMessageBoxImpl(messageboxdata, buttonID); 336#endif 337} 338#endif // SDL_VIDEO_DRIVER_X11 339
[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.