mirror of
https://github.com/Ryujinx/SDL.git
synced 2025-03-23 21:55:12 +00:00
video(wayland): use both --icon and --icon-name for Zenity (#7897)
video(wayland): use both --icon and --icon-name for Zenity Many distros ship an older version of Zenity that supports GTK3, while some distros ship newer version of Zenity which uses libadwaita. This command tries to use --icon and fall back to --icon-name when it fails.
This commit is contained in:
parent
042243471f
commit
b90343e512
|
@ -33,162 +33,220 @@
|
||||||
|
|
||||||
#include "SDL_waylandmessagebox.h"
|
#include "SDL_waylandmessagebox.h"
|
||||||
|
|
||||||
|
#define ZENITY_VERSION_LEN 32 /* Number of bytes to read from zenity --version (including NUL)*/
|
||||||
|
|
||||||
#define MAX_BUTTONS 8 /* Maximum number of buttons supported */
|
#define MAX_BUTTONS 8 /* Maximum number of buttons supported */
|
||||||
|
|
||||||
int Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
static int run_zenity(const char **args, int fd_pipe[2]) {
|
||||||
{
|
int status;
|
||||||
int fd_pipe[2]; /* fd_pipe[0]: read end of pipe, fd_pipe[1]: write end of pipe */
|
|
||||||
pid_t pid1;
|
pid_t pid1;
|
||||||
|
|
||||||
if (messageboxdata->numbuttons > MAX_BUTTONS) {
|
|
||||||
return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pipe(fd_pipe) != 0) { /* create a pipe */
|
|
||||||
return SDL_SetError("pipe() failed: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
pid1 = fork();
|
pid1 = fork();
|
||||||
if (pid1 == 0) { /* child process */
|
if (pid1 == 0) { /* child process */
|
||||||
int argc = 5, i;
|
|
||||||
const char *argv[5 + 2 /* icon name */ + 2 /* title */ + 2 /* message */ + 2 * MAX_BUTTONS + 1 /* NULL */] = {
|
|
||||||
"zenity", "--question", "--switch", "--no-wrap", "--no-markup"
|
|
||||||
};
|
|
||||||
|
|
||||||
close(fd_pipe[0]); /* no reading from pipe */
|
close(fd_pipe[0]); /* no reading from pipe */
|
||||||
/* write stdout in pipe */
|
/* write stdout in pipe */
|
||||||
if (dup2(fd_pipe[1], STDOUT_FILENO) == -1) {
|
if (dup2(fd_pipe[1], STDOUT_FILENO) == -1) {
|
||||||
_exit(128);
|
_exit(128);
|
||||||
}
|
}
|
||||||
|
|
||||||
argv[argc++] = "--icon-name";
|
|
||||||
switch (messageboxdata->flags) {
|
|
||||||
case SDL_MESSAGEBOX_ERROR:
|
|
||||||
argv[argc++] = "dialog-error";
|
|
||||||
break;
|
|
||||||
case SDL_MESSAGEBOX_WARNING:
|
|
||||||
argv[argc++] = "dialog-warning";
|
|
||||||
break;
|
|
||||||
case SDL_MESSAGEBOX_INFORMATION:
|
|
||||||
default:
|
|
||||||
argv[argc++] = "dialog-information";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messageboxdata->title && messageboxdata->title[0]) {
|
|
||||||
argv[argc++] = "--title";
|
|
||||||
argv[argc++] = messageboxdata->title;
|
|
||||||
} else {
|
|
||||||
argv[argc++] = "--title=\"\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messageboxdata->message && messageboxdata->message[0]) {
|
|
||||||
argv[argc++] = "--text";
|
|
||||||
argv[argc++] = messageboxdata->message;
|
|
||||||
} else {
|
|
||||||
argv[argc++] = "--text=\"\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < messageboxdata->numbuttons; ++i) {
|
|
||||||
if (messageboxdata->buttons[i].text && messageboxdata->buttons[i].text[0]) {
|
|
||||||
argv[argc++] = "--extra-button";
|
|
||||||
argv[argc++] = messageboxdata->buttons[i].text;
|
|
||||||
} else {
|
|
||||||
argv[argc++] = "--extra-button=\"\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argv[argc] = NULL;
|
|
||||||
|
|
||||||
/* const casting argv is fine:
|
/* const casting argv is fine:
|
||||||
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html -> rational
|
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html -> rational
|
||||||
*/
|
*/
|
||||||
execvp("zenity", (char **)argv);
|
execvp("zenity", (char **)args);
|
||||||
_exit(129);
|
_exit(129);
|
||||||
} else if (pid1 < 0) {
|
} else if (pid1 < 0) { /* fork() failed */
|
||||||
close(fd_pipe[0]);
|
|
||||||
close(fd_pipe[1]);
|
|
||||||
return SDL_SetError("fork() failed: %s", strerror(errno));
|
return SDL_SetError("fork() failed: %s", strerror(errno));
|
||||||
} else {
|
} else { /* parent process */
|
||||||
int status;
|
close(fd_pipe[1]); /* no writing to the pipe */
|
||||||
if (waitpid(pid1, &status, 0) == pid1) {
|
if (waitpid(pid1, &status, 0) != pid1) {
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
if (WEXITSTATUS(status) < 128) {
|
|
||||||
int i;
|
|
||||||
size_t output_len = 1;
|
|
||||||
char *output = NULL;
|
|
||||||
char *tmp = NULL;
|
|
||||||
FILE *outputfp = NULL;
|
|
||||||
|
|
||||||
close(fd_pipe[1]); /* no writing to pipe */
|
|
||||||
/* At this point, if no button ID is needed, we can just bail as soon as the
|
|
||||||
* process has completed.
|
|
||||||
*/
|
|
||||||
if (buttonid == NULL) {
|
|
||||||
close(fd_pipe[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*buttonid = -1;
|
|
||||||
|
|
||||||
/* find button with longest text */
|
|
||||||
for (i = 0; i < messageboxdata->numbuttons; ++i) {
|
|
||||||
if (messageboxdata->buttons[i].text != NULL) {
|
|
||||||
const size_t button_len = SDL_strlen(messageboxdata->buttons[i].text);
|
|
||||||
if (button_len > output_len) {
|
|
||||||
output_len = button_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output = SDL_malloc(output_len + 1);
|
|
||||||
if (output == NULL) {
|
|
||||||
close(fd_pipe[0]);
|
|
||||||
return SDL_OutOfMemory();
|
|
||||||
}
|
|
||||||
output[0] = '\0';
|
|
||||||
|
|
||||||
outputfp = fdopen(fd_pipe[0], "r");
|
|
||||||
if (outputfp == NULL) {
|
|
||||||
SDL_free(output);
|
|
||||||
close(fd_pipe[0]);
|
|
||||||
return SDL_SetError("Couldn't open pipe for reading: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
tmp = fgets(output, output_len + 1, outputfp);
|
|
||||||
(void)fclose(outputfp);
|
|
||||||
|
|
||||||
if ((tmp == NULL) || (*tmp == '\0') || (*tmp == '\n')) {
|
|
||||||
SDL_free(output);
|
|
||||||
return 0; /* 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 (messageboxdata->buttons[i].text != NULL) {
|
|
||||||
if (SDL_strcmp(output, messageboxdata->buttons[i].text) == 0) {
|
|
||||||
*buttonid = messageboxdata->buttons[i].buttonid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_free(output);
|
|
||||||
return 0; /* success! */
|
|
||||||
} else {
|
|
||||||
return SDL_SetError("zenity reported error or failed to launch: %d", WEXITSTATUS(status));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return SDL_SetError("zenity failed for some reason");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return SDL_SetError("Waiting on zenity failed: %s", strerror(errno));
|
return SDL_SetError("Waiting on zenity failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!WIFEXITED(status)) {
|
||||||
|
return SDL_SetError("zenity failed for some reason");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WEXITSTATUS(status) >= 128) {
|
||||||
|
return SDL_SetError("zenity reported error or failed to launch: %d", WEXITSTATUS(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* success! */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_zenity_version(int *major, int *minor) {
|
||||||
|
int fd_pipe[2]; /* fd_pipe[0]: read end of pipe, fd_pipe[1]: write end of pipe */
|
||||||
|
const char *argv[] = { "zenity", "--version", NULL };
|
||||||
|
|
||||||
|
if (pipe(fd_pipe) != 0) { /* create a pipe */
|
||||||
|
return SDL_SetError("pipe() failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (run_zenity(argv, fd_pipe) == 0) {
|
||||||
|
FILE *outputfp = NULL;
|
||||||
|
char version_str[ZENITY_VERSION_LEN];
|
||||||
|
char *version_ptr = NULL, *end_ptr = NULL;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
outputfp = fdopen(fd_pipe[0], "r");
|
||||||
|
if (outputfp == NULL) {
|
||||||
|
close(fd_pipe[0]);
|
||||||
|
return SDL_SetError("failed to open pipe for reading: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
version_ptr = fgets(version_str, ZENITY_VERSION_LEN, outputfp);
|
||||||
|
(void)fclose(outputfp); /* will close underlying fd */
|
||||||
|
|
||||||
|
/* we expect the version string is in the form of MAJOR.MINOR.MICRO
|
||||||
|
* as described in meson.build. We'll ignore everything after that.
|
||||||
|
*/
|
||||||
|
tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10);
|
||||||
|
if (tmp == 0 && end_ptr == version_ptr) {
|
||||||
|
return SDL_SetError("failed to get zenity major version number");
|
||||||
|
}
|
||||||
|
*major = tmp;
|
||||||
|
|
||||||
|
version_ptr = end_ptr + 1; /* skip the dot */
|
||||||
|
tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10);
|
||||||
|
if (tmp == 0 && end_ptr == version_ptr) {
|
||||||
|
return SDL_SetError("failed to get zenity minor version number");
|
||||||
|
}
|
||||||
|
*minor = tmp;
|
||||||
|
|
||||||
|
return 0; /* success */
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd_pipe[0]);
|
||||||
|
close(fd_pipe[1]);
|
||||||
|
return -1; /* run_zenity should've called SDL_SetError() */
|
||||||
|
}
|
||||||
|
|
||||||
|
int Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) {
|
||||||
|
int fd_pipe[2]; /* fd_pipe[0]: read end of pipe, fd_pipe[1]: write end of pipe */
|
||||||
|
int zenity_major = 0, zenity_minor = 0, output_len = 0;
|
||||||
|
int argc = 5, i;
|
||||||
|
const char *argv[5 + 2 /* icon name */ + 2 /* title */ + 2 /* message */ + 2 * MAX_BUTTONS + 1 /* NULL */] = {
|
||||||
|
"zenity", "--question", "--switch", "--no-wrap", "--no-markup"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (messageboxdata->numbuttons > MAX_BUTTONS) {
|
||||||
|
return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get zenity version so we know which arg to use */
|
||||||
|
if (get_zenity_version(&zenity_major, &zenity_minor) != 0) {
|
||||||
|
return -1; /* get_zenity_version() calls SDL_SetError(), so message is already set */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipe(fd_pipe) != 0) { /* create a pipe */
|
||||||
|
return SDL_SetError("pipe() failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* https://gitlab.gnome.org/GNOME/zenity/-/commit/c686bdb1b45e95acf010efd9ca0c75527fbb4dea
|
||||||
|
* This commit removed --icon-name without adding a deprecation notice.
|
||||||
|
* We need to handle it gracefully, otherwise no message box will be shown.
|
||||||
|
*/
|
||||||
|
argv[argc++] = zenity_major > 3 || (zenity_major == 3 && zenity_minor >= 90) ? "--icon" : "--icon-name";
|
||||||
|
switch (messageboxdata->flags) {
|
||||||
|
case SDL_MESSAGEBOX_ERROR:
|
||||||
|
argv[argc++] = "dialog-error";
|
||||||
|
break;
|
||||||
|
case SDL_MESSAGEBOX_WARNING:
|
||||||
|
argv[argc++] = "dialog-warning";
|
||||||
|
break;
|
||||||
|
case SDL_MESSAGEBOX_INFORMATION:
|
||||||
|
default:
|
||||||
|
argv[argc++] = "dialog-information";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageboxdata->title && messageboxdata->title[0]) {
|
||||||
|
argv[argc++] = "--title";
|
||||||
|
argv[argc++] = messageboxdata->title;
|
||||||
|
} else {
|
||||||
|
argv[argc++] = "--title=\"\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageboxdata->message && messageboxdata->message[0]) {
|
||||||
|
argv[argc++] = "--text";
|
||||||
|
argv[argc++] = messageboxdata->message;
|
||||||
|
} else {
|
||||||
|
argv[argc++] = "--text=\"\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < messageboxdata->numbuttons; ++i) {
|
||||||
|
if (messageboxdata->buttons[i].text && messageboxdata->buttons[i].text[0]) {
|
||||||
|
int len = SDL_strlen(messageboxdata->buttons[i].text);
|
||||||
|
if (len > output_len) {
|
||||||
|
output_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv[argc++] = "--extra-button";
|
||||||
|
argv[argc++] = messageboxdata->buttons[i].text;
|
||||||
|
} else {
|
||||||
|
argv[argc++] = "--extra-button=\"\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argv[argc] = NULL;
|
||||||
|
|
||||||
|
if (run_zenity(argv, fd_pipe) == 0) {
|
||||||
|
FILE *outputfp = NULL;
|
||||||
|
char *output = NULL;
|
||||||
|
char *tmp = NULL;
|
||||||
|
|
||||||
|
if (buttonid == NULL) {
|
||||||
|
/* if we don't need buttonid, we can return immediately */
|
||||||
|
close(fd_pipe[0]);
|
||||||
|
return 0; /* success */
|
||||||
|
}
|
||||||
|
*buttonid = -1;
|
||||||
|
|
||||||
|
output = SDL_malloc(output_len + 1);
|
||||||
|
if (output == NULL) {
|
||||||
|
close(fd_pipe[0]);
|
||||||
|
return SDL_OutOfMemory();
|
||||||
|
}
|
||||||
|
output[0] = '\0';
|
||||||
|
|
||||||
|
outputfp = fdopen(fd_pipe[0], "r");
|
||||||
|
if (outputfp == NULL) {
|
||||||
|
SDL_free(output);
|
||||||
|
close(fd_pipe[0]);
|
||||||
|
return SDL_SetError("Couldn't open pipe for reading: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
tmp = fgets(output, output_len + 1, outputfp);
|
||||||
|
(void)fclose(outputfp);
|
||||||
|
|
||||||
|
if ((tmp == NULL) || (*tmp == '\0') || (*tmp == '\n')) {
|
||||||
|
SDL_free(output);
|
||||||
|
return 0; /* 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 (messageboxdata->buttons[i].text != NULL) {
|
||||||
|
if (SDL_strcmp(output, messageboxdata->buttons[i].text) == 0) {
|
||||||
|
*buttonid = messageboxdata->buttons[i].buttonid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(output);
|
||||||
|
return 0; /* success! */
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd_pipe[0]);
|
||||||
|
close(fd_pipe[1]);
|
||||||
|
return -1; /* run_zenity() calls SDL_SetError(), so message is already set */
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
|
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
Loading…
Reference in a new issue