From 6b2b6e476c36b018bced593eb00b7a36b9db8511 Mon Sep 17 00:00:00 2001 From: Fabio Ka Date: Wed, 27 Jan 2016 12:01:11 -0200 Subject: [PATCH 1/4] Add message box on Linux platforms --- src/platform/linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/linux.c b/src/platform/linux.c index 4df2a9806d..e47e9c5bef 100644 --- a/src/platform/linux.c +++ b/src/platform/linux.c @@ -154,7 +154,7 @@ utf8 *platform_open_directory_browser(utf8 *title) void platform_show_messagebox(char *message) { - STUB(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenRCT2", message, gWindow); log_verbose(message); } From d193e9f3b3afdc49a1a1ae83c89b4988e03bd97e Mon Sep 17 00:00:00 2001 From: Fabio Ka Date: Wed, 27 Jan 2016 12:57:08 -0200 Subject: [PATCH 2/4] Change msgbox flags/log on Linux to "warning" --- src/platform/linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/linux.c b/src/platform/linux.c index e47e9c5bef..cd0fa82e59 100644 --- a/src/platform/linux.c +++ b/src/platform/linux.c @@ -154,8 +154,8 @@ utf8 *platform_open_directory_browser(utf8 *title) void platform_show_messagebox(char *message) { - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenRCT2", message, gWindow); - log_verbose(message); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "OpenRCT2", message, gWindow); + log_warning(message); } /** From ffafd07c9023d3b3b8a22d668ff0ab78c8668623 Mon Sep 17 00:00:00 2001 From: anyc Date: Fri, 29 Jan 2016 18:40:42 +0100 Subject: [PATCH 3/4] use enum to specify file dialog type --- src/game.c | 6 +++--- src/platform/linux.c | 2 +- src/platform/osx.m | 6 +++--- src/platform/platform.h | 5 ++++- src/platform/windows.c | 10 +++++----- src/ride/track.c | 2 +- src/windows/editor_bottom_toolbar.c | 2 +- src/windows/loadsave.c | 12 ++++++------ 8 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/game.c b/src/game.c index 3917b22f7b..e5612c3c7b 100644 --- a/src/game.c +++ b/src/game.c @@ -624,7 +624,7 @@ static int open_landscape_file_dialog() safe_strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_LANDSCAPES_PATH, MAX_PATH); format_string((char*)0x0141EE68, STR_RCT2_LANDSCAPE_FILE, 0); audio_pause_sounds(); - result = platform_open_common_file_dialog(1, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6;*.SV4;*.SC6", (char*)0x0141EE68); + result = platform_open_common_file_dialog(FD_OPEN, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6;*.SV4;*.SC6", (char*)0x0141EE68); audio_unpause_sounds(); // window_proc return result; @@ -641,7 +641,7 @@ static int open_load_game_dialog() safe_strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_SAVED_GAMES_PATH, MAX_PATH); format_string((char*)0x0141EE68, STR_RCT2_SAVED_GAME, 0); audio_pause_sounds(); - result = platform_open_common_file_dialog(1, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6", (char*)0x0141EE68); + result = platform_open_common_file_dialog(FD_OPEN, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6", (char*)0x0141EE68); audio_unpause_sounds(); // window_proc return result; @@ -990,7 +990,7 @@ static int show_save_game_dialog(char *resultPath) format_string(filterName, STR_RCT2_SAVED_GAME, NULL); audio_pause_sounds(); - result = platform_open_common_file_dialog(0, title, filename, "*.SV6", filterName); + result = platform_open_common_file_dialog(FD_SAVE, title, filename, "*.SV6", filterName); audio_unpause_sounds(); if (result) diff --git a/src/platform/linux.c b/src/platform/linux.c index cd0fa82e59..c910f535e2 100644 --- a/src/platform/linux.c +++ b/src/platform/linux.c @@ -162,7 +162,7 @@ void platform_show_messagebox(char *message) * * rct2: 0x004080EA */ -int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) +int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) { STUB(); return 0; diff --git a/src/platform/osx.m b/src/platform/osx.m index a4e7cb5e05..fb2f7f9916 100644 --- a/src/platform/osx.m +++ b/src/platform/osx.m @@ -131,7 +131,7 @@ utf8 *platform_open_directory_browser(utf8 *title) } } -int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) +int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) { @autoreleasepool { @@ -144,12 +144,12 @@ int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 NSString *basename = filePath.lastPathComponent; NSSavePanel *panel; - if (type == 0) + if (type == FD_SAVE) { panel = [NSSavePanel savePanel]; panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.%@", basename, extensions.firstObject]; } - else if (type == 1) + else if (type == FD_OPEN) { NSOpenPanel *open = [NSOpenPanel openPanel]; open.canChooseDirectories = false; diff --git a/src/platform/platform.h b/src/platform/platform.h index 24717e007b..72fc7c7069 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -85,6 +85,9 @@ enum { CURSOR_PRESSED = CURSOR_DOWN | CURSOR_CHANGED, }; +typedef enum {FD_OPEN, FD_SAVE} filedialog_type; + + extern openrct2_cursor gCursorState; extern const unsigned char *gKeysState; extern unsigned char *gKeysPressed; @@ -158,7 +161,7 @@ void platform_resolve_openrct_data_path(); void platform_get_openrct_data_path(utf8 *outPath); void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory); void platform_show_messagebox(utf8 *message); -int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName); +int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName); utf8 *platform_open_directory_browser(utf8 *title); uint8 platform_get_locale_currency(); uint8 platform_get_currency_value(const char *currencyCode); diff --git a/src/platform/windows.c b/src/platform/windows.c index 8f0be894b3..b6ec169242 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -579,7 +579,7 @@ void platform_show_messagebox(char *message) * * rct2: 0x004080EA */ -int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) +int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) { wchar_t wctitle[256], wcfilename[MAX_PATH], wcfilterPattern[256], wcfilterName[256]; wchar_t initialDirectory[MAX_PATH], *dotAddress, *slashAddress; @@ -603,8 +603,8 @@ int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 } // Clear filename - if (type != 0) - wcfilename[0] = 0; + if (type != FD_SAVE) + wcfilename[0] = 0; // Set open file name options memset(&openFileName, 0, sizeof(OPENFILENAMEW)); @@ -633,10 +633,10 @@ int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 // Open dialog commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; - if (type == 0) { + if (type == FD_SAVE) { openFileName.Flags = commonFlags | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT; result = GetSaveFileNameW(&openFileName); - } else if (type == 1) { + } else if (type == FD_OPEN) { openFileName.Flags = commonFlags | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST; result = GetOpenFileNameW(&openFileName); } diff --git a/src/ride/track.c b/src/ride/track.c index 3ef16ebc89..5c28d6ac4f 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -3086,7 +3086,7 @@ int save_track_design(uint8 rideIndex){ audio_pause_sounds(); int result = platform_open_common_file_dialog( - 0, + FD_SAVE, RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char), path, "*.TD?", diff --git a/src/windows/editor_bottom_toolbar.c b/src/windows/editor_bottom_toolbar.c index bc36612bda..261998c07b 100644 --- a/src/windows/editor_bottom_toolbar.c +++ b/src/windows/editor_bottom_toolbar.c @@ -338,7 +338,7 @@ static int show_save_scenario_dialog(char *resultPath) format_string(filterName, STR_RCT2_SCENARIO_FILE, NULL); audio_pause_sounds(); - result = platform_open_common_file_dialog(0, title, filename, "*.SC6", filterName); + result = platform_open_common_file_dialog(FD_SAVE, title, filename, "*.SC6", filterName); audio_unpause_sounds(); if (result) diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index b824a2d3ad..77f1464823 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -304,22 +304,22 @@ static void window_loadsave_mouseup(rct_window *w, int widgetIndex) switch (_type) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : - result = platform_open_common_file_dialog(1, (char*)language_get_string(STR_LOAD_GAME), path, filter, _extension); + result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(STR_LOAD_GAME), path, filter, _extension); break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : - result = platform_open_common_file_dialog(0, (char*)language_get_string(STR_SAVE_GAME), path, filter, _extension); + result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_GAME), path, filter, _extension); break; case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : - result = platform_open_common_file_dialog(1, (char*)language_get_string(STR_LOAD_LANDSCAPE), path, filter, _extension); + result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(STR_LOAD_LANDSCAPE), path, filter, _extension); break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : - result = platform_open_common_file_dialog(0, (char*)language_get_string(STR_SAVE_LANDSCAPE), path, filter, _extension); + result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_LANDSCAPE), path, filter, _extension); break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : - result = platform_open_common_file_dialog(0, (char*)language_get_string(STR_SAVE_SCENARIO), path, filter, _extension); + result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_SCENARIO), path, filter, _extension); break; case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : - result = platform_open_common_file_dialog(1, (char*)language_get_string(1039), path, filter, _extension); + result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(1039), path, filter, _extension); break; } From fb1c6b22bafb1eb1bd38dbce740da1e085a186e7 Mon Sep 17 00:00:00 2001 From: anyc Date: Fri, 29 Jan 2016 18:56:06 +0100 Subject: [PATCH 4/4] Linux: use zenity or kdialog to show user dialogs --- src/platform/linux.c | 229 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 214 insertions(+), 15 deletions(-) diff --git a/src/platform/linux.c b/src/platform/linux.c index c910f535e2..19eb3ad481 100644 --- a/src/platform/linux.c +++ b/src/platform/linux.c @@ -23,6 +23,7 @@ #ifdef __LINUX__ #include +#include #include #include "../util/util.h" @@ -41,6 +42,8 @@ struct dummy { struct dummy* ptr; }; +typedef enum { DT_NONE, DT_KDIALOG, DT_ZENITY } dialog_type; + void platform_get_exe_path(utf8 *outPath) { char exePath[MAX_PATH]; @@ -146,28 +149,224 @@ void platform_posix_sub_resolve_openrct_data_path(utf8 *out) { } } -utf8 *platform_open_directory_browser(utf8 *title) -{ - STUB(); - return NULL; + +void execute_cmd(char *command, int *exit_value, char *buf, size_t *buf_size) { + FILE *f; + int status; + size_t n_chars; + + printf("executing \"%s\"...\n", command); + f = popen(command, "r"); + + if (buf && buf_size) { + n_chars = fread(buf, 1, *buf_size, f); + + // make sure string is null-terminated + if (n_chars == *buf_size) { + n_chars--; + buf[n_chars] = 0; + } + + *buf_size = n_chars; + } else { + fflush(f); + } + + if (exit_value) + *exit_value = pclose(f); + else + pclose(f); } -void platform_show_messagebox(char *message) -{ - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "OpenRCT2", message, gWindow); - log_warning(message); +dialog_type get_dialog_app(char *cmd, size_t *cmd_size) { + int exit_value; + size_t size; + dialog_type dtype; + + /* + * prefer zenity as it offers more required features, e.g., overwrite + * confirmation and selecting only existing files + */ + + dtype = DT_ZENITY; + size = *cmd_size; + execute_cmd("which zenity", &exit_value, cmd, &size); + + if (exit_value != 0) { + dtype = DT_KDIALOG; + size = *cmd_size; + execute_cmd("which kdialog", &exit_value, cmd, &size); + + if (exit_value != 0) { + log_error("no dialog (zenity or kdialog) found\n"); + return DT_NONE; + } + } + + if (cmd[size-1] == '\n') + cmd[size-1] = 0; + + *cmd_size = size; + + return dtype; } -/** - * - * rct2: 0x004080EA - */ -int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) -{ - STUB(); +int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) { + int exit_value; + char executable[MAX_PATH]; + char cmd[MAX_PATH]; + char result[MAX_PATH]; + char *app; + size_t size; + dialog_type dtype; + char *action; + char *flags; + char *filter; + + size = MAX_PATH; + dtype = get_dialog_app(executable, &size); + + filter = 0; + switch (dtype) { + case DT_KDIALOG: + switch (type) { + case FD_OPEN: + action = "--getopenfilename"; + break; + case FD_SAVE: + action = "--getsavefilename"; + break; + } + + if (filterPattern && filterName) { + filter = (char*) malloc(strlen(filterPattern) + 3 + strlen(filterName) + 1); + sprintf(filter, "\"%s | %s\"", filterPattern, filterName); + } + + snprintf(cmd, MAX_PATH, "%s --title \"%s\" %s / %s", executable, title, action, filter?filter:""); + break; + case DT_ZENITY: + action = "--file-selection"; + switch (type) { + case FD_SAVE: + flags = "--confirm-overwrite --save"; + break; + case FD_OPEN: + flags = ""; + break; + } + + if (filterPattern && filterName) { + filter = (char*) malloc(strlen("--file-filter=\"") + strlen(filterPattern) + 3 + strlen(filterName) + 2); + sprintf(filter, "--file-filter=\"%s | %s\"", filterName, filterPattern); + } + + snprintf(cmd, MAX_PATH, "%s %s %s --title=\"%s\" / %s", executable, action, flags, title, filter?filter:""); + break; + default: return 1; + } + + size = MAX_PATH; + execute_cmd(cmd, &exit_value, result, &size); + + if (exit_value != 0) { + return 1; + } + + if (result[size-1] == '\n') + result[size-1] = 0; + + if (type == FD_OPEN && access(result, F_OK) == -1) { + char msg[MAX_PATH]; + + snprintf(msg, MAX_PATH, "\"%s\" not found: %s, please choose another file\n", result, strerror(errno)); + platform_show_messagebox(msg); + + if (filter) + free(filter); + return platform_open_common_file_dialog(type, title, filename, filterPattern, filterName); + } else + if (type == FD_SAVE && access(result, F_OK) != -1 && dtype == DT_KDIALOG) { + snprintf(cmd, MAX_PATH, "%s --yesno \"Overwrite %s?\"", executable, result); + + size = MAX_PATH; + execute_cmd(cmd, &exit_value, 0, 0); + + if (exit_value != 0) + return 0; + } + + strncpy(filename, result, MAX_PATH); + return 0; } +utf8 *platform_open_directory_browser(utf8 *title) { + size_t size; + dialog_type dtype; + int exit_value; + char cmd[MAX_PATH]; + char executable[MAX_PATH]; + char result[MAX_PATH]; + char *return_value; + + size = MAX_PATH; + dtype = get_dialog_app(executable, &size); + + switch (dtype) { + case DT_KDIALOG: + snprintf(cmd, MAX_PATH, "%s --title \"%s\" --getexistingdirectory /", executable, title); + break; + case DT_ZENITY: + snprintf(cmd, MAX_PATH, "%s --title=\"%s\" --file-selection --directory /", executable, title); + break; + default: return 0; + } + + size = MAX_PATH; + execute_cmd(cmd, &exit_value, result, &size); + + if (exit_value != 0) { + return 0; + } + + if (result[size-1] == '\n') + result[size-1] = 0; + + return_value = (char*) malloc(strlen(result)+1); + strcpy(return_value, result); + + return return_value; +} + +void platform_show_messagebox(char *message) { + size_t size; + dialog_type dtype; + int exit_value; + char cmd[MAX_PATH]; + char executable[MAX_PATH]; + + log_verbose(message); + + size = MAX_PATH; + dtype = get_dialog_app(executable, &size); + + switch (dtype) { + case DT_KDIALOG: + snprintf(cmd, MAX_PATH, "%s --title \"OpenRCT2\" --msgbox \"%s\"", executable, message); + break; + case DT_ZENITY: + snprintf(cmd, MAX_PATH, "%s --title=\"OpenRCT2\" --info --text=\"%s\"", executable, message); + break; + default: + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "OpenRCT2", message, gWindow); + return; + } + + size = MAX_PATH; + execute_cmd(cmd, 0, 0, 0); +} + bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) { assert(buffer != NULL);