diff options
author | bruvzg <7645683+bruvzg@users.noreply.github.com> | 2021-12-16 15:00:55 +0200 |
---|---|---|
committer | bruvzg <7645683+bruvzg@users.noreply.github.com> | 2021-12-18 10:14:07 +0200 |
commit | ea5bb8b47dce95aa98f47d13ada8297670559c8b (patch) | |
tree | 17868fd701035115690b9d751a47da7858b9870f | |
parent | b0e93711b36bae3d2bb3a7e9a4a88faf055499fb (diff) |
[Windows] Improve console handling and execute/create_process.
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 `create_process`).
Add `open_console` argument to the `execute` and `create_process` to open a new console window.
Remove `interface/editor/hide_console_window` editor setting.
Remove `Toggle System Console` menu option.
Remove `set_console_visible` and `is_console_visible` functions.
29 files changed, 116 insertions, 258 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp index fe026ed38f..6dcb673286 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -224,14 +224,14 @@ 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, Array r_output, bool p_read_stderr) { +int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) { List<String> args; for (int i = 0; i < p_arguments.size(); i++) { args.push_back(p_arguments[i]); } String pipe; int exitcode = 0; - Error err = ::OS::get_singleton()->execute(p_path, args, &pipe, &exitcode, p_read_stderr); + Error err = ::OS::get_singleton()->execute(p_path, args, &pipe, &exitcode, p_read_stderr, nullptr, p_open_console); r_output.push_back(pipe); if (err != OK) { return -1; @@ -252,13 +252,13 @@ int OS::create_instance(const Vector<String> &p_arguments) { return pid; } -int OS::create_process(const String &p_path, const Vector<String> &p_arguments) { +int OS::create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console) { List<String> args; for (int i = 0; i < p_arguments.size(); i++) { args.push_back(p_arguments[i]); } ::OS::ProcessID pid = 0; - Error err = ::OS::get_singleton()->create_process(p_path, args, &pid); + Error err = ::OS::get_singleton()->create_process(p_path, args, &pid, p_open_console); if (err != OK) { return -1; } @@ -557,8 +557,8 @@ 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", "output", "read_stderr"), &OS::execute, DEFVAL(Array()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("create_process", "path", "arguments"), &OS::create_process); + ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false)); ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance); ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill); ClassDB::bind_method(D_METHOD("shell_open", "uri"), &OS::shell_open); diff --git a/core/core_bind.h b/core/core_bind.h index 6da4403880..4772c53f4f 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -164,8 +164,8 @@ public: void crash(const String &p_message); String get_executable_path() const; - int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false); - int create_process(const String &p_path, const Vector<String> &p_arguments); + int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false); + int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false); int create_instance(const Vector<String> &p_arguments); Error kill(int p_pid); Error shell_open(String p_uri); diff --git a/core/os/os.h b/core/os/os.h index 3042696cce..59a7052f42 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -149,8 +149,8 @@ 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, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0; - virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) = 0; + virtual Error execute(const String &p_path, const List<String> &p_arguments, 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 create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) = 0; virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) { return create_process(get_executable_path(), p_arguments, r_child_id); }; virtual Error kill(const ProcessID &p_pid) = 0; virtual int get_process_id() const; diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 1ca69057b4..4d7b921d96 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -35,12 +35,6 @@ [b]Note:[/b] This method is only implemented on Linux. </description> </method> - <method name="console_set_visible"> - <return type="void" /> - <argument index="0" name="console_visible" type="bool" /> - <description> - </description> - </method> <method name="create_sub_window"> <return type="int" /> <argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode" /> @@ -281,11 +275,6 @@ <description> </description> </method> - <method name="is_console_visible" qualifiers="const"> - <return type="bool" /> - <description> - </description> - </method> <method name="keyboard_get_current_layout" qualifiers="const"> <return type="int" /> <description> @@ -803,23 +792,21 @@ </constant> <constant name="FEATURE_NATIVE_DIALOG" value="9" enum="Feature"> </constant> - <constant name="FEATURE_CONSOLE_WINDOW" value="10" enum="Feature"> - </constant> - <constant name="FEATURE_IME" value="11" enum="Feature"> + <constant name="FEATURE_IME" value="10" enum="Feature"> </constant> - <constant name="FEATURE_WINDOW_TRANSPARENCY" value="12" enum="Feature"> + <constant name="FEATURE_WINDOW_TRANSPARENCY" value="11" enum="Feature"> </constant> - <constant name="FEATURE_HIDPI" value="13" enum="Feature"> + <constant name="FEATURE_HIDPI" value="12" enum="Feature"> </constant> - <constant name="FEATURE_ICON" value="14" enum="Feature"> + <constant name="FEATURE_ICON" value="13" enum="Feature"> </constant> - <constant name="FEATURE_NATIVE_ICON" value="15" enum="Feature"> + <constant name="FEATURE_NATIVE_ICON" value="14" enum="Feature"> </constant> - <constant name="FEATURE_ORIENTATION" value="16" enum="Feature"> + <constant name="FEATURE_ORIENTATION" value="15" enum="Feature"> </constant> - <constant name="FEATURE_SWAP_BUFFERS" value="17" enum="Feature"> + <constant name="FEATURE_SWAP_BUFFERS" value="16" enum="Feature"> </constant> - <constant name="FEATURE_CLIPBOARD_PRIMARY" value="19" enum="Feature"> + <constant name="FEATURE_CLIPBOARD_PRIMARY" value="18" enum="Feature"> </constant> <constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode"> Makes the mouse cursor visible if it is hidden. diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index ffc02f09a9..2be8b36822 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -51,8 +51,10 @@ <return type="int" /> <argument index="0" name="path" type="String" /> <argument index="1" name="arguments" type="PackedStringArray" /> + <argument index="2" name="open_console" type="bool" default="false" /> <description> Creates a new process that runs independently of Godot. It will not terminate if Godot terminates. The path specified in [code]path[/code] must exist and be executable file or macOS .app bundle. Platform path resolution will be used. The [code]arguments[/code] are used in the given order and separated by a space. + 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. If the process creation succeeds, the method will return the new process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process creation fails, the method will return [code]-1[/code]. For example, running another instance of the project: [codeblocks] @@ -109,8 +111,10 @@ <argument index="1" name="arguments" type="PackedStringArray" /> <argument index="2" name="output" type="Array" default="[]" /> <argument index="3" name="read_stderr" type="bool" default="false" /> + <argument index="4" name="open_console" type="bool" default="false" /> <description> Executes a command. The file specified in [code]path[/code] must exist and be executable. Platform path resolution will be used. The [code]arguments[/code] are used in the given order and separated by a space. If an [code]output[/code] [Array] is provided, the complete shell output of the process will be appended as a single [String] element in [code]output[/code]. If [code]read_stderr[/code] is [code]true[/code], the output to the standard error stream will be included too. + 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. If the command is successfully executed, the method will return the exit code of the command, or [code]-1[/code] if it fails. [b]Note:[/b] The Godot thread will pause its execution until the executed command terminates. Use [Thread] to create a separate thread that will not pause the Godot thread, or use [method create_process] to create a completely independent process. For example, to retrieve a list of the working directory's contents: @@ -124,7 +128,7 @@ int exitCode = OS.Execute("ls", new string[] {"-l", "/tmp"}, output); [/csharp] [/codeblocks] - To execute a composite command, a platform-specific shell can be invoked. For example: + If you wish to access a shell built-in or perform a composite command, a platform-specific shell can be invoked. For example: [codeblocks] [gdscript] var output = [] diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index f0c679b54e..bead5584c8 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -249,7 +249,7 @@ uint64_t OS_Unix::get_ticks_usec() const { return longtime; } -Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, 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, 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. @@ -318,7 +318,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St #endif } -Error OS_Unix::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { +Error OS_Unix::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. // Actual virtual call goes to OS_JavaScript. diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 67ee6ac856..405baac424 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -81,8 +81,8 @@ public: virtual void delay_usec(uint32_t p_usec) const override; virtual uint64_t get_ticks_usec() const override; - virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override; - virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override; + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error kill(const ProcessID &p_pid) override; virtual int get_process_id() const override; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 00a776ba4d..78e5d97135 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2852,11 +2852,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { DisplayServer::get_singleton()->window_set_mode(DisplayServer::get_singleton()->window_get_mode() == DisplayServer::WINDOW_MODE_FULLSCREEN ? DisplayServer::WINDOW_MODE_WINDOWED : DisplayServer::WINDOW_MODE_FULLSCREEN); } break; - case SETTINGS_TOGGLE_CONSOLE: { - bool was_visible = DisplayServer::get_singleton()->is_console_visible(); - DisplayServer::get_singleton()->console_set_visible(!was_visible); - EditorSettings::get_singleton()->set_setting("interface/editor/hide_console_window", was_visible); - } break; case EDITOR_SCREENSHOT: { screenshot_timer->start(); } break; @@ -6500,11 +6495,6 @@ EditorNode::EditorNode() { ED_SHORTCUT_OVERRIDE("editor/fullscreen_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::F); p->add_shortcut(ED_GET_SHORTCUT("editor/fullscreen_mode"), SETTINGS_TOGGLE_FULLSCREEN); -#if defined(WINDOWS_ENABLED) && defined(WINDOWS_SUBSYSTEM_CONSOLE) - // The console can only be toggled if the application was built for the console subsystem, - // not the GUI subsystem. - p->add_item(TTR("Toggle System Console"), SETTINGS_TOGGLE_CONSOLE); -#endif p->add_separator(); if (OS::get_singleton()->get_data_path() == OS::get_singleton()->get_config_path()) { diff --git a/editor/editor_node.h b/editor/editor_node.h index d74ec33f25..82e31b41c9 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -188,7 +188,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, diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 1ac1d6f048..a7410117d7 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -428,7 +428,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/separate_distraction_mode", false); _initial_set("interface/editor/automatically_open_screenshots", true); EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/single_window_mode", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) - _initial_set("interface/editor/hide_console_window", false); _initial_set("interface/editor/mouse_extra_buttons_navigate_history", true); _initial_set("interface/editor/save_each_scene_on_quit", true); // Regression EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/show_internal_errors_in_toast_notifications", 0, "Auto,Enabled,Disabled") diff --git a/main/main.cpp b/main/main.cpp index 805c8c2c84..80f242d4a9 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2529,13 +2529,6 @@ bool Main::start() { } if (project_manager || editor) { - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CONSOLE_WINDOW)) { - // Hide console window if requested (Windows-only). - bool hide_console = EditorSettings::get_singleton()->get_setting( - "interface/editor/hide_console_window"); - DisplayServer::get_singleton()->console_set_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()); diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 505e7ac0eb..1df118ee3f 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -47,7 +47,6 @@ DisplayServerAndroid *DisplayServerAndroid::get_singleton() { bool DisplayServerAndroid::has_feature(Feature p_feature) const { switch (p_feature) { - //case FEATURE_CONSOLE_WINDOW: case FEATURE_CURSOR_SHAPE: //case FEATURE_CUSTOM_CURSOR_SHAPE: //case FEATURE_GLOBAL_MENU: diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm index b746c60d4e..2b582e9cd7 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/iphone/display_server_iphone.mm @@ -293,7 +293,6 @@ void DisplayServerIPhone::update_gyroscope(float p_x, float p_y, float p_z) { bool DisplayServerIPhone::has_feature(Feature p_feature) const { switch (p_feature) { - // case FEATURE_CONSOLE_WINDOW: // case FEATURE_CURSOR_SHAPE: // case FEATURE_CUSTOM_CURSOR_SHAPE: // case FEATURE_GLOBAL_MENU: diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index 7648ddaf43..9b641a3fe2 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -746,7 +746,6 @@ DisplayServerJavaScript::~DisplayServerJavaScript() { bool DisplayServerJavaScript::has_feature(Feature p_feature) const { switch (p_feature) { - //case FEATURE_CONSOLE_WINDOW: //case FEATURE_GLOBAL_MENU: //case FEATURE_HIDPI: //case FEATURE_IME: diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 5da9a96a90..9b470e0ed7 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -107,11 +107,11 @@ void OS_JavaScript::finalize() { // Miscellaneous -Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, 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, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { return create_process(p_path, p_arguments); } -Error OS_JavaScript::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { +Error OS_JavaScript::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { Array args; for (const String &E : p_arguments) { args.push_back(E); diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index fbab95d33b..dfec7dca37 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -70,8 +70,8 @@ public: MainLoop *get_main_loop() const override; bool main_loop_iterate(); - Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override; - Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; + Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override; + Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; Error kill(const ProcessID &p_pid) override; int get_process_id() const override; int get_processor_count() const override; diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index 3cc0b10c5b..44901e8ce6 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -314,9 +314,6 @@ public: virtual void set_native_icon(const String &p_filename) override; virtual void set_icon(const Ref<Image> &p_icon) override; - virtual void console_set_visible(bool p_enabled) override; - virtual bool is_console_visible() const override; - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index fec5c98a99..cde00f2028 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -1480,7 +1480,6 @@ bool DisplayServerOSX::has_feature(Feature p_feature) const { case FEATURE_CURSOR_SHAPE: case FEATURE_CUSTOM_CURSOR_SHAPE: case FEATURE_NATIVE_DIALOG: - //case FEATURE_CONSOLE_WINDOW: case FEATURE_IME: case FEATURE_WINDOW_TRANSPARENCY: case FEATURE_HIDPI: @@ -3682,14 +3681,6 @@ void DisplayServerOSX::swap_buffers() { #endif } -void DisplayServerOSX::console_set_visible(bool p_enabled) { - //TODO - open terminal and redirect -} - -bool DisplayServerOSX::is_console_visible() const { - return isatty(STDIN_FILENO); -} - DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 7e02f4e154..daaaf3c18e 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -94,7 +94,7 @@ public: String get_locale() const override; virtual String get_executable_path() const override; - virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; virtual String get_unique_id() const override; //++ diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 39608bdea8..93e5fc7b79 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -497,13 +497,13 @@ Error OS_OSX::create_instance(const List<String> &p_arguments, ProcessID *r_chil if (nsappname != nil) { String path; path.parse_utf8([[[NSBundle mainBundle] bundlePath] UTF8String]); - return create_process(path, p_arguments, r_child_id); + return create_process(path, p_arguments, r_child_id, false); } else { - return create_process(get_executable_path(), p_arguments, r_child_id); + return create_process(get_executable_path(), p_arguments, r_child_id, false); } } -Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { +Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { if (@available(macOS 10.15, *)) { // Use NSWorkspace if path is an .app bundle. NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())]; @@ -542,10 +542,10 @@ Error OS_OSX::create_process(const String &p_path, const List<String> &p_argumen return err; } else { - return OS_Unix::create_process(p_path, p_arguments, r_child_id); + return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console); } } else { - return OS_Unix::create_process(p_path, p_arguments, r_child_id); + return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console); } } diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 1114f5359a..81c1474357 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -629,11 +629,11 @@ 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, 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, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { return FAILED; }; -Error OS_UWP::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { +Error OS_UWP::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { return FAILED; }; diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 0b4d6b73b6..e4d1661e13 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -195,8 +195,8 @@ 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, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr); - virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr); + virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false); + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false); virtual Error kill(const ProcessID &p_pid); virtual bool has_environment(const String &p_var) const; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index e9ecc99ef5..249a0d2e79 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -65,7 +65,7 @@ def get_opts(): # Vista support dropped after EOL due to GH-10243 ("target_win_version", "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601"), BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), - EnumVariable("windows_subsystem", "Windows subsystem", "default", ("default", "console", "gui")), + EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("gui", "console")), BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False), ("msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", None), BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed.", False), @@ -178,15 +178,6 @@ def configure_msvc(env, manual_msvc_config): # Build type - if env["tests"]: - env["windows_subsystem"] = "console" - elif env["windows_subsystem"] == "default": - # Default means we use console for debug, gui for release. - if "debug" in env["target"]: - env["windows_subsystem"] = "console" - else: - env["windows_subsystem"] = "gui" - if env["target"] == "release": if env["optimize"] == "speed": # optimize for speed (default) env.Append(CCFLAGS=["/O2"]) @@ -326,15 +317,6 @@ def configure_mingw(env): ## Build type - if env["tests"]: - env["windows_subsystem"] = "console" - elif env["windows_subsystem"] == "default": - # Default means we use console for debug, gui for release. - if "debug" in env["target"]: - env["windows_subsystem"] = "console" - else: - env["windows_subsystem"] = "gui" - if env["target"] == "release": env.Append(CCFLAGS=["-msse2"]) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index f83029e662..ac07ff9529 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -68,7 +68,6 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const { case FEATURE_CLIPBOARD: case FEATURE_CURSOR_SHAPE: case FEATURE_CUSTOM_CURSOR_SHAPE: - case FEATURE_CONSOLE_WINDOW: case FEATURE_IME: case FEATURE_WINDOW_TRANSPARENCY: case FEATURE_HIDPI: @@ -1198,23 +1197,6 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI ImmReleaseContext(wd.hWnd, himc); } -void DisplayServerWindows::console_set_visible(bool p_enabled) { - _THREAD_SAFE_METHOD_ - - if (console_visible == p_enabled) { - return; - } - if (!((OS_Windows *)OS::get_singleton())->_is_win11_terminal()) { - // GetConsoleWindow is not supported by the Windows Terminal. - ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE); - console_visible = p_enabled; - } -} - -bool DisplayServerWindows::is_console_visible() const { - return console_visible; -} - void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) { _THREAD_SAFE_METHOD_ @@ -3246,7 +3228,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win shift_mem = false; control_mem = false; meta_mem = false; - console_visible = IsWindowVisible(GetConsoleWindow()); hInstance = ((OS_Windows *)OS::get_singleton())->get_hinstance(); pressrc = 0; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index a59f8ebb44..eebe3c8715 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -414,7 +414,6 @@ class DisplayServerWindows : public DisplayServer { bool use_raw_input = false; bool drop_events = false; bool in_dispatch_input_event = false; - bool console_visible = false; WNDCLASSEXW wc; @@ -477,7 +476,7 @@ public: virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override; virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override; - virtual void gl_window_make_current(DisplayServer::WindowID p_window_id); + virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override; virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; @@ -529,9 +528,6 @@ public: virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; - virtual void console_set_visible(bool p_enabled) override; - virtual bool is_console_visible() const override; - virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index bb6a077a5d..f714ede62c 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -52,8 +52,6 @@ #include <regstr.h> #include <shlobj.h> -static const WORD MAX_CONSOLE_LINES = 1500; - extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 1; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; @@ -86,65 +84,17 @@ static String format_error_message(DWORD id) { } void RedirectIOToConsole() { - int hConHandle; - - intptr_t lStdHandle; - - 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, nullptr, _IONBF, 0); - - // redirect unbuffered STDIN to the console - - lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE); + if (AttachConsole(ATTACH_PARENT_PROCESS)) { + FILE *fpstdin = stdin; + FILE *fpstdout = stdout; + FILE *fpstderr = stderr; - hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + freopen_s(&fpstdin, "CONIN$", "r", stdin); + freopen_s(&fpstdout, "CONOUT$", "w", stdout); + freopen_s(&fpstderr, "CONOUT$", "w", stderr); - fp = _fdopen(hConHandle, "r"); - - *stdin = *fp; - - setvbuf(stdin, nullptr, _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, nullptr, _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) { @@ -172,7 +122,9 @@ void OS_Windows::initialize_debugging() { void OS_Windows::initialize() { crash_handler.initialize(); - //RedirectIOToConsole(); +#ifndef WINDOWS_SUBSYSTEM_CONSOLE + RedirectIOToConsole(); +#endif FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA); @@ -406,78 +358,87 @@ 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, 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, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { String path = p_path.replace("/", "\\"); String command = _quote_command_line_argument(path); for (const String &E : p_arguments) { command += " " + _quote_command_line_argument(E); } + ProcessInfo pi; + ZeroMemory(&pi.si, sizeof(pi.si)); + pi.si.cb = sizeof(pi.si); + ZeroMemory(&pi.pi, sizeof(pi.pi)); + LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si; + + bool inherit_handles = false; + HANDLE pipe[2] = { nullptr, nullptr }; if (r_pipe) { + // Create pipe for StdOut and StdErr. + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = true; + sa.lpSecurityDescriptor = nullptr; + + 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) { - command += " 2>&1"; // Include stderr + pi.si.hStdError = pipe[1]; } - // Add extra quotes around the full command, to prevent it from stripping quotes in the command, - // because _wpopen calls command as "cmd.exe /c command", instead of executing it directly - command = _quote_command_line_argument(command); - - FILE *f = _wpopen((LPCWSTR)(command.utf16().get_data()), L"r"); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot create pipe from command: " + command); - char buf[65535]; - while (fgets(buf, 65535, f)) { + 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(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, inherit_handles, creaton_flags, nullptr, nullptr, si_w, &pi.pi); + if (!ret && r_pipe) { + CloseHandle(pipe[0]); // Cleanup pipe handles. + CloseHandle(pipe[1]); + } + ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command); + + 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); + (*r_pipe) += String::utf8(buf, read); if (p_pipe_mutex) { p_pipe_mutex->unlock(); } - } - int rv = _pclose(f); - - if (r_exitcode) { - *r_exitcode = rv; - } - return OK; + }; + CloseHandle(pipe[0]); // Close pipe read handle. + } else { + WaitForSingleObject(pi.pi.hProcess, INFINITE); } - ProcessInfo pi; - ZeroMemory(&pi.si, sizeof(pi.si)); - pi.si.cb = sizeof(pi.si); - ZeroMemory(&pi.pi, sizeof(pi.pi)); - LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si; - - DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS; -#ifndef DEBUG_ENABLED - dwCreationFlags |= CREATE_NO_WINDOW; -#endif - - int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, dwCreationFlags, nullptr, nullptr, si_w, &pi.pi); - ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command); - - WaitForSingleObject(pi.pi.hProcess, INFINITE); if (r_exitcode) { DWORD ret2; GetExitCodeProcess(pi.pi.hProcess, &ret2); *r_exitcode = ret2; } + CloseHandle(pi.pi.hProcess); CloseHandle(pi.pi.hThread); return OK; }; -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; - } -} - -Error OS_Windows::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { +Error OS_Windows::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { String path = p_path.replace("/", "\\"); String command = _quote_command_line_argument(path); for (const String &E : p_arguments) { @@ -490,16 +451,14 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg ZeroMemory(&pi.pi, sizeof(pi.pi)); LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si; - DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS; -#ifndef DEBUG_ENABLED - dwCreationFlags |= CREATE_NO_WINDOW; -#endif - if (p_path == get_executable_path() && GetConsoleWindow() != nullptr && _is_win11_terminal()) { - // Open a new terminal as a workaround for Windows Terminal bug. - dwCreationFlags |= CREATE_NEW_CONSOLE; + DWORD creaton_flags = NORMAL_PRIORITY_CLASS; + if (p_open_console) { + creaton_flags |= CREATE_NEW_CONSOLE; + } else { + creaton_flags |= CREATE_NO_WINDOW; } - int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, dwCreationFlags, nullptr, nullptr, si_w, &pi.pi); + int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, creaton_flags, nullptr, nullptr, si_w, &pi.pi); ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command); ProcessID pid = pi.pi.dwProcessId; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 086f63eb3e..d9504fcd0c 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -128,8 +128,8 @@ public: virtual void delay_usec(uint32_t p_usec) const override; virtual uint64_t get_ticks_usec() const override; - virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override; - virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override; + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error kill(const ProcessID &p_pid) override; virtual int get_process_id() const override; @@ -157,7 +157,6 @@ public: void run(); - bool _is_win11_terminal() const; virtual bool _check_internal_feature_support(const String &p_feature) override; virtual void disable_crash_handler() override; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 8b5a965738..af4b6a4e62 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -228,14 +228,6 @@ String DisplayServer::ime_get_text() const { ERR_FAIL_V_MSG(String(), "IME or NOTIFICATION_WM_IME_UPDATEnot supported by this display server."); } -void DisplayServer::console_set_visible(bool p_enabled) { - WARN_PRINT("Console window not supported by this display server."); -} - -bool DisplayServer::is_console_visible() const { - return false; -} - void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { WARN_PRINT("Virtual keyboard not supported by this display server."); } @@ -446,9 +438,6 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection); ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text); - ClassDB::bind_method(D_METHOD("console_set_visible", "console_visible"), &DisplayServer::console_set_visible); - ClassDB::bind_method(D_METHOD("is_console_visible"), &DisplayServer::is_console_visible); - ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "multiline", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()), DEFVAL(false), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("virtual_keyboard_hide"), &DisplayServer::virtual_keyboard_hide); @@ -493,7 +482,6 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_CURSOR_SHAPE); BIND_ENUM_CONSTANT(FEATURE_CUSTOM_CURSOR_SHAPE); BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG); - BIND_ENUM_CONSTANT(FEATURE_CONSOLE_WINDOW); BIND_ENUM_CONSTANT(FEATURE_IME); BIND_ENUM_CONSTANT(FEATURE_WINDOW_TRANSPARENCY); BIND_ENUM_CONSTANT(FEATURE_HIDPI); diff --git a/servers/display_server.h b/servers/display_server.h index 2d837dbef9..53e28f3198 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -105,7 +105,6 @@ public: FEATURE_CURSOR_SHAPE, FEATURE_CUSTOM_CURSOR_SHAPE, FEATURE_NATIVE_DIALOG, - FEATURE_CONSOLE_WINDOW, FEATURE_IME, FEATURE_WINDOW_TRANSPARENCY, FEATURE_HIDPI, @@ -304,9 +303,6 @@ public: virtual Point2i ime_get_selection() const; virtual String ime_get_text() const; - virtual void console_set_visible(bool p_enabled); - virtual bool is_console_visible() const; - virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); virtual void virtual_keyboard_hide(); |