diff --git a/dive.h b/dive.h index dd321a7b9..701767b3a 100644 --- a/dive.h +++ b/dive.h @@ -720,6 +720,8 @@ extern FILE *subsurface_fopen(const char *path, const char *mode); extern void *subsurface_opendir(const char *path); extern struct zip *subsurface_zip_open_readonly(const char *path, int flags, int *errorp); extern int subsurface_zip_close(struct zip *zip); +extern void subsurface_console_init(bool dedicated); +extern void subsurface_console_exit(void); extern void shift_times(const timestamp_t amount); extern timestamp_t get_times(); diff --git a/linux.c b/linux.c index 6bfb38126..ea0170dc8 100644 --- a/linux.c +++ b/linux.c @@ -131,3 +131,14 @@ int subsurface_zip_close(struct zip *zip) { return zip_close(zip); } + +/* win32 console */ +void subsurface_console_init(bool dedicated) +{ + /* NOP */ +} + +void subsurface_console_exit(void) +{ + /* NOP */ +} diff --git a/macos.c b/macos.c index 01c3fbfb5..19ce9e89d 100644 --- a/macos.c +++ b/macos.c @@ -112,3 +112,14 @@ int subsurface_zip_close(struct zip *zip) { return zip_close(zip); } + +/* win32 console */ +void subsurface_console_init(bool dedicated) +{ + /* NOP */ +} + +void subsurface_console_exit(void) +{ + /* NOP */ +} diff --git a/main.cpp b/main.cpp index c93121400..a011b4caf 100644 --- a/main.cpp +++ b/main.cpp @@ -23,6 +23,11 @@ int main(int argc, char **argv) QStringList files; QStringList importedFiles; QStringList arguments = QCoreApplication::arguments(); + + bool dedicated_console = arguments.length() > 1 && + (arguments.at(1) == QString("--win32console")); + subsurface_console_init(dedicated_console); + for (i = 1; i < arguments.length(); i++) { QString a = arguments.at(i); if (a.at(0) == '-') { @@ -56,5 +61,6 @@ int main(int argc, char **argv) run_ui(); exit_ui(); parse_xml_exit(); + subsurface_console_exit(); return 0; } diff --git a/subsurfacestartup.c b/subsurfacestartup.c index 6d3714b91..b16c1fb9c 100644 --- a/subsurfacestartup.c +++ b/subsurfacestartup.c @@ -94,7 +94,8 @@ static void print_help() printf("\n --help|-h This help text"); printf("\n --import logfile ... Logs before this option is treated as base, everything after is imported"); printf("\n --verbose|-v Verbose debug (repeat to increase verbosity)"); - printf("\n --version Prints current version\n\n"); + printf("\n --version Prints current version"); + printf("\n --win32console Create a dedicated console if needed (Windows only). Add option before everything else\n\n"); } void parse_argument(const char *arg) @@ -130,6 +131,8 @@ void parse_argument(const char *arg) print_version(); exit(0); } + if (strcmp(arg, "--win32console") == 0) + return; /* fallthrough */ case 'p': /* ignore process serial number argument when run as native macosx app */ diff --git a/windows.c b/windows.c index c76a73048..99720cf9d 100644 --- a/windows.c +++ b/windows.c @@ -2,6 +2,7 @@ /* implements Windows specific functions */ #include "dive.h" #include "display.h" +#define _WIN32_WINNT 0x500 #include #include #include @@ -199,3 +200,79 @@ int subsurface_zip_close(struct zip *zip) { return zip_close(zip); } + +/* win32 console */ +static struct { + bool allocated; + UINT cp; + FILE *out, *err; +} console_desc; + +void subsurface_console_init(bool dedicated) +{ + /* if this is a console app already, do nothing */ +#ifndef WIN32_CONSOLE_APP + /* just in case of multiple calls */ + memset((void *)&console_desc, 0, sizeof(console_desc)); + /* the AttachConsole(..) call can be used to determine if the parent process + * is a terminal. if it succeeds, there is no need for a dedicated console + * window and we don't need to call the AllocConsole() function. on the other + * hand if the user has set the 'dedicated' flag to 'true' and if AttachConsole() + * has failed, we create a dedicated console window. + */ + console_desc.allocated = AttachConsole(ATTACH_PARENT_PROCESS); + if (console_desc.allocated) + dedicated = false; + if (!console_desc.allocated && dedicated) + console_desc.allocated = AllocConsole(); + if (!console_desc.allocated) + return; + + console_desc.cp = GetConsoleCP(); + SetConsoleOutputCP(CP_UTF8); /* make the ouput utf8 */ + + /* set some console modes; we don't need to reset these back. + * ENABLE_EXTENDED_FLAGS = 0x0080, ENABLE_QUICK_EDIT_MODE = 0x0040 */ + HANDLE h_in = GetStdHandle(STD_INPUT_HANDLE); + if (h_in) { + SetConsoleMode(h_in, 0x0080 | 0x0040); + CloseHandle(h_in); + } + + /* dedicated only; disable the 'x' button as it will close the main process as well */ + HWND h_cw = GetConsoleWindow(); + if (h_cw && dedicated) { + SetWindowTextA(h_cw, "Subsurface Console"); + HMENU h_menu = GetSystemMenu(h_cw, 0); + if (h_menu) { + EnableMenuItem(h_menu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED); + DrawMenuBar(h_cw); + } + SetConsoleCtrlHandler(NULL, TRUE); /* disable the CTRL handler */ + } + + /* redirect; on win32, CON is a reserved pipe target, like NUL */ + console_desc.out = freopen("CON", "w", stdout); + console_desc.err = freopen("CON", "w", stderr); + if (!dedicated) + puts(""); /* add an empty line */ +#endif +} + +void subsurface_console_exit(void) +{ +#ifndef WIN32_CONSOLE_APP + if (!console_desc.allocated) + return; + + /* close handles */ + if (console_desc.out) + fclose(console_desc.out); + if (console_desc.err) + fclose(console_desc.err); + + /* reset code page and free */ + SetConsoleOutputCP(console_desc.cp); + FreeConsole(); +#endif +}