#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include "../../dialog/unix/SDL_zenitymessagebox.h"
#include "SDL_x11messagebox.h"
#include "SDL_x11toolkit.h"
#ifndef SDL_FORK_MESSAGEBOX
#define SDL_FORK_MESSAGEBOX 0
#endif
#if SDL_FORK_MESSAGEBOX
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#endif
typedef struct SDL_MessageBoxX11
{
SDL_ToolkitWindowX11 *window;
SDL_ToolkitControlX11 *icon;
SDL_ToolkitControlX11 *message;
SDL_ToolkitControlX11 **buttons;
const SDL_MessageBoxData *messageboxdata;
int *buttonID;
} SDL_MessageBoxX11;
static void X11_MessageBoxButtonCallback(SDL_ToolkitControlX11 *control, void *data)
{
SDL_MessageBoxX11 *cbdata;
cbdata = data;
*cbdata->buttonID = X11Toolkit_GetButtonControlData(control)->buttonID;
X11Toolkit_SignalWindowClose(cbdata->window);
}
static void X11_PositionMessageBox(SDL_MessageBoxX11 *controls, int *wp, int *hp) {
int first_line_width;
int first_line_height;
int second_line_width;
int second_line_height;
int max_button_width;
int max_button_height;
int window_width;
int window_height;
int i;
bool rtl;
window_width = 1;
window_height = 1;
if (controls->messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
rtl = true;
} else if (controls->messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT) {
rtl = false;
} else {
rtl = controls->window->flip_interface;
}
first_line_width = first_line_height = 0;
if (controls->icon && controls->message) {
controls->icon->rect.y = 0;
first_line_width = controls->icon->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale + controls->message->rect.w;
if (!controls->window->flip_interface) {
controls->message->rect.x = controls->icon->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
controls->icon->rect.x = 0;
} else {
controls->message->rect.x = 0;
controls->icon->rect.x = controls->message->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;;
}
if (controls->message->rect.h > controls->icon->rect.h) {
controls->message->rect.y = (controls->icon->rect.h - X11Toolkit_GetLabelControlFirstLineHeight(controls->message))/2;
first_line_height = controls->message->rect.y + controls->message->rect.h;
} else {
controls->message->rect.y = (controls->icon->rect.h - controls->message->rect.h)/2;
first_line_height = controls->icon->rect.h;
}
} else if (!controls->icon && controls->message) {
first_line_width = controls->message->rect.w;
first_line_height = controls->message->rect.h;
controls->message->rect.x = 0;
controls->message->rect.y = 0;
} else if (controls->icon && !controls->message) {
first_line_width = controls->icon->rect.w;
first_line_height = controls->icon->rect.h;
controls->icon->rect.x = 0;
controls->icon->rect.y = 0;
}
max_button_width = 50;
max_button_height = 0;
second_line_width = second_line_height = 0;
for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
max_button_width = SDL_max(max_button_width, controls->buttons[i]->rect.w);
max_button_height = SDL_max(max_button_height, controls->buttons[i]->rect.h);
controls->buttons[i]->rect.x = 0;
controls->buttons[i]->rect.y = 0;
}
if (rtl) {
for (i = (controls->messageboxdata->numbuttons - 1); i != -1; i--) {
controls->buttons[i]->rect.w = max_button_width;
controls->buttons[i]->rect.h = max_button_height;
X11Toolkit_NotifyControlOfSizeChange(controls->buttons[i]);
if (first_line_height) {
controls->buttons[i]->rect.y = first_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale;
second_line_height = max_button_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale;
} else {
second_line_height = max_button_height;
}
if ((i + 1) < controls->messageboxdata->numbuttons) {
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);
}
}
} else {
for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
controls->buttons[i]->rect.w = max_button_width;
controls->buttons[i]->rect.h = max_button_height;
X11Toolkit_NotifyControlOfSizeChange(controls->buttons[i]);
if (first_line_height) {
controls->buttons[i]->rect.y = first_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale;
second_line_height = max_button_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale;
} else {
second_line_height = max_button_height;
}
if (i) {
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);
}
}
}
if (controls->messageboxdata->numbuttons) {
if (rtl) {
second_line_width = controls->buttons[0]->rect.x + controls->buttons[0]->rect.w;
} else {
second_line_width = controls->buttons[controls->messageboxdata->numbuttons - 1]->rect.x + controls->buttons[controls->messageboxdata->numbuttons - 1]->rect.w;
}
}
if (second_line_width > first_line_width) {
int pad;
pad = (second_line_width - first_line_width)/2;
if (controls->message) {
controls->message->rect.x += pad;
}
if (controls->icon) {
controls->icon->rect.x += pad;
}
} else {
int pad;
pad = (first_line_width - second_line_width)/2;
for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
controls->buttons[i]->rect.x += pad;
}
}
window_width = SDL_max(first_line_width, second_line_width) + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * 2 * controls->window->iscale;
window_height = first_line_height + second_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * 2 * controls->window->iscale;
*wp = window_width;
*hp = window_height;
if (controls->message) {
controls->message->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
controls->message->rect.y += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
}
if (controls->icon) {
controls->icon->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
controls->icon->rect.y += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
}
for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
controls->buttons[i]->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
controls->buttons[i]->rect.y += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
}
}
static void X11_OnMessageBoxScaleChange(SDL_ToolkitWindowX11 *window, void *data) {
SDL_MessageBoxX11 *controls;
int w;
int h;
controls = data;
X11_PositionMessageBox(controls, &w, &h);
X11Toolkit_ResizeWindow(window, w, h);
}
static bool X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonID)
{
SDL_VideoDevice *video = SDL_GetVideoDevice();
SDL_Window *parent_window = NULL;
SDL_MessageBoxX11 controls;
const SDL_MessageBoxColor *colorhints;
int i;
int w;
int h;
controls.messageboxdata = messageboxdata;
if (messageboxdata->colorScheme) {
colorhints = messageboxdata->colorScheme->colors;
} else {
colorhints = NULL;
}
if (messageboxdata->window && video && SDL_strcmp(video->name, "x11") == 0) {
parent_window = messageboxdata->window;
}
#if SDL_FORK_MESSAGEBOX
controls.window = X11Toolkit_CreateWindowStruct(parent_window, NULL, SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG, colorhints, true);
#else
controls.window = X11Toolkit_CreateWindowStruct(parent_window, NULL, SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG, colorhints, false);
#endif
controls.window->cb_data = &controls;
controls.window->cb_on_scale_change = X11_OnMessageBoxScaleChange;
if (!controls.window) {
return false;
}
controls.buttonID = buttonID;
controls.buttons = SDL_calloc(messageboxdata->numbuttons, sizeof(SDL_ToolkitControlX11 *));
controls.icon = X11Toolkit_CreateIconControl(controls.window, messageboxdata->flags);
controls.message = X11Toolkit_CreateLabelControl(controls.window, (char *)messageboxdata->message);
for (i = 0; i < messageboxdata->numbuttons; i++) {
controls.buttons[i] = X11Toolkit_CreateButtonControl(controls.window, &messageboxdata->buttons[i]);
X11Toolkit_RegisterCallbackForButtonControl(controls.buttons[i], &controls, X11_MessageBoxButtonCallback);
}
X11_PositionMessageBox(&controls, &w, &h);
X11Toolkit_CreateWindowRes(controls.window, w, h, 0, 0, (char *)messageboxdata->title);
X11Toolkit_DoWindowEventLoop(controls.window);
X11Toolkit_DestroyWindow(controls.window);
SDL_free(controls.buttons);
return true;
}
bool X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
{
if (SDL_Zenity_ShowMessageBox(messageboxdata, buttonID)) {
return true;
}
#if SDL_FORK_MESSAGEBOX
pid_t pid;
int fds[2];
int status = 0;
bool result = true;
if (pipe(fds) == -1) {
return X11_ShowMessageBoxImpl(messageboxdata, buttonID); }
pid = fork();
if (pid == -1) { close(fds[0]);
close(fds[1]);
return X11_ShowMessageBoxImpl(messageboxdata, buttonID); } else if (pid == 0) { int exitcode = 0;
close(fds[0]);
result = X11_ShowMessageBoxImpl(messageboxdata, buttonID);
if (write(fds[1], &result, sizeof(result)) != sizeof(result)) {
exitcode = 1;
} else if (write(fds[1], buttonID, sizeof(*buttonID)) != sizeof(*buttonID)) {
exitcode = 1;
}
close(fds[1]);
_exit(exitcode); } else { pid_t rc;
close(fds[1]);
do {
rc = waitpid(pid, &status, 0);
} while ((rc == -1) && (errno == EINTR));
SDL_assert(rc == pid);
if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
result = SDL_SetError("msgbox child process failed");
} else if ((read(fds[0], &result, sizeof(result)) != sizeof(result)) ||
(read(fds[0], buttonID, sizeof(*buttonID)) != sizeof(*buttonID))) {
result = SDL_SetError("read from msgbox child process failed");
*buttonID = 0;
}
close(fds[0]);
return result;
}
#else
return X11_ShowMessageBoxImpl(messageboxdata, buttonID);
#endif
}
#endif