diff --git a/core/core_bind.cpp b/core/core_bind.cpp index fe026ed38f5f..6dcb673286a6 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 &p_arguments, Array r_output, bool p_read_stderr) { +int OS::execute(const String &p_path, const Vector &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) { List 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 &p_arguments) { return pid; } -int OS::create_process(const String &p_path, const Vector &p_arguments) { +int OS::create_process(const String &p_path, const Vector &p_arguments, bool p_open_console) { List 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 6da440388084..4772c53f4f5f 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 &p_arguments, Array r_output = Array(), bool p_read_stderr = false); - int create_process(const String &p_path, const Vector &p_arguments); + int execute(const String &p_path, const Vector &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 &p_arguments, bool p_open_console = false); int create_instance(const Vector &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 3042696ccee9..59a7052f4253 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 &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 &p_arguments, ProcessID *r_child_id = nullptr) = 0; + virtual Error execute(const String &p_path, const List &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 &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) = 0; virtual Error create_instance(const List &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 1ca69057b411..4d7b921d96f7 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. - - - - - - @@ -281,11 +275,6 @@ - - - - - @@ -803,23 +792,21 @@ - + - + - + - + - + - + - + - - - + Makes the mouse cursor visible if it is hidden. diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index ffc02f09a988..2be8b368221b 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -51,8 +51,10 @@ + 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 @@ + 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 f0c679b54e57..bead5584c83b 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 &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 &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 &p_arguments, St #endif } -Error OS_Unix::create_process(const String &p_path, const List &p_arguments, ProcessID *r_child_id) { +Error OS_Unix::create_process(const String &p_path, const List &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 67ee6ac8564b..405baac424c4 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 &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 &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error execute(const String &p_path, const List &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 &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 00a776ba4df6..78e5d9713570 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 d74ec33f2598..82e31b41c928 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 1ac1d6f048a8..a7410117d725 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -428,7 +428,6 @@ void EditorSettings::_load_defaults(Ref 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 805c8c2c84bf..80f242d4a99f 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 505e7ac0eb02..1df118ee3fec 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 b746c60d4ece..2b582e9cd78c 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 7648ddaf43ef..9b641a3fe2fa 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 5da9a96a90cf..9b470e0ed717 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 &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 &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 &p_arguments, ProcessID *r_child_id) { +Error OS_JavaScript::create_process(const String &p_path, const List &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 fbab95d33bd8..dfec7dca37e5 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 &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 &p_arguments, ProcessID *r_child_id = nullptr) override; + Error execute(const String &p_path, const List &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 &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 3cc0b10c5bae..44901e8ce660 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 &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 get_rendering_drivers_func(); diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index fec5c98a9915..cde00f202868 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 7e02f4e154df..daaaf3c18e83 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 &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error create_process(const String &p_path, const List &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error create_instance(const List &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 39608bdea8c1..93e5fc7b7914 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -497,13 +497,13 @@ Error OS_OSX::create_instance(const List &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 &p_arguments, ProcessID *r_child_id) { +Error OS_OSX::create_process(const String &p_path, const List &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 &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 1114f5359a93..81c14743575a 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 &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 &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 &p_arguments, ProcessID *r_child_id) { +Error OS_UWP::create_process(const String &p_path, const List &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 0b4d6b73b64c..e4d1661e13aa 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 &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 &p_arguments, ProcessID *r_child_id = nullptr); + virtual Error execute(const String &p_path, const List &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 &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 e9ecc99ef581..249a0d2e7934 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 f83029e662d3..ac07ff952962 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 a59f8ebb4415..eebe3c871523 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 bb6a077a5d63..f714ede62c38 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -52,8 +52,6 @@ #include #include -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; + 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, nullptr, _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, 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(FileAccess::ACCESS_RESOURCES); FileAccess::make_default(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 &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 &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); } - if (r_pipe) { - if (read_stderr) { - command += " 2>&1"; // Include stderr - } - // 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)) { - 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; - } - 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 + 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; - int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, dwCreationFlags, nullptr, nullptr, si_w, &pi.pi); + 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(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); - 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); *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 &p_arguments, ProcessID *r_child_id) { +Error OS_Windows::create_process(const String &p_path, const List &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 &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 086f63eb3e39..d9504fcd0cb3 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 &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 &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error execute(const String &p_path, const List &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 &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 8b5a965738fa..af4b6a4e62fc 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 2d837dbef90f..53e28f31984c 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();