[Windows] Improve console handling and execute.
Always build with the GUI subsystem. Redirect stdout and stderr output to the parent process console. Use CreateProcessW for blocking `execute` calls with piped stdout and stderr (prevent console windows for popping up when used with the GUI subsystem build, and have more consistent behavior with non-blocking calls). Add `open_console` argument to the `execute` to open a new console window (for both blocking and non-blocking calls). Remove `interface/editor/hide_console_window` editor setting. Remove `Toggle System Console` menu option. Remove `set_console_visible` and `is_console_visible` functions.
This commit is contained in:
parent
e937963007
commit
59085d5051
19 changed files with 87 additions and 173 deletions
|
@ -36,6 +36,7 @@
|
|||
#include "core/io/json.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "core/math/geometry.h"
|
||||
#include "core/method_bind_ext.gen.inc"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/project_settings.h"
|
||||
|
@ -471,7 +472,7 @@ Error _OS::shell_open(String p_uri) {
|
|||
return OS::get_singleton()->shell_open(p_uri);
|
||||
};
|
||||
|
||||
int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr) {
|
||||
int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr, bool p_open_console) {
|
||||
OS::ProcessID pid = -2;
|
||||
int exitcode = 0;
|
||||
List<String> args;
|
||||
|
@ -479,7 +480,7 @@ int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p
|
|||
args.push_back(p_arguments[i]);
|
||||
}
|
||||
String pipe;
|
||||
Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, &exitcode, p_read_stderr);
|
||||
Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, &exitcode, p_read_stderr, nullptr, p_open_console);
|
||||
p_output.clear();
|
||||
p_output.push_back(pipe);
|
||||
if (err != OK) {
|
||||
|
@ -1311,7 +1312,7 @@ void _OS::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_processor_count"), &_OS::get_processor_count);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_executable_path"), &_OS::get_executable_path);
|
||||
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output", "read_stderr"), &_OS::execute, DEFVAL(true), DEFVAL(Array()), DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output", "read_stderr", "open_console"), &_OS::execute, DEFVAL(true), DEFVAL(Array()), DEFVAL(false), DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("kill", "pid"), &_OS::kill);
|
||||
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &_OS::shell_open);
|
||||
ClassDB::bind_method(D_METHOD("get_process_id"), &_OS::get_process_id);
|
||||
|
|
|
@ -241,7 +241,7 @@ public:
|
|||
int get_low_processor_usage_mode_sleep_usec() const;
|
||||
|
||||
String get_executable_path() const;
|
||||
int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true, Array p_output = Array(), bool p_read_stderr = false);
|
||||
int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true, Array p_output = Array(), bool p_read_stderr = false, bool p_open_console = false);
|
||||
|
||||
Error kill(int p_pid);
|
||||
Error shell_open(String p_uri);
|
||||
|
|
|
@ -234,8 +234,6 @@ public:
|
|||
virtual void set_window_always_on_top(bool p_enabled) {}
|
||||
virtual bool is_window_always_on_top() const { return false; }
|
||||
virtual bool is_window_focused() const { return true; }
|
||||
virtual void set_console_visible(bool p_enabled) {}
|
||||
virtual bool is_console_visible() const { return false; }
|
||||
virtual void request_attention() {}
|
||||
virtual void center_window();
|
||||
|
||||
|
@ -290,7 +288,7 @@ public:
|
|||
virtual int get_low_processor_usage_mode_sleep_usec() const;
|
||||
|
||||
virtual String get_executable_path() const;
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0;
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) = 0;
|
||||
virtual Error kill(const ProcessID &p_pid) = 0;
|
||||
virtual int get_process_id() const;
|
||||
virtual void vibrate_handheld(int p_duration_ms = 500);
|
||||
|
|
|
@ -92,12 +92,14 @@
|
|||
<argument index="2" name="blocking" type="bool" default="true" />
|
||||
<argument index="3" name="output" type="Array" default="[ ]" />
|
||||
<argument index="4" name="read_stderr" type="bool" default="false" />
|
||||
<argument index="5" name="open_console" type="bool" default="false" />
|
||||
<description>
|
||||
Execute the file at the given path with the arguments passed as an array of strings. Platform path resolution will take place. The resolved file must exist and be executable.
|
||||
The arguments are used in the given order and separated by a space, so [code]OS.execute("ping", ["-w", "3", "godotengine.org"], false)[/code] will resolve to [code]ping -w 3 godotengine.org[/code] in the system's shell.
|
||||
This method has slightly different behavior based on whether the [code]blocking[/code] mode is enabled.
|
||||
If [code]blocking[/code] is [code]true[/code], the Godot thread will pause its execution while waiting for the process to terminate. The shell output of the process will be written to the [code]output[/code] array as a single string. When the process terminates, the Godot thread will resume execution.
|
||||
If [code]blocking[/code] is [code]false[/code], the Godot thread will continue while the new process runs. It is not possible to retrieve the shell output in non-blocking mode, so [code]output[/code] will be empty.
|
||||
On Windows, if [code]open_console[/code] is [code]true[/code] and process is console app, new terminal window will be opened, it's ignored on other platforms.
|
||||
The return value also depends on the blocking mode. When blocking, the method will return an exit code of the process. When non-blocking, the method returns a process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process forking (non-blocking) or opening (blocking) fails, the method will return [code]-1[/code] or another exit code.
|
||||
Example of blocking mode and retrieving the shell output:
|
||||
[codeblock]
|
||||
|
|
|
@ -260,7 +260,7 @@ uint64_t OS_Unix::get_ticks_usec() const {
|
|||
return longtime;
|
||||
}
|
||||
|
||||
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// Don't compile this code at all to avoid undefined references.
|
||||
// Actual virtual call goes to OS_JavaScript.
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
virtual void delay_usec(uint32_t p_usec) const;
|
||||
virtual uint64_t get_ticks_usec() const;
|
||||
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false);
|
||||
virtual Error kill(const ProcessID &p_pid);
|
||||
virtual int get_process_id() const;
|
||||
|
||||
|
|
|
@ -2803,11 +2803,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
|
|||
OS::get_singleton()->set_window_fullscreen(!OS::get_singleton()->is_window_fullscreen());
|
||||
|
||||
} break;
|
||||
case SETTINGS_TOGGLE_CONSOLE: {
|
||||
bool was_visible = OS::get_singleton()->is_console_visible();
|
||||
OS::get_singleton()->set_console_visible(!was_visible);
|
||||
EditorSettings::get_singleton()->set_setting("interface/editor/hide_console_window", was_visible);
|
||||
} break;
|
||||
case EDITOR_SCREENSHOT: {
|
||||
screenshot_timer->start();
|
||||
} break;
|
||||
|
@ -6437,9 +6432,6 @@ EditorNode::EditorNode() {
|
|||
p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_CMD | KEY_MASK_CTRL | KEY_F), SETTINGS_TOGGLE_FULLSCREEN);
|
||||
#else
|
||||
p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_SHIFT | KEY_F11), SETTINGS_TOGGLE_FULLSCREEN);
|
||||
#endif
|
||||
#ifdef WINDOWS_ENABLED
|
||||
p->add_item(TTR("Toggle System Console"), SETTINGS_TOGGLE_CONSOLE);
|
||||
#endif
|
||||
p->add_separator();
|
||||
|
||||
|
|
|
@ -190,7 +190,6 @@ private:
|
|||
SETTINGS_MANAGE_FEATURE_PROFILES,
|
||||
SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE,
|
||||
SETTINGS_PICK_MAIN_SCENE,
|
||||
SETTINGS_TOGGLE_CONSOLE,
|
||||
SETTINGS_TOGGLE_FULLSCREEN,
|
||||
SETTINGS_HELP,
|
||||
SCENE_TAB_CLOSE,
|
||||
|
|
|
@ -335,7 +335,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
|
|||
hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,1000000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
|
||||
_initial_set("interface/editor/separate_distraction_mode", false);
|
||||
_initial_set("interface/editor/automatically_open_screenshots", true);
|
||||
_initial_set("interface/editor/hide_console_window", false);
|
||||
_initial_set("interface/editor/save_each_scene_on_quit", true); // Regression
|
||||
_initial_set("interface/editor/quit_confirmation", true);
|
||||
|
||||
|
|
|
@ -2089,10 +2089,6 @@ bool Main::start() {
|
|||
}
|
||||
|
||||
if (project_manager || editor) {
|
||||
// Hide console window if requested (Windows-only).
|
||||
bool hide_console = EditorSettings::get_singleton()->get_setting("interface/editor/hide_console_window");
|
||||
OS::get_singleton()->set_console_visible(!hide_console);
|
||||
|
||||
// Load SSL Certificates from Editor Settings (or builtin)
|
||||
Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String());
|
||||
}
|
||||
|
|
|
@ -890,7 +890,7 @@ void OS_JavaScript::finalize() {
|
|||
|
||||
// Miscellaneous
|
||||
|
||||
Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||
Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
||||
Array args;
|
||||
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
||||
args.push_back(E->get());
|
||||
|
|
|
@ -168,7 +168,7 @@ public:
|
|||
virtual MainLoop *get_main_loop() const;
|
||||
bool main_loop_iterate();
|
||||
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL, bool p_open_console = false);
|
||||
virtual Error kill(const ProcessID &p_pid);
|
||||
virtual int get_process_id() const;
|
||||
int get_processor_count() const;
|
||||
|
|
|
@ -255,7 +255,7 @@ public:
|
|||
virtual void set_offscreen_gl_current(bool p_current);
|
||||
|
||||
virtual String get_executable_path() const;
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false);
|
||||
|
||||
virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
|
||||
virtual int keyboard_get_layout_count() const;
|
||||
|
|
|
@ -2967,7 +2967,7 @@ String OS_OSX::get_executable_path() const {
|
|||
}
|
||||
}
|
||||
|
||||
Error OS_OSX::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||
Error OS_OSX::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
||||
if (@available(macOS 10.15, *)) {
|
||||
NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
|
||||
// If executable is bundled, always execute editor instances using NSWorkspace to ensure app window is registered and activated correctly.
|
||||
|
@ -3014,10 +3014,10 @@ Error OS_OSX::execute(const String &p_path, const List<String> &p_arguments, boo
|
|||
|
||||
return err;
|
||||
} else {
|
||||
return OS_Unix::execute(p_path, p_arguments, p_blocking, r_child_id, r_pipe, r_exitcode, read_stderr, p_pipe_mutex);
|
||||
return OS_Unix::execute(p_path, p_arguments, p_blocking, r_child_id, r_pipe, r_exitcode, read_stderr, p_pipe_mutex, p_open_console);
|
||||
}
|
||||
} else {
|
||||
return OS_Unix::execute(p_path, p_arguments, p_blocking, r_child_id, r_pipe, r_exitcode, read_stderr, p_pipe_mutex);
|
||||
return OS_Unix::execute(p_path, p_arguments, p_blocking, r_child_id, r_pipe, r_exitcode, read_stderr, p_pipe_mutex, p_open_console);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -669,7 +669,7 @@ void OS_UWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c
|
|||
// TODO
|
||||
}
|
||||
|
||||
Error OS_UWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||
Error OS_UWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
||||
return FAILED;
|
||||
};
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ public:
|
|||
virtual void delay_usec(uint32_t p_usec) const;
|
||||
virtual uint64_t get_ticks_usec() const;
|
||||
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL, bool p_open_console = false);
|
||||
virtual Error kill(const ProcessID &p_pid);
|
||||
|
||||
virtual bool has_environment(const String &p_var) const;
|
||||
|
|
|
@ -183,9 +183,6 @@ def configure_msvc(env, manual_msvc_config):
|
|||
env.Append(CCFLAGS=["/O1"])
|
||||
env.Append(LINKFLAGS=["/OPT:REF"])
|
||||
|
||||
env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
|
||||
env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"])
|
||||
|
||||
elif env["target"] == "release_debug":
|
||||
if env["optimize"] == "speed": # optimize for speed (default)
|
||||
env.Append(CCFLAGS=["/O2"])
|
||||
|
@ -193,15 +190,16 @@ def configure_msvc(env, manual_msvc_config):
|
|||
elif env["optimize"] == "size": # optimize for size
|
||||
env.Append(CCFLAGS=["/O1"])
|
||||
env.Append(LINKFLAGS=["/OPT:REF"])
|
||||
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
|
||||
|
||||
elif env["target"] == "debug":
|
||||
env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"])
|
||||
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
|
||||
# Allow big objects. Only needed for debug, see MinGW branch for rationale.
|
||||
env.AppendUnique(CCFLAGS=["/bigobj"])
|
||||
env.Append(LINKFLAGS=["/DEBUG"])
|
||||
|
||||
env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
|
||||
env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"])
|
||||
|
||||
if env["debug_symbols"]:
|
||||
env.AppendUnique(CCFLAGS=["/Zi", "/FS"])
|
||||
env.AppendUnique(LINKFLAGS=["/DEBUG"])
|
||||
|
@ -316,8 +314,6 @@ def configure_mingw(env):
|
|||
env.Append(CCFLAGS=["-O2"])
|
||||
else: # optimize for size
|
||||
env.Prepend(CCFLAGS=["-Os"])
|
||||
env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
|
||||
|
||||
if env["debug_symbols"]:
|
||||
env.Prepend(CCFLAGS=["-g2"])
|
||||
|
||||
|
@ -337,6 +333,8 @@ def configure_mingw(env):
|
|||
# and are the only ones with too big objects).
|
||||
env.Append(CCFLAGS=["-Wa,-mbig-obj"])
|
||||
|
||||
env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
|
||||
|
||||
## Compiler configuration
|
||||
|
||||
if os.name == "nt":
|
||||
|
|
|
@ -108,69 +108,17 @@ static String format_error_message(DWORD id) {
|
|||
extern HINSTANCE godot_hinstance;
|
||||
|
||||
void RedirectIOToConsole() {
|
||||
int hConHandle;
|
||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
FILE *fpstdin = stdin;
|
||||
FILE *fpstdout = stdout;
|
||||
FILE *fpstderr = stderr;
|
||||
|
||||
intptr_t lStdHandle;
|
||||
freopen_s(&fpstdin, "CONIN$", "r", stdin);
|
||||
freopen_s(&fpstdout, "CONOUT$", "w", stdout);
|
||||
freopen_s(&fpstderr, "CONOUT$", "w", stderr);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
||||
|
||||
FILE *fp;
|
||||
|
||||
// allocate a console for this app
|
||||
|
||||
AllocConsole();
|
||||
|
||||
// set the screen buffer to be big enough to let us scroll text
|
||||
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
|
||||
&coninfo);
|
||||
|
||||
coninfo.dwSize.Y = MAX_CONSOLE_LINES;
|
||||
|
||||
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
|
||||
coninfo.dwSize);
|
||||
|
||||
// redirect unbuffered STDOUT to the console
|
||||
|
||||
lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
|
||||
|
||||
fp = _fdopen(hConHandle, "w");
|
||||
|
||||
*stdout = *fp;
|
||||
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
// redirect unbuffered STDIN to the console
|
||||
|
||||
lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
|
||||
|
||||
fp = _fdopen(hConHandle, "r");
|
||||
|
||||
*stdin = *fp;
|
||||
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
|
||||
// redirect unbuffered STDERR to the console
|
||||
|
||||
lStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
|
||||
|
||||
fp = _fdopen(hConHandle, "w");
|
||||
|
||||
*stderr = *fp;
|
||||
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
|
||||
|
||||
// point to console as well
|
||||
printf("\n"); // Make sure our output is starting from the new line.
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
|
||||
|
@ -210,7 +158,8 @@ void OS_Windows::initialize_core() {
|
|||
last_button_state = 0;
|
||||
restore_mouse_trails = 0;
|
||||
|
||||
//RedirectIOToConsole();
|
||||
RedirectIOToConsole();
|
||||
|
||||
maximized = false;
|
||||
minimized = false;
|
||||
borderless = false;
|
||||
|
@ -2247,31 +2196,6 @@ bool OS_Windows::is_window_focused() const {
|
|||
return window_focused;
|
||||
}
|
||||
|
||||
bool OS_Windows::_is_win11_terminal() const {
|
||||
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hStdOut, &dwMode)) {
|
||||
return ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void OS_Windows::set_console_visible(bool p_enabled) {
|
||||
if (console_visible == p_enabled)
|
||||
return;
|
||||
|
||||
if (!_is_win11_terminal()) {
|
||||
// GetConsoleWindow is not supported by the Windows Terminal.
|
||||
ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE);
|
||||
console_visible = p_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
bool OS_Windows::is_console_visible() const {
|
||||
return console_visible;
|
||||
}
|
||||
|
||||
bool OS_Windows::get_window_per_pixel_transparency_enabled() const {
|
||||
if (!is_layered_allowed())
|
||||
return false;
|
||||
|
@ -2815,43 +2739,9 @@ String OS_Windows::_quote_command_line_argument(const String &p_text) const {
|
|||
return p_text;
|
||||
}
|
||||
|
||||
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
||||
String path = p_path.replace("/", "\\");
|
||||
|
||||
if (p_blocking && r_pipe) {
|
||||
String argss = _quote_command_line_argument(path);
|
||||
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
||||
argss += " " + _quote_command_line_argument(E->get());
|
||||
}
|
||||
|
||||
if (read_stderr) {
|
||||
argss += " 2>&1"; // Read stderr too
|
||||
}
|
||||
// Note: _wpopen is calling command as "cmd.exe /c argss", instead of executing it directly, add extra quotes around full command, to prevent it from stripping quotes in the command.
|
||||
argss = _quote_command_line_argument(argss);
|
||||
|
||||
FILE *f = _wpopen(argss.c_str(), L"r");
|
||||
ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
|
||||
|
||||
char buf[65535];
|
||||
while (fgets(buf, 65535, f)) {
|
||||
if (p_pipe_mutex) {
|
||||
p_pipe_mutex->lock();
|
||||
}
|
||||
(*r_pipe) += String::utf8(buf);
|
||||
if (p_pipe_mutex) {
|
||||
p_pipe_mutex->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int rv = _pclose(f);
|
||||
if (r_exitcode) {
|
||||
*r_exitcode = rv;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String cmdline = _quote_command_line_argument(path);
|
||||
const List<String>::Element *I = p_arguments.front();
|
||||
while (I) {
|
||||
|
@ -2871,17 +2761,62 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
|
|||
modstr.write[i] = cmdline[i];
|
||||
}
|
||||
|
||||
DWORD creation_flags = NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW;
|
||||
if (p_path == get_executable_path() && GetConsoleWindow() != NULL && _is_win11_terminal()) {
|
||||
// Open a new terminal as a workaround for Windows Terminal bug.
|
||||
creation_flags |= CREATE_NEW_CONSOLE;
|
||||
bool inherit_handles = false;
|
||||
HANDLE pipe[2] = { NULL, NULL };
|
||||
if (p_blocking && r_pipe) {
|
||||
// Create pipe for StdOut and StdErr.
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
sa.bInheritHandle = true;
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
|
||||
ERR_FAIL_COND_V(!CreatePipe(&pipe[0], &pipe[1], &sa, 0), ERR_CANT_FORK);
|
||||
ERR_FAIL_COND_V(!SetHandleInformation(pipe[0], HANDLE_FLAG_INHERIT, 0), ERR_CANT_FORK); // Read handle is for host process only and should not be inherited.
|
||||
|
||||
pi.si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
pi.si.hStdOutput = pipe[1];
|
||||
if (read_stderr) {
|
||||
pi.si.hStdError = pipe[1];
|
||||
}
|
||||
inherit_handles = true;
|
||||
}
|
||||
DWORD creaton_flags = NORMAL_PRIORITY_CLASS;
|
||||
if (p_open_console) {
|
||||
creaton_flags |= CREATE_NEW_CONSOLE;
|
||||
} else {
|
||||
creaton_flags |= CREATE_NO_WINDOW;
|
||||
}
|
||||
|
||||
int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, 0, creation_flags, NULL, NULL, si_w, &pi.pi);
|
||||
int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, inherit_handles, creaton_flags, NULL, NULL, si_w, &pi.pi);
|
||||
if (!ret && r_pipe) {
|
||||
CloseHandle(pipe[0]); // Cleanup pipe handles.
|
||||
CloseHandle(pipe[1]);
|
||||
}
|
||||
ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
|
||||
|
||||
if (p_blocking) {
|
||||
WaitForSingleObject(pi.pi.hProcess, INFINITE);
|
||||
if (r_pipe) {
|
||||
CloseHandle(pipe[1]); // Close pipe write handle (only child process is writing).
|
||||
char buf[4096];
|
||||
DWORD read = 0;
|
||||
for (;;) { // Read StdOut and StdErr from pipe.
|
||||
bool success = ReadFile(pipe[0], buf, 4096, &read, NULL);
|
||||
if (!success || read == 0) {
|
||||
break;
|
||||
}
|
||||
if (p_pipe_mutex) {
|
||||
p_pipe_mutex->lock();
|
||||
}
|
||||
(*r_pipe) += String::utf8(buf, read);
|
||||
if (p_pipe_mutex) {
|
||||
p_pipe_mutex->unlock();
|
||||
}
|
||||
};
|
||||
CloseHandle(pipe[0]); // Close pipe read handle.
|
||||
} else {
|
||||
WaitForSingleObject(pi.pi.hProcess, INFINITE);
|
||||
}
|
||||
|
||||
if (r_exitcode) {
|
||||
DWORD ret2;
|
||||
GetExitCodeProcess(pi.pi.hProcess, &ret2);
|
||||
|
@ -3689,7 +3624,6 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
|
|||
minimized = false;
|
||||
was_maximized = false;
|
||||
window_focused = true;
|
||||
console_visible = IsWindowVisible(GetConsoleWindow());
|
||||
|
||||
//Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
|
||||
HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
|
||||
|
|
|
@ -371,8 +371,6 @@ class OS_Windows : public OS {
|
|||
|
||||
CrashHandler crash_handler;
|
||||
|
||||
bool _is_win11_terminal() const;
|
||||
|
||||
void _drag_event(float p_x, float p_y, int idx);
|
||||
void _touch_event(bool p_pressed, float p_x, float p_y, int idx);
|
||||
|
||||
|
@ -414,7 +412,6 @@ protected:
|
|||
bool minimized;
|
||||
bool borderless;
|
||||
bool window_focused;
|
||||
bool console_visible;
|
||||
bool was_maximized;
|
||||
|
||||
public:
|
||||
|
@ -469,8 +466,6 @@ public:
|
|||
virtual void set_window_always_on_top(bool p_enabled);
|
||||
virtual bool is_window_always_on_top() const;
|
||||
virtual bool is_window_focused() const;
|
||||
virtual void set_console_visible(bool p_enabled);
|
||||
virtual bool is_console_visible() const;
|
||||
virtual void request_attention();
|
||||
virtual void *get_native_handle(int p_handle_type);
|
||||
|
||||
|
@ -501,7 +496,7 @@ public:
|
|||
virtual void delay_usec(uint32_t p_usec) const;
|
||||
virtual uint64_t get_ticks_usec() const;
|
||||
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL, bool p_open_console = false);
|
||||
virtual Error kill(const ProcessID &p_pid);
|
||||
virtual int get_process_id() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue