[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.
This commit is contained in:
bruvzg 2021-12-16 15:00:55 +02:00
parent b0e93711b3
commit ea5bb8b47d
No known key found for this signature in database
GPG key ID: 7960FCF39844EC38
29 changed files with 118 additions and 260 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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 name="FEATURE_IME" value="10" enum="Feature">
</constant>
<constant name="FEATURE_IME" value="11" enum="Feature">
<constant name="FEATURE_WINDOW_TRANSPARENCY" value="11" enum="Feature">
</constant>
<constant name="FEATURE_WINDOW_TRANSPARENCY" value="12" enum="Feature">
<constant name="FEATURE_HIDPI" value="12" enum="Feature">
</constant>
<constant name="FEATURE_HIDPI" value="13" enum="Feature">
<constant name="FEATURE_ICON" value="13" enum="Feature">
</constant>
<constant name="FEATURE_ICON" value="14" enum="Feature">
<constant name="FEATURE_NATIVE_ICON" value="14" enum="Feature">
</constant>
<constant name="FEATURE_NATIVE_ICON" value="15" enum="Feature">
<constant name="FEATURE_ORIENTATION" value="15" enum="Feature">
</constant>
<constant name="FEATURE_ORIENTATION" value="16" enum="Feature">
<constant name="FEATURE_SWAP_BUFFERS" value="16" enum="Feature">
</constant>
<constant name="FEATURE_SWAP_BUFFERS" value="17" 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.

View file

@ -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 = []

View file

@ -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.

View file

@ -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;

View file

@ -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()) {

View file

@ -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,

View file

@ -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")

View file

@ -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());

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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);

View file

@ -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; //++

View file

@ -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);
}
}

View file

@ -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;
};

View file

@ -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;

View file

@ -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"])

View file

@ -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;

View file

@ -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;

View file

@ -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;
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<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);
}
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<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;

View file

@ -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;

View file

@ -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);

View file

@ -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();