diff options
Diffstat (limited to 'platform/windows')
-rw-r--r-- | platform/windows/SCsub | 4 | ||||
-rw-r--r-- | platform/windows/crash_handler_windows.h | 2 | ||||
-rw-r--r-- | platform/windows/crash_handler_windows_signal.cpp | 2 | ||||
-rw-r--r-- | platform/windows/detect.py | 178 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 104 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 7 | ||||
-rw-r--r-- | platform/windows/drop_target_windows.cpp | 375 | ||||
-rw-r--r-- | platform/windows/drop_target_windows.h | 77 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.h | 2 | ||||
-rw-r--r-- | platform/windows/godot.natvis | 191 | ||||
-rw-r--r-- | platform/windows/joypad_windows.cpp | 3 | ||||
-rw-r--r-- | platform/windows/native_menu_windows.cpp | 6 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 50 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 2 | ||||
-rw-r--r-- | platform/windows/platform_windows_builders.py | 18 | ||||
-rw-r--r-- | platform/windows/windows_utils.cpp | 4 |
16 files changed, 811 insertions, 214 deletions
diff --git a/platform/windows/SCsub b/platform/windows/SCsub index 1d17e7b325..eaa5ceff88 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -24,6 +24,7 @@ common_win = [ "gl_manager_windows_angle.cpp", "wgl_detect_version.cpp", "rendering_context_driver_vulkan_windows.cpp", + "drop_target_windows.cpp", ] if env.msvc: @@ -59,6 +60,9 @@ sources += res_obj prog = env.add_program("#bin/godot", sources, PROGSUFFIX=env["PROGSUFFIX"]) arrange_program_clean(prog) +if env.msvc: + env.Depends(prog, "godot.natvis") + # Build console wrapper app. if env["windows_subsystem"] == "gui": env_wrap = env.Clone() diff --git a/platform/windows/crash_handler_windows.h b/platform/windows/crash_handler_windows.h index a0a0b610d0..f47d9ec66e 100644 --- a/platform/windows/crash_handler_windows.h +++ b/platform/windows/crash_handler_windows.h @@ -51,7 +51,7 @@ public: void initialize(); void disable(); - bool is_disabled() const { return disabled; }; + bool is_disabled() const { return disabled; } CrashHandler(); ~CrashHandler(); diff --git a/platform/windows/crash_handler_windows_signal.cpp b/platform/windows/crash_handler_windows_signal.cpp index e11a60bdc7..c3a0d08ad6 100644 --- a/platform/windows/crash_handler_windows_signal.cpp +++ b/platform/windows/crash_handler_windows_signal.cpp @@ -159,7 +159,7 @@ extern void CrashHandlerException(int signal) { // Load process and image info to determine ASLR addresses offset. MODULEINFO mi; - GetModuleInformation(GetCurrentProcess(), GetModuleHandle(NULL), &mi, sizeof(mi)); + GetModuleInformation(GetCurrentProcess(), GetModuleHandle(nullptr), &mi, sizeof(mi)); int64_t image_mem_base = reinterpret_cast<int64_t>(mi.lpBaseOfDll); int64_t image_file_base = get_image_base(_execpath); data.offset = image_mem_base - image_file_base; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 0ee52a09a7..e1109db24f 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING import methods from methods import print_error, print_warning -from platform_methods import detect_arch +from platform_methods import detect_arch, validate_arch if TYPE_CHECKING: from SCons.Script.SConscript import SConsEnvironment @@ -68,23 +68,23 @@ def can_build(): def get_mingw_bin_prefix(prefix, arch): - if not prefix: - mingw_bin_prefix = "" - elif prefix[-1] != "/": - mingw_bin_prefix = prefix + "/bin/" - else: - mingw_bin_prefix = prefix + "bin/" + bin_prefix = (os.path.normpath(os.path.join(prefix, "bin")) + os.sep) if prefix else "" + ARCH_PREFIXES = { + "x86_64": "x86_64-w64-mingw32-", + "x86_32": "i686-w64-mingw32-", + "arm32": "armv7-w64-mingw32-", + "arm64": "aarch64-w64-mingw32-", + } + arch_prefix = ARCH_PREFIXES[arch] if arch else "" + return bin_prefix + arch_prefix - if arch == "x86_64": - mingw_bin_prefix += "x86_64-w64-mingw32-" - elif arch == "x86_32": - mingw_bin_prefix += "i686-w64-mingw32-" - elif arch == "arm32": - mingw_bin_prefix += "armv7-w64-mingw32-" - elif arch == "arm64": - mingw_bin_prefix += "aarch64-w64-mingw32-" - return mingw_bin_prefix +def get_detected(env: "SConsEnvironment", tool: str) -> str: + checks = [ + get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) + tool, + get_mingw_bin_prefix(env["mingw_prefix"], "") + tool, + ] + return str(env.Detect(checks)) def detect_build_env_arch(): @@ -245,41 +245,6 @@ def get_flags(): } -def build_res_file(target, source, env: "SConsEnvironment"): - arch_aliases = { - "x86_32": "pe-i386", - "x86_64": "pe-x86-64", - "arm32": "armv7-w64-mingw32", - "arm64": "aarch64-w64-mingw32", - } - cmdbase = "windres --include-dir . --target=" + arch_aliases[env["arch"]] - - mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) - - for x in range(len(source)): - ok = True - # Try prefixed executable (MinGW on Linux). - cmd = mingw_bin_prefix + cmdbase + " -i " + str(source[x]) + " -o " + str(target[x]) - try: - out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate() - if len(out[1]): - ok = False - except Exception: - ok = False - - # Try generic executable (MSYS2). - if not ok: - cmd = cmdbase + " -i " + str(source[x]) + " -o " + str(target[x]) - try: - out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate() - if len(out[1]): - return -1 - except Exception: - return -1 - - return 0 - - def setup_msvc_manual(env: "SConsEnvironment"): """Running from VCVARS environment""" @@ -361,6 +326,10 @@ def setup_mingw(env: "SConsEnvironment"): print_error("No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.") sys.exit(255) + env.Tool("mingw") + env.AppendUnique(CCFLAGS=env.get("ccflags", "").split()) + env.AppendUnique(RCFLAGS=env.get("rcflags", "").split()) + print("Using MinGW, arch %s" % (env["arch"])) @@ -483,9 +452,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): else: print_warning("Missing environment variable: WindowsSdkDir") - if int(env["target_win_version"], 16) < 0x0601: - print_error("`target_win_version` should be 0x0601 or higher (Windows 7).") - sys.exit(255) + validate_win_version(env) env.AppendUnique( CPPDEFINES=[ @@ -549,15 +516,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): LIBS += ["vulkan"] if env["d3d12"]: - # Check whether we have d3d12 dependencies installed. - if not os.path.exists(env["mesa_libs"]): - print_error( - "The Direct3D 12 rendering driver requires dependencies to be installed.\n" - "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n" - "See the documentation for more information:\n\t" - "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html" - ) - sys.exit(255) + check_d3d12_installed(env) env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) LIBS += ["dxgi", "dxguid"] @@ -716,6 +675,13 @@ def configure_mingw(env: "SConsEnvironment"): # https://www.scons.org/wiki/LongCmdLinesOnWin32 env.use_windows_spawn_fix() + # HACK: For some reason, Windows-native shells have their MinGW tools + # frequently fail as a result of parsing path separators incorrectly. + # For some other reason, this issue is circumvented entirely if the + # `mingw_prefix` bin is prepended to PATH. + if os.sep == "\\": + env.PrependENVPath("PATH", os.path.join(env["mingw_prefix"], "bin")) + # In case the command line to AR is too long, use a response file. env["ARCOM_ORIG"] = env["ARCOM"] env["ARCOM"] = "${TEMPFILE('$ARCOM_ORIG', '$ARCOMSTR')}" @@ -753,9 +719,6 @@ def configure_mingw(env: "SConsEnvironment"): ## Compiler configuration - if os.name != "nt": - env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation - if env["arch"] == "x86_32": if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static"]) @@ -770,29 +733,31 @@ def configure_mingw(env: "SConsEnvironment"): env.Append(CCFLAGS=["-ffp-contract=off"]) - mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) - if env["use_llvm"]: - env["CC"] = mingw_bin_prefix + "clang" - env["CXX"] = mingw_bin_prefix + "clang++" - if try_cmd("as --version", env["mingw_prefix"], env["arch"]): - env["AS"] = mingw_bin_prefix + "as" - env.Append(ASFLAGS=["-c"]) - if try_cmd("ar --version", env["mingw_prefix"], env["arch"]): - env["AR"] = mingw_bin_prefix + "ar" - if try_cmd("ranlib --version", env["mingw_prefix"], env["arch"]): - env["RANLIB"] = mingw_bin_prefix + "ranlib" + env["CC"] = get_detected(env, "clang") + env["CXX"] = get_detected(env, "clang++") + env["AR"] = get_detected(env, "ar") + env["RANLIB"] = get_detected(env, "ranlib") + env.Append(ASFLAGS=["-c"]) env.extra_suffix = ".llvm" + env.extra_suffix else: - env["CC"] = mingw_bin_prefix + "gcc" - env["CXX"] = mingw_bin_prefix + "g++" - if try_cmd("as --version", env["mingw_prefix"], env["arch"]): - env["AS"] = mingw_bin_prefix + "as" - ar = "ar" if os.name == "nt" else "gcc-ar" - if try_cmd(f"{ar} --version", env["mingw_prefix"], env["arch"]): - env["AR"] = mingw_bin_prefix + ar - if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]): - env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib" + env["CC"] = get_detected(env, "gcc") + env["CXX"] = get_detected(env, "g++") + env["AR"] = get_detected(env, "gcc-ar" if os.name != "nt" else "ar") + env["RANLIB"] = get_detected(env, "gcc-ranlib") + + env["RC"] = get_detected(env, "windres") + ARCH_TARGETS = { + "x86_32": "pe-i386", + "x86_64": "pe-x86-64", + "arm32": "armv7-w64-mingw32", + "arm64": "aarch64-w64-mingw32", + } + env.AppendUnique(RCFLAGS=f"--target={ARCH_TARGETS[env['arch']]}") + + env["AS"] = get_detected(env, "as") + env["OBJCOPY"] = get_detected(env, "objcopy") + env["STRIP"] = get_detected(env, "strip") ## LTO @@ -820,9 +785,7 @@ def configure_mingw(env: "SConsEnvironment"): ## Compile flags - if int(env["target_win_version"], 16) < 0x0601: - print_error("`target_win_version` should be 0x0601 or higher (Windows 7).") - sys.exit(255) + validate_win_version(env) if not env["use_llvm"]: env.Append(CCFLAGS=["-mwindows"]) @@ -900,15 +863,7 @@ def configure_mingw(env: "SConsEnvironment"): env.Append(LIBS=["vulkan"]) if env["d3d12"]: - # Check whether we have d3d12 dependencies installed. - if not os.path.exists(env["mesa_libs"]): - print_error( - "The Direct3D 12 rendering driver requires dependencies to be installed.\n" - "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n" - "See the documentation for more information:\n\t" - "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html" - ) - sys.exit(255) + check_d3d12_installed(env) env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) env.Append(LIBS=["dxgi", "dxguid"]) @@ -944,19 +899,11 @@ def configure_mingw(env: "SConsEnvironment"): env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)]) - # resrc - env.Append(BUILDERS={"RES": env.Builder(action=build_res_file, suffix=".o", src_suffix=".rc")}) - def configure(env: "SConsEnvironment"): # Validate arch. supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] - if env["arch"] not in supported_arches: - print_error( - 'Unsupported CPU architecture "%s" for Windows. Supported architectures are: %s.' - % (env["arch"], ", ".join(supported_arches)) - ) - sys.exit(255) + validate_arch(env["arch"], get_name(), supported_arches) # At this point the env has been set up with basic tools/compilers. env.Prepend(CPPPATH=["#platform/windows"]) @@ -984,3 +931,20 @@ def configure(env: "SConsEnvironment"): else: # MinGW configure_mingw(env) + + +def check_d3d12_installed(env): + if not os.path.exists(env["mesa_libs"]): + print_error( + "The Direct3D 12 rendering driver requires dependencies to be installed.\n" + "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n" + "See the documentation for more information:\n\t" + "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html" + ) + sys.exit(255) + + +def validate_win_version(env): + if int(env["target_win_version"], 16) < 0x0601: + print_error("`target_win_version` should be 0x0601 or higher (Windows 7).") + sys.exit(255) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 21b318ee4d..a6eab1bd29 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -30,6 +30,7 @@ #include "display_server_windows.h" +#include "drop_target_windows.h" #include "os_windows.h" #include "wgl_detect_version.h" @@ -129,6 +130,7 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const { case FEATURE_NATIVE_DIALOG: case FEATURE_NATIVE_DIALOG_INPUT: case FEATURE_NATIVE_DIALOG_FILE: + case FEATURE_NATIVE_DIALOG_FILE_EXTRA: case FEATURE_SWAP_BUFFERS: case FEATURE_KEEP_SCREEN_ON: case FEATURE_TEXT_TO_SPEECH: @@ -316,8 +318,8 @@ public: } // IFileDialogEvents methods - HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *) { return S_OK; }; - HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog *) { return S_OK; }; + HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *) { return S_OK; } + HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog *) { return S_OK; } HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialog *p_pfd, IShellItem *p_item) { if (root.is_empty()) { @@ -336,11 +338,11 @@ public: return S_OK; } - HRESULT STDMETHODCALLTYPE OnHelp(IFileDialog *) { return S_OK; }; - HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog *) { return S_OK; }; - HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; }; - HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog *pfd) { return S_OK; }; - HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; }; + HRESULT STDMETHODCALLTYPE OnHelp(IFileDialog *) { return S_OK; } + HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog *) { return S_OK; } + HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; } + HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog *pfd) { return S_OK; } + HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; } // IFileDialogControlEvents methods HRESULT STDMETHODCALLTYPE OnItemSelected(IFileDialogCustomize *p_pfdc, DWORD p_ctl_id, DWORD p_item_idx) { @@ -350,14 +352,14 @@ public: return S_OK; } - HRESULT STDMETHODCALLTYPE OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; }; + HRESULT STDMETHODCALLTYPE OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; } HRESULT STDMETHODCALLTYPE OnCheckButtonToggled(IFileDialogCustomize *p_pfdc, DWORD p_ctl_id, BOOL p_checked) { if (ctls.has(p_ctl_id)) { selected[ctls[p_ctl_id]] = (bool)p_checked; } return S_OK; } - HRESULT STDMETHODCALLTYPE OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; }; + HRESULT STDMETHODCALLTYPE OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; } Dictionary get_selected() { return selected; @@ -734,7 +736,7 @@ Error DisplayServerWindows::_file_dialog_with_options_show(const String &p_title GetWindowRect(fd->hwnd_owner, &crect); fd->wrect = Rect2i(crect.left, crect.top, crect.right - crect.left, crect.bottom - crect.top); } else { - fd->hwnd_owner = 0; + fd->hwnd_owner = nullptr; fd->wrect = Rect2i(CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT); } fd->appid = appname; @@ -1616,11 +1618,17 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { } #endif - if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window].wtctx) { - wintab_WTClose(windows[p_window].wtctx); - windows[p_window].wtctx = nullptr; + if ((tablet_get_current_driver() == "wintab") && wintab_available && wd.wtctx) { + wintab_WTClose(wd.wtctx); + wd.wtctx = nullptr; + } + + if (wd.drop_target != nullptr) { + RevokeDragDrop(wd.hWnd); + wd.drop_target->Release(); } - DestroyWindow(windows[p_window].hWnd); + + DestroyWindow(wd.hWnd); windows.erase(p_window); if (last_focused_window == p_window) { @@ -1665,6 +1673,18 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type, } return 0; } + case EGL_DISPLAY: { + if (gl_manager_angle) { + return (int64_t)gl_manager_angle->get_display(p_window); + } + return 0; + } + case EGL_CONFIG: { + if (gl_manager_angle) { + return (int64_t)gl_manager_angle->get_config(p_window); + } + return 0; + } #endif default: { return 0; @@ -1718,7 +1738,14 @@ void DisplayServerWindows::window_set_drop_files_callback(const Callable &p_call _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); - windows[p_window].drop_files_callback = p_callable; + WindowData &window_data = windows[p_window]; + + window_data.drop_files_callback = p_callable; + + if (window_data.drop_target == nullptr) { + window_data.drop_target = memnew(DropTargetWindows(&window_data)); + ERR_FAIL_COND(RegisterDragDrop(window_data.hWnd, window_data.drop_target) != S_OK); + } } void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_window) { @@ -5307,32 +5334,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } } break; - case WM_DROPFILES: { - HDROP hDropInfo = (HDROP)wParam; - const int buffsize = 4096; - WCHAR buf[buffsize]; - - int fcount = DragQueryFileW(hDropInfo, 0xFFFFFFFF, nullptr, 0); - - Vector<String> files; - - for (int i = 0; i < fcount; i++) { - DragQueryFileW(hDropInfo, i, buf, buffsize); - String file = String::utf16((const char16_t *)buf); - files.push_back(file); - } - - if (files.size() && windows[window_id].drop_files_callback.is_valid()) { - Variant v_files = files; - const Variant *v_args[1] = { &v_files }; - Variant ret; - Callable::CallError ce; - windows[window_id].drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce); - if (ce.error != Callable::CallError::CALL_OK) { - ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(windows[window_id].drop_files_callback, v_args, 1, ce))); - } - } - } break; default: { if (user_proc) { return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam); @@ -5437,7 +5438,7 @@ void DisplayServerWindows::_process_key_events() { k->set_physical_keycode(physical_keycode); k->set_key_label(key_label); k->set_unicode(fix_unicode(unicode)); - if (k->get_unicode() && ke.altgr) { + if (k->get_unicode() && ke.altgr && windows[ke.window_id].ime_active) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } @@ -5513,7 +5514,7 @@ void DisplayServerWindows::_process_key_events() { } k->set_unicode(fix_unicode(unicode)); } - if (k->get_unicode() && ke.altgr) { + if (k->get_unicode() && ke.altgr && windows[ke.window_id].ime_active) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } @@ -6161,6 +6162,8 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win FreeLibrary(comctl32); } + OleInitialize(nullptr); + memset(&wc, 0, sizeof(WNDCLASSEXW)); wc.cbSize = sizeof(WNDCLASSEXW); wc.style = CS_OWNDC | CS_DBLCLKS; @@ -6226,6 +6229,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } } #endif +#if defined(GLES3_ENABLED) bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); if (failed && fallback_to_opengl3 && rendering_driver != "opengl3") { memdelete(rendering_context); @@ -6237,6 +6241,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); failed = false; } +#endif if (failed) { memdelete(rendering_context); rendering_context = nullptr; @@ -6400,7 +6405,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), false, INVALID_WINDOW_ID); - ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); + if (main_window == INVALID_WINDOW_ID) { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Failed to create main window."); + } joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); @@ -6588,6 +6596,12 @@ DisplayServerWindows::~DisplayServerWindows() { wintab_WTClose(windows[MAIN_WINDOW_ID].wtctx); windows[MAIN_WINDOW_ID].wtctx = nullptr; } + + if (windows[MAIN_WINDOW_ID].drop_target != nullptr) { + RevokeDragDrop(windows[MAIN_WINDOW_ID].hWnd); + windows[MAIN_WINDOW_ID].drop_target->Release(); + } + DestroyWindow(windows[MAIN_WINDOW_ID].hWnd); } @@ -6619,4 +6633,6 @@ DisplayServerWindows::~DisplayServerWindows() { if (tts) { memdelete(tts); } + + OleUninitialize(); } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index fc72e05b1d..0462d3f8fa 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -357,9 +357,13 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS { SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2, } SHC_PROCESS_DPI_AWARENESS; +class DropTargetWindows; + class DisplayServerWindows : public DisplayServer { // No need to register with GDCLASS, it's platform-specific and nothing is added. + friend class DropTargetWindows; + _THREAD_SAFE_CLASS_ // UXTheme API @@ -521,6 +525,9 @@ class DisplayServerWindows : public DisplayServer { Callable input_text_callback; Callable drop_files_callback; + // OLE API + DropTargetWindows *drop_target = nullptr; + WindowID transient_parent = INVALID_WINDOW_ID; HashSet<WindowID> transient_children; diff --git a/platform/windows/drop_target_windows.cpp b/platform/windows/drop_target_windows.cpp new file mode 100644 index 0000000000..d04924a9cf --- /dev/null +++ b/platform/windows/drop_target_windows.cpp @@ -0,0 +1,375 @@ +/**************************************************************************/ +/* drop_target_windows.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "drop_target_windows.h" + +#include "core/io/dir_access.h" +#include "core/math/random_pcg.h" +#include "core/os/time.h" + +#include <fileapi.h> + +// Helpers + +static String create_temp_dir() { + Char16String buf; + int bufsize = GetTempPathW(0, nullptr) + 1; + buf.resize(bufsize); + if (GetTempPathW(bufsize, (LPWSTR)buf.ptrw()) == 0) { + return ""; + } + + String tmp_dir = String::utf16((const char16_t *)buf.ptr()); + RandomPCG gen(Time::get_singleton()->get_ticks_usec()); + + const int attempts = 4; + + for (int i = 0; i < attempts; ++i) { + uint32_t rnd = gen.rand(); + String dirname = "godot_tmp_" + String::num_uint64(rnd); + String res_dir = tmp_dir.path_join(dirname); + Char16String res_dir16 = res_dir.utf16(); + + if (CreateDirectoryW((LPCWSTR)res_dir16.ptr(), nullptr)) { + return res_dir; + } + } + + return ""; +} + +static bool remove_dir_recursive(const String &p_dir) { + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (dir_access->change_dir(p_dir) != OK) { + return false; + } + return dir_access->erase_contents_recursive() == OK; +} + +static bool stream2file(IStream *p_stream, FILEDESCRIPTORW *p_desc, const String &p_path) { + if (DirAccess::make_dir_recursive_absolute(p_path.get_base_dir()) != OK) { + return false; + } + + Char16String path16 = p_path.utf16(); + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + + if (p_desc->dwFlags & FD_ATTRIBUTES) { + dwFlagsAndAttributes = p_desc->dwFileAttributes; + } + + HANDLE file = CreateFileW( + (LPCWSTR)path16.ptr(), + GENERIC_WRITE, + 0, + nullptr, + CREATE_NEW, + dwFlagsAndAttributes, + nullptr); + + if (!file) { + return false; + } + + const int bufsize = 4096; + char buf[bufsize]; + ULONG nread = 0; + DWORD nwritten = 0; + HRESULT read_result = S_OK; + bool result = true; + + while (true) { + read_result = p_stream->Read(buf, bufsize, &nread); + if (read_result != S_OK && read_result != S_FALSE) { + result = false; + goto cleanup; + } + + if (!nread) { + break; + } + + while (nread > 0) { + if (!WriteFile(file, buf, nread, &nwritten, nullptr) || !nwritten) { + result = false; + goto cleanup; + } + nread -= nwritten; + } + } + +cleanup: + CloseHandle(file); + return result; +} + +// DropTargetWindows + +bool DropTargetWindows::is_valid_filedescriptor() { + return cf_filedescriptor != 0 && cf_filecontents != 0; +} + +HRESULT DropTargetWindows::handle_hdrop_format(Vector<String> *p_files, IDataObject *pDataObj) { + FORMATETC fmt = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stg; + HRESULT res = S_OK; + + if (pDataObj->GetData(&fmt, &stg) != S_OK) { + return E_UNEXPECTED; + } + + HDROP hDropInfo = (HDROP)GlobalLock(stg.hGlobal); + + Char16String buf; + + if (hDropInfo == nullptr) { + ReleaseStgMedium(&stg); + return E_UNEXPECTED; + } + + int fcount = DragQueryFileW(hDropInfo, 0xFFFFFFFF, nullptr, 0); + + for (int i = 0; i < fcount; i++) { + int buffsize = DragQueryFileW(hDropInfo, i, nullptr, 0); + buf.resize(buffsize + 1); + if (DragQueryFileW(hDropInfo, i, (LPWSTR)buf.ptrw(), buffsize + 1) == 0) { + res = E_UNEXPECTED; + goto cleanup; + } + String file = String::utf16((const char16_t *)buf.ptr()); + p_files->push_back(file); + } + +cleanup: + GlobalUnlock(stg.hGlobal); + ReleaseStgMedium(&stg); + + return res; +} + +HRESULT DropTargetWindows::handle_filedescriptor_format(Vector<String> *p_files, IDataObject *pDataObj) { + FORMATETC fmt = { cf_filedescriptor, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stg; + HRESULT res = S_OK; + + if (pDataObj->GetData(&fmt, &stg) != S_OK) { + return E_UNEXPECTED; + } + + FILEGROUPDESCRIPTORW *filegroup_desc = (FILEGROUPDESCRIPTORW *)GlobalLock(stg.hGlobal); + + if (!filegroup_desc) { + ReleaseStgMedium(&stg); + return E_UNEXPECTED; + } + + tmp_path = create_temp_dir(); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + PackedStringArray copied; + + if (dir_access->change_dir(tmp_path) != OK) { + res = E_UNEXPECTED; + goto cleanup; + } + + for (int i = 0; i < (int)filegroup_desc->cItems; ++i) { + res = save_as_file(tmp_path, filegroup_desc->fgd + i, pDataObj, i); + if (res != S_OK) { + res = E_UNEXPECTED; + goto cleanup; + } + } + + copied = dir_access->get_files(); + for (const String &file : copied) { + p_files->push_back(tmp_path.path_join(file)); + } + + copied = dir_access->get_directories(); + for (const String &dir : copied) { + p_files->push_back(tmp_path.path_join(dir)); + } + +cleanup: + GlobalUnlock(filegroup_desc); + ReleaseStgMedium(&stg); + if (res != S_OK) { + remove_dir_recursive(tmp_path); + tmp_path.clear(); + } + return res; +} + +HRESULT DropTargetWindows::save_as_file(const String &p_out_dir, FILEDESCRIPTORW *p_file_desc, IDataObject *pDataObj, int p_file_idx) { + String relpath = String::utf16((const char16_t *)p_file_desc->cFileName); + String fullpath = p_out_dir.path_join(relpath); + + if (p_file_desc->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (DirAccess::make_dir_recursive_absolute(fullpath) != OK) { + return E_UNEXPECTED; + } + return S_OK; + } + + FORMATETC fmt = { cf_filecontents, nullptr, DVASPECT_CONTENT, p_file_idx, TYMED_ISTREAM }; + STGMEDIUM stg; + HRESULT res = S_OK; + + if (pDataObj->GetData(&fmt, &stg) != S_OK) { + return E_UNEXPECTED; + } + + IStream *stream = stg.pstm; + if (stream == nullptr) { + res = E_UNEXPECTED; + goto cleanup; + } + + if (!stream2file(stream, p_file_desc, fullpath)) { + res = E_UNEXPECTED; + goto cleanup; + } + +cleanup: + ReleaseStgMedium(&stg); + return res; +} + +DropTargetWindows::DropTargetWindows(DisplayServerWindows::WindowData *p_window_data) : + ref_count(1), window_data(p_window_data) { + cf_filedescriptor = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); + cf_filecontents = RegisterClipboardFormat(CFSTR_FILECONTENTS); +} + +HRESULT STDMETHODCALLTYPE DropTargetWindows::QueryInterface(REFIID riid, void **ppvObject) { + if (riid == IID_IUnknown || riid == IID_IDropTarget) { + *ppvObject = static_cast<IDropTarget *>(this); + AddRef(); + return S_OK; + } + *ppvObject = nullptr; + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE DropTargetWindows::AddRef() { + return InterlockedIncrement(&ref_count); +} + +ULONG STDMETHODCALLTYPE DropTargetWindows::Release() { + ULONG count = InterlockedDecrement(&ref_count); + if (count == 0) { + memfree(this); + } + return count; +} + +HRESULT STDMETHODCALLTYPE DropTargetWindows::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { + (void)grfKeyState; + (void)pt; + + FORMATETC hdrop_fmt = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + FORMATETC filedesc_fmt = { cf_filedescriptor, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + + if (!window_data->drop_files_callback.is_valid()) { + *pdwEffect = DROPEFFECT_NONE; + } else if (pDataObj->QueryGetData(&hdrop_fmt) == S_OK) { + *pdwEffect = DROPEFFECT_COPY; + } else if (is_valid_filedescriptor() && pDataObj->QueryGetData(&filedesc_fmt) == S_OK) { + *pdwEffect = DROPEFFECT_COPY; + } else { + *pdwEffect = DROPEFFECT_NONE; + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DropTargetWindows::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { + (void)grfKeyState; + (void)pt; + + *pdwEffect = DROPEFFECT_COPY; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DropTargetWindows::DragLeave() { + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DropTargetWindows::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { + (void)grfKeyState; + (void)pt; + + *pdwEffect = DROPEFFECT_NONE; + + if (!window_data->drop_files_callback.is_valid()) { + return S_OK; + } + + FORMATETC hdrop_fmt = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + FORMATETC filedesc_fmt = { cf_filedescriptor, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + Vector<String> files; + + if (pDataObj->QueryGetData(&hdrop_fmt) == S_OK) { + HRESULT res = handle_hdrop_format(&files, pDataObj); + if (res != S_OK) { + return res; + } + } else if (pDataObj->QueryGetData(&filedesc_fmt) == S_OK && is_valid_filedescriptor()) { + HRESULT res = handle_filedescriptor_format(&files, pDataObj); + if (res != S_OK) { + return res; + } + } else { + return E_UNEXPECTED; + } + + if (!files.size()) { + return S_OK; + } + + Variant v_files = files; + const Variant *v_args[1] = { &v_files }; + Variant ret; + Callable::CallError ce; + window_data->drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce); + + if (!tmp_path.is_empty()) { + remove_dir_recursive(tmp_path); + tmp_path.clear(); + } + + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(window_data->drop_files_callback, v_args, 1, ce))); + return E_UNEXPECTED; + } + + *pdwEffect = DROPEFFECT_COPY; + return S_OK; +} diff --git a/platform/windows/drop_target_windows.h b/platform/windows/drop_target_windows.h new file mode 100644 index 0000000000..bd0e0270c6 --- /dev/null +++ b/platform/windows/drop_target_windows.h @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* drop_target_windows.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DROP_TARGET_WINDOWS_H +#define DROP_TARGET_WINDOWS_H + +#include "display_server_windows.h" + +#include <shlobj.h> + +// Silence warning due to a COM API weirdness. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif + +// https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-dodragdrop#remarks +class DropTargetWindows : public IDropTarget { + LONG ref_count; + DisplayServerWindows::WindowData *window_data = nullptr; + CLIPFORMAT cf_filedescriptor = 0; + CLIPFORMAT cf_filecontents = 0; + String tmp_path; + + bool is_valid_filedescriptor(); + HRESULT handle_hdrop_format(Vector<String> *p_files, IDataObject *pDataObj); + HRESULT handle_filedescriptor_format(Vector<String> *p_files, IDataObject *pDataObj); + HRESULT save_as_file(const String &p_out_dir, FILEDESCRIPTORW *p_file_desc, IDataObject *pDataObj, int p_file_idx); + +public: + DropTargetWindows(DisplayServerWindows::WindowData *p_window_data); + virtual ~DropTargetWindows() {} + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + + // IDropTarget + HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override; + HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override; + HRESULT STDMETHODCALLTYPE DragLeave() override; + HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override; +}; + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif // DROP_TARGET_WINDOWS_H diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index 1972b36845..89db449424 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -59,7 +59,7 @@ class EditorExportPlatformWindows : public EditorExportPlatformPC { ssh_args = p_ssh_arg; cmd_args = p_cmd_args; wait = p_wait; - }; + } }; Ref<ImageTexture> run_icon; diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index 14536fa130..e3a535580f 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -1,5 +1,15 @@ <?xml version="1.0" encoding="utf-8"?> <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> + <Type Name="Ref<*>"> + <SmartPointer Usage="Minimal">reference</SmartPointer> + <DisplayString Condition="!reference">[empty]</DisplayString> + <DisplayString Condition="!!reference">{*reference}</DisplayString> + <Expand> + <Item Condition="!!reference" Name="[ptr]">reference</Item> + <Item Condition="!!reference" Name="[refcount]">reference->refcount.count.value</Item> + </Expand> + </Type> + <Type Name="Vector<*>"> <Expand> <Item Name="[size]">_cowdata._ptr ? (((const unsigned long long *)(_cowdata._ptr))[-1]) : 0</Item> @@ -20,16 +30,6 @@ </Expand> </Type> - <Type Name="TypedArray<*>"> - <Expand> - <Item Name="[size]"> _p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Item> - <ArrayItems> - <Size>_p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Size> - <ValuePointer >(Variant *) _p->array._cowdata._ptr</ValuePointer> - </ArrayItems> - </Expand> - </Type> - <Type Name="Dictionary"> <Expand> <Item Name="[size]">_p && _p->variant_map.head_element ? _p->variant_map.num_elements : 0</Item> @@ -91,6 +91,16 @@ <StringView Condition="_data && !_data->cname">_data->name,s32b</StringView> </Type> + <Type Name="HashSet<*,*,*>"> + <Expand> + <Item Name="[size]">num_elements</Item> + <ArrayItems> + <Size>num_elements</Size> + <ValuePointer>($T1 *) keys._cowdata._ptr</ValuePointer> + </ArrayItems> + </Expand> + </Type> + <Type Name="HashMapElement<*,*>"> <DisplayString>{{Key = {($T1 *) &data.key} Value = {($T2 *) &data.value}}}</DisplayString> <Expand> @@ -133,7 +143,7 @@ <Type Name="HashMapElement<*,*>" IncludeView="MapHelper"> <DisplayString>{data.value}</DisplayString> <Expand> - <Item Name="[key]" >($T1 *) &data.key</Item> + <Item Name="[key]">($T1 *) &data.key</Item> <Item Name="[value]">($T2 *) &data.value</Item> </Expand> </Type> @@ -265,39 +275,164 @@ </Type> <Type Name="Vector2"> - <DisplayString>{{{x},{y}}}</DisplayString> + <DisplayString>({x,g}, {y,g})</DisplayString> + <Expand> + <Item Name="[x]">x</Item> + <Item Name="[y]">y</Item> + </Expand> + </Type> + <Type Name="Vector2i"> + <DisplayString>({x}, {y})</DisplayString> <Expand> - <Item Name="x">x</Item> - <Item Name="y">y</Item> + <Item Name="[x]">x</Item> + <Item Name="[y]">y</Item> </Expand> </Type> <Type Name="Vector3"> - <DisplayString>{{{x},{y},{z}}}</DisplayString> + <DisplayString>({x,g}, {y,g}, {z,g})</DisplayString> + <Expand> + <Item Name="[x]">x</Item> + <Item Name="[y]">y</Item> + <Item Name="[z]">z</Item> + </Expand> + </Type> + <Type Name="Vector3i"> + <DisplayString>({x}, {y}, {z})</DisplayString> + <Expand> + <Item Name="[x]">x</Item> + <Item Name="[y]">y</Item> + <Item Name="[z]">z</Item> + </Expand> + </Type> + + <Type Name="Vector4"> + <DisplayString>({x,g}, {y,g}, {z,g}, {w,g})</DisplayString> + <Expand> + <Item Name="[x]">x</Item> + <Item Name="[y]">y</Item> + <Item Name="[z]">z</Item> + <Item Name="[w]">w</Item> + </Expand> + </Type> + <Type Name="Vector4i"> + <DisplayString>({x}, {y}, {z}, {w})</DisplayString> <Expand> - <Item Name="x">x</Item> - <Item Name="y">y</Item> - <Item Name="z">z</Item> + <Item Name="[x]">x</Item> + <Item Name="[y]">y</Item> + <Item Name="[z]">z</Item> + <Item Name="[w]">w</Item> </Expand> </Type> <Type Name="Quaternion"> - <DisplayString>Quaternion {{{x},{y},{z},{w}}}</DisplayString> + <DisplayString>({x,g}, {y,g}, {z,g}, {w,g})</DisplayString> <Expand> - <Item Name="x">x</Item> - <Item Name="y">y</Item> - <Item Name="z">z</Item> - <Item Name="w">w</Item> + <Item Name="[x]">x</Item> + <Item Name="[y]">y</Item> + <Item Name="[z]">z</Item> + <Item Name="[w]">w</Item> </Expand> </Type> <Type Name="Color"> - <DisplayString>Color {{{r},{g},{b},{a}}}</DisplayString> + <DisplayString>({r,g}, {g,g}, {b,g}, {a,g})</DisplayString> + <Expand> + <Item Name="[red]">r</Item> + <Item Name="[green]">g</Item> + <Item Name="[blue]">b</Item> + <Item Name="[alpha]">a</Item> + </Expand> + </Type> + + <Type Name="Rect2"> + <DisplayString>[P: {position}, S: {size}]</DisplayString> + <Expand> + <Item Name="[position]">position,nr</Item> + <Item Name="[size]">size,nr</Item> + </Expand> + </Type> + <Type Name="Rect2i"> + <DisplayString>[P: {position}, S: {size}]</DisplayString> + <Expand> + <Item Name="[position]">position,nr</Item> + <Item Name="[size]">size,nr</Item> + </Expand> + </Type> + + <Type Name="AABB"> + <DisplayString>[P: {position}, S: {size}]</DisplayString> + <Expand> + <Item Name="[position]">position,nr</Item> + <Item Name="[size]">size,nr</Item> + </Expand> + </Type> + + <Type Name="Plane"> + <DisplayString>[N: {normal}, D: {d,g}]</DisplayString> + <Expand> + <Item Name="[normal]">normal,nr</Item> + <Item Name="[d]">d</Item> + </Expand> + </Type> + + <Type Name="Basis"> + <DisplayString>[X: {rows[0]}, Y: {rows[1]}, Z: {rows[2]}]</DisplayString> + <Expand> + <Item Name="[x]">rows[0],nr</Item> + <Item Name="[y]">rows[1],nr</Item> + <Item Name="[z]">rows[2],nr</Item> + </Expand> + </Type> + + <Type Name="Transform2D"> + <DisplayString>[X: {columns[0]}, Y: {columns[1]}, O: {columns[2]}]</DisplayString> + <Expand> + <Item Name="[x]">columns[0],nr</Item> + <Item Name="[y]">columns[1],nr</Item> + <Item Name="[origin]">columns[2],nr</Item> + </Expand> + </Type> + + <Type Name="Transform3D"> + <!-- Can't call column functions, so just pretend we can via obscene code duplication. --> + <DisplayString>[X: ({basis.rows[0].x,g}, {basis.rows[1].x,g}, {basis.rows[2].x,g}), Y: ({basis.rows[0].y,g}, {basis.rows[1].y,g}, {basis.rows[2].y,g}), Z: ({basis.rows[0].z,g}, {basis.rows[1].z,g}, {basis.rows[2].z,g}), O: {origin}]</DisplayString> + <Expand> + <Synthetic Name="[x]"> + <DisplayString>({basis.rows[0].x,g}, {basis.rows[1].x,g}, {basis.rows[2].x,g})</DisplayString> + <Expand> + <Item Name="[x]">basis.rows[0].x</Item> + <Item Name="[y]">basis.rows[1].x</Item> + <Item Name="[z]">basis.rows[2].x</Item> + </Expand> + </Synthetic> + <Synthetic Name="[y]"> + <DisplayString>({basis.rows[0].y,g}, {basis.rows[1].y,g}, {basis.rows[2].y,g})</DisplayString> + <Expand> + <Item Name="[x]">basis.rows[0].y</Item> + <Item Name="[y]">basis.rows[1].y</Item> + <Item Name="[z]">basis.rows[2].y</Item> + </Expand> + </Synthetic> + <Synthetic Name="[z]"> + <DisplayString>({basis.rows[0].z,g}, {basis.rows[1].z,g}, {basis.rows[2].z,g})</DisplayString> + <Expand> + <Item Name="[x]">basis.rows[0].z</Item> + <Item Name="[y]">basis.rows[1].z</Item> + <Item Name="[z]">basis.rows[2].z</Item> + </Expand> + </Synthetic> + <Item Name="[origin]">origin,nr</Item> + </Expand> + </Type> + + <Type Name="Projection"> + <DisplayString>[X: {columns[0]}, Y: {columns[1]}, Z: {columns[2]}, W: {columns[3]}]</DisplayString> <Expand> - <Item Name="red">r</Item> - <Item Name="green">g</Item> - <Item Name="blue">b</Item> - <Item Name="alpha">a</Item> + <Item Name="[x]">columns[0],nr</Item> + <Item Name="[y]">columns[1],nr</Item> + <Item Name="[z]">columns[2],nr</Item> + <Item Name="[w]">columns[3],nr</Item> </Expand> </Type> </AutoVisualizer> diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index a5f1629cf0..0f55cda5d7 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -122,8 +122,9 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) { memcmp(p_guid, &IID_XOneSWirelessGamepad, sizeof(*p_guid)) == 0 || memcmp(p_guid, &IID_XOneSBluetoothGamepad, sizeof(*p_guid)) == 0 || memcmp(p_guid, &IID_XOneEliteWirelessGamepad, sizeof(*p_guid)) == 0 || - memcmp(p_guid, &IID_XOneElite2WirelessGamepad, sizeof(*p_guid)) == 0) + memcmp(p_guid, &IID_XOneElite2WirelessGamepad, sizeof(*p_guid)) == 0) { return true; + } PRAWINPUTDEVICELIST dev_list = nullptr; unsigned int dev_list_count = 0; diff --git a/platform/windows/native_menu_windows.cpp b/platform/windows/native_menu_windows.cpp index fde55918e4..9fa2849e7b 100644 --- a/platform/windows/native_menu_windows.cpp +++ b/platform/windows/native_menu_windows.cpp @@ -158,7 +158,7 @@ Size2 NativeMenuWindows::get_size(const RID &p_rid) const { int count = GetMenuItemCount(md->menu); for (int i = 0; i < count; i++) { RECT rect; - if (GetMenuItemRect(NULL, md->menu, i, &rect)) { + if (GetMenuItemRect(nullptr, md->menu, i, &rect)) { size.x = MAX(size.x, rect.right - rect.left); size.y += rect.bottom - rect.top; } @@ -992,7 +992,7 @@ void NativeMenuWindows::set_item_submenu(const RID &p_rid, int p_idx, const RID if (p_submenu_rid.is_valid()) { item.hSubMenu = md_sub->menu; } else { - item.hSubMenu = 0; + item.hSubMenu = nullptr; } SetMenuItemInfoW(md->menu, p_idx, true, &item); } @@ -1095,7 +1095,7 @@ void NativeMenuWindows::set_item_icon(const RID &p_rid, int p_idx, const Ref<Tex item_data->bmp = _make_bitmap(item_data->img); } else { item_data->img = Ref<Image>(); - item_data->bmp = 0; + item_data->bmp = nullptr; } item.hbmpItem = item_data->bmp; SetMenuItemInfoW(md->menu, p_idx, true, &item); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index adc72a79e9..0d151668ba 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -40,10 +40,10 @@ #include "core/debugger/script_debugger.h" #include "core/io/marshalls.h" #include "core/version_generated.gen.h" -#include "drivers/unix/net_socket_posix.h" #include "drivers/windows/dir_access_windows.h" #include "drivers/windows/file_access_windows.h" #include "drivers/windows/file_access_windows_pipe.h" +#include "drivers/windows/net_socket_winsock.h" #include "main/main.h" #include "servers/audio_server.h" #include "servers/rendering/rendering_server_default.h" @@ -139,13 +139,13 @@ void RedirectIOToConsole() { if (AttachConsole(ATTACH_PARENT_PROCESS)) { // Restore redirection (Note: if not redirected it's NULL handles not INVALID_HANDLE_VALUE). - if (h_stdin != 0) { + if (h_stdin != nullptr) { SetStdHandle(STD_INPUT_HANDLE, h_stdin); } - if (h_stdout != 0) { + if (h_stdout != nullptr) { SetStdHandle(STD_OUTPUT_HANDLE, h_stdout); } - if (h_stderr != 0) { + if (h_stderr != nullptr) { SetStdHandle(STD_ERROR_HANDLE, h_stderr); } @@ -209,7 +209,7 @@ void OS_Windows::initialize() { DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); - NetSocketPosix::make_default(); + NetSocketWinSock::make_default(); // We need to know how often the clock is updated QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second); @@ -303,7 +303,7 @@ void OS_Windows::finalize_core() { timeEndPeriod(1); memdelete(process_map); - NetSocketPosix::cleanup(); + NetSocketWinSock::cleanup(); #ifdef WINDOWS_DEBUG_OUTPUT_ENABLED remove_error_handler(&error_handlers); @@ -908,9 +908,9 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String } // Create pipes. - HANDLE pipe_in[2] = { 0, 0 }; - HANDLE pipe_out[2] = { 0, 0 }; - HANDLE pipe_err[2] = { 0, 0 }; + HANDLE pipe_in[2] = { nullptr, nullptr }; + HANDLE pipe_out[2] = { nullptr, nullptr }; + HANDLE pipe_err[2] = { nullptr, nullptr }; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); @@ -981,7 +981,7 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String Ref<FileAccessWindowsPipe> err_pipe; err_pipe.instantiate(); - err_pipe->open_existing(pipe_err[0], 0, p_blocking); + err_pipe->open_existing(pipe_err[0], nullptr, p_blocking); ret["stdio"] = main_pipe; ret["stderr"] = err_pipe; @@ -1363,7 +1363,7 @@ public: locale = p_locale; n_sub = p_nsub; rtl = p_rtl; - }; + } virtual ~FallbackTextAnalysisSource() {} }; @@ -1740,6 +1740,34 @@ String OS_Windows::get_locale() const { return "en"; } +String OS_Windows::get_model_name() const { + HKEY hkey; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Hardware\\Description\\System\\BIOS", 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) { + return OS::get_model_name(); + } + + String sys_name; + String board_name; + WCHAR buffer[256]; + DWORD buffer_len = 256; + DWORD vtype = REG_SZ; + if (RegQueryValueExW(hkey, L"SystemProductName", nullptr, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS && buffer_len != 0) { + sys_name = String::utf16((const char16_t *)buffer, buffer_len).strip_edges(); + } + buffer_len = 256; + if (RegQueryValueExW(hkey, L"BaseBoardProduct", nullptr, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS && buffer_len != 0) { + board_name = String::utf16((const char16_t *)buffer, buffer_len).strip_edges(); + } + RegCloseKey(hkey); + if (!sys_name.is_empty() && sys_name.to_lower() != "system product name") { + return sys_name; + } + if (!board_name.is_empty() && board_name.to_lower() != "base board product") { + return board_name; + } + return OS::get_model_name(); +} + String OS_Windows::get_processor_name() const { const String id = "Hardware\\Description\\System\\CentralProcessor\\0"; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 4f9bc049ee..34af004822 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -210,6 +210,8 @@ public: virtual String get_processor_name() const override; + virtual String get_model_name() const override; + virtual uint64_t get_embedded_pck_offset() const override; virtual String get_config_path() const override; diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py index 3fd9e1a581..2020e68748 100644 --- a/platform/windows/platform_windows_builders.py +++ b/platform/windows/platform_windows_builders.py @@ -2,23 +2,11 @@ import os -from detect import get_mingw_bin_prefix, try_cmd - def make_debug_mingw(target, source, env): dst = str(target[0]) # Force separate debug symbols if executable size is larger than 1.9 GB. if env["separate_debug_symbols"] or os.stat(dst).st_size >= 2040109465: - mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) - if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]): - os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst)) - else: - os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst)) - if try_cmd("strip --version", env["mingw_prefix"], env["arch"]): - os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(dst)) - else: - os.system("strip --strip-debug --strip-unneeded {0}".format(dst)) - if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]): - os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst)) - else: - os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst)) + os.system("{0} --only-keep-debug {1} {1}.debugsymbols".format(env["OBJCOPY"], dst)) + os.system("{0} --strip-debug --strip-unneeded {1}".format(env["STRIP"], dst)) + os.system("{0} --add-gnu-debuglink={1}.debugsymbols {1}".format(env["OBJCOPY"], dst)) diff --git a/platform/windows/windows_utils.cpp b/platform/windows/windows_utils.cpp index 30743c6900..3b9bfb50f7 100644 --- a/platform/windows/windows_utils.cpp +++ b/platform/windows/windows_utils.cpp @@ -67,11 +67,11 @@ Error WindowsUtils::copy_and_rename_pdb(const String &p_dll_path) { { // The custom LoadLibraryExW is used instead of open_dynamic_library // to avoid loading the original PDB into the debugger. - HMODULE library_ptr = LoadLibraryExW((LPCWSTR)(p_dll_path.utf16().get_data()), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE); + HMODULE library_ptr = LoadLibraryExW((LPCWSTR)(p_dll_path.utf16().get_data()), nullptr, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE); ERR_FAIL_NULL_V_MSG(library_ptr, ERR_FILE_CANT_OPEN, vformat("Failed to load library '%s'.", p_dll_path)); - IMAGE_DEBUG_DIRECTORY *dbg_dir = (IMAGE_DEBUG_DIRECTORY *)ImageDirectoryEntryToDataEx(library_ptr, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &dbg_info_size, NULL); + IMAGE_DEBUG_DIRECTORY *dbg_dir = (IMAGE_DEBUG_DIRECTORY *)ImageDirectoryEntryToDataEx(library_ptr, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &dbg_info_size, nullptr); bool has_debug = dbg_dir && dbg_dir->Type == IMAGE_DEBUG_TYPE_CODEVIEW; if (has_debug) { |