diff options
Diffstat (limited to 'platform/windows')
24 files changed, 981 insertions, 704 deletions
diff --git a/platform/windows/SCsub b/platform/windows/SCsub index daffe59f34..47d8e14680 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -26,11 +26,11 @@ prog = env.add_program("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGS # Microsoft Visual Studio Project Generation if env["vsproj"]: - env.vs_srcs = env.vs_srcs + ["platform/windows/" + res_file] - env.vs_srcs = env.vs_srcs + ["platform/windows/godot.natvis"] + env.vs_srcs += ["platform/windows/" + res_file] + env.vs_srcs += ["platform/windows/godot.natvis"] for x in common_win: - env.vs_srcs = env.vs_srcs + ["platform/windows/" + str(x)] + env.vs_srcs += ["platform/windows/" + str(x)] if not os.getenv("VCINSTALLDIR"): - if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]: + if env["debug_symbols"] and env["separate_debug_symbols"]: env.AddPostAction(prog, run_in_subprocess(platform_windows_builders.make_debug_mingw)) diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp index 1c32639a38..7cf9738f13 100644 --- a/platform/windows/context_gl_windows.cpp +++ b/platform/windows/context_gl_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -94,7 +94,7 @@ void ContextGL_Windows::swap_buffers() { if (vsync_via_compositor_now != vsync_via_compositor) { // The previous frame had a different operating mode than this - // frame. Set the 'vsync_via_compositor' member variable and the + // frame. Set the 'vsync_via_compositor' member variable and the // OpenGL swap interval to their proper values. set_use_vsync(true); } @@ -211,6 +211,7 @@ ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) { hWnd = hwnd; use_vsync = false; vsync_via_compositor = false; + pixel_format = 0; } ContextGL_Windows::~ContextGL_Windows() { diff --git a/platform/windows/context_gl_windows.h b/platform/windows/context_gl_windows.h index 046e3437ea..e44e2945ca 100644 --- a/platform/windows/context_gl_windows.h +++ b/platform/windows/context_gl_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -35,7 +35,7 @@ #ifndef CONTEXT_GL_WIN_H #define CONTEXT_GL_WIN_H -#include "core/error_list.h" +#include "core/error/error_list.h" #include "core/os/os.h" #include <windows.h> diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index 996d9722f5..e2d507eddd 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,13 +30,13 @@ #include "crash_handler_windows.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "main/main.h" #ifdef CRASH_HANDLER_EXCEPTION -// Backtrace code code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app +// Backtrace code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app #include <algorithm> #include <iterator> @@ -57,7 +57,7 @@ struct module_data { std::string image_name; std::string module_name; - void *base_address; + void *base_address = nullptr; DWORD load_size; }; @@ -175,7 +175,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { msg = proj_settings->get("debug/settings/crash_handler/message"); } - fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); + fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data()); int n = 0; do { diff --git a/platform/windows/crash_handler_windows.h b/platform/windows/crash_handler_windows.h index 66a4cac296..e1ec8e6787 100644 --- a/platform/windows/crash_handler_windows.h +++ b/platform/windows/crash_handler_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 9f79e92dcb..7772ba2dbe 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -64,22 +64,23 @@ def get_opts(): # XP support dropped after EOL due to missing API for IPv6 and other issues # Vista support dropped after EOL due to GH-10243 ("target_win_version", "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601"), - EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")), + BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), + EnumVariable("windows_subsystem", "Windows subsystem", "default", ("default", "console", "gui")), 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. Only used on Windows.", False), + BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed.", False), BoolVariable("use_llvm", "Use the LLVM compiler", False), BoolVariable("use_thinlto", "Use ThinLTO", False), + BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True), + BoolVariable("use_asan", "Use address sanitizer (ASAN)", False), ] def get_flags(): - return [] def build_res_file(target, source, env): - if env["bits"] == "32": cmdbase = env["mingw_prefix_32"] else: @@ -93,7 +94,7 @@ def build_res_file(target, source, env): out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate() if len(out[1]): return 1 - except: + except Exception: return 1 return 0 @@ -128,7 +129,9 @@ def setup_msvc_manual(env): print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).") else: print( - "Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR." + "Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings" + " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this" + " build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR." ) @@ -176,39 +179,58 @@ 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"]) - else: # optimize for size + env.Append(LINKFLAGS=["/OPT:REF"]) + elif env["optimize"] == "size": # optimize for size env.Append(CCFLAGS=["/O1"]) - env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"]) + env.Append(LINKFLAGS=["/OPT:REF"]) env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"]) - env.Append(LINKFLAGS=["/OPT:REF"]) elif env["target"] == "release_debug": if env["optimize"] == "speed": # optimize for speed (default) env.Append(CCFLAGS=["/O2"]) - else: # optimize for size + env.Append(LINKFLAGS=["/OPT:REF"]) + elif env["optimize"] == "size": # optimize for size env.Append(CCFLAGS=["/O1"]) + env.Append(LINKFLAGS=["/OPT:REF"]) env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"]) - env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) - env.Append(LINKFLAGS=["/OPT:REF"]) elif env["target"] == "debug": - env.AppendUnique(CCFLAGS=["/Z7", "/Od", "/EHsc"]) - env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED", "D3D_DEBUG_INFO"]) - env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) + env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"]) + env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"]) env.Append(LINKFLAGS=["/DEBUG"]) - if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes": - env.AppendUnique(CCFLAGS=["/Z7"]) + if env["debug_symbols"]: + env.AppendUnique(CCFLAGS=["/Zi", "/FS"]) env.AppendUnique(LINKFLAGS=["/DEBUG"]) + if env["windows_subsystem"] == "gui": + env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"]) + else: + env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) + env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"]) + ## Compile/link flags - env.AppendUnique(CCFLAGS=["/MT", "/Gd", "/GR", "/nologo"]) - if int(env["MSVC_VERSION"].split(".")[0]) >= 14: # vs2015 and later - env.AppendUnique(CCFLAGS=["/utf-8"]) + if env["use_static_cpp"]: + env.AppendUnique(CCFLAGS=["/MT"]) + else: + env.AppendUnique(CCFLAGS=["/MD"]) + + env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"]) + # Force to use Unicode encoding + env.AppendUnique(CCFLAGS=["/utf-8"]) env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++ if manual_msvc_config: # should be automatic if SCons found it if os.getenv("WindowsSdkDir") is not None: @@ -287,6 +309,12 @@ def configure_msvc(env, manual_msvc_config): env.Prepend(CPPPATH=[p for p in os.getenv("INCLUDE").split(";")]) env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) + # Sanitizers + if env["use_asan"]: + env.extra_suffix += ".s" + env.Append(LINKFLAGS=["/INFERASANLIBS"]) + env.Append(CCFLAGS=["/fsanitize=address"]) + # Incremental linking fix env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"] env["BUILDERS"]["Program"] = methods.precious_program @@ -301,6 +329,15 @@ 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"]) @@ -312,19 +349,13 @@ def configure_mingw(env): else: # optimize for size env.Prepend(CCFLAGS=["-Os"]) - env.Append(LINKFLAGS=["-Wl,--subsystem,windows"]) - - if env["debug_symbols"] == "yes": - env.Prepend(CCFLAGS=["-g1"]) - if env["debug_symbols"] == "full": + if env["debug_symbols"]: env.Prepend(CCFLAGS=["-g2"]) elif env["target"] == "release_debug": env.Append(CCFLAGS=["-O2"]) env.Append(CPPDEFINES=["DEBUG_ENABLED"]) - if env["debug_symbols"] == "yes": - env.Prepend(CCFLAGS=["-g1"]) - if env["debug_symbols"] == "full": + if env["debug_symbols"]: env.Prepend(CCFLAGS=["-g2"]) if env["optimize"] == "speed": # optimize for speed (default) env.Append(CCFLAGS=["-O2"]) @@ -333,7 +364,13 @@ def configure_mingw(env): elif env["target"] == "debug": env.Append(CCFLAGS=["-g3"]) - env.Append(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"]) + env.Append(CPPDEFINES=["DEBUG_ENABLED"]) + + if env["windows_subsystem"] == "gui": + env.Append(LINKFLAGS=["-Wl,--subsystem,windows"]) + else: + env.Append(LINKFLAGS=["-Wl,--subsystem,console"]) + env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"]) ## Compiler configuration @@ -349,28 +386,29 @@ def configure_mingw(env): mingw_prefix = "" if env["bits"] == "32": - env.Append(LINKFLAGS=["-static"]) - env.Append(LINKFLAGS=["-static-libgcc"]) - env.Append(LINKFLAGS=["-static-libstdc++"]) + if env["use_static_cpp"]: + env.Append(LINKFLAGS=["-static"]) + env.Append(LINKFLAGS=["-static-libgcc"]) + env.Append(LINKFLAGS=["-static-libstdc++"]) mingw_prefix = env["mingw_prefix_32"] else: - env.Append(LINKFLAGS=["-static"]) + if env["use_static_cpp"]: + env.Append(LINKFLAGS=["-static"]) mingw_prefix = env["mingw_prefix_64"] if env["use_llvm"]: env["CC"] = mingw_prefix + "clang" - env["AS"] = mingw_prefix + "as" env["CXX"] = mingw_prefix + "clang++" + env["AS"] = mingw_prefix + "as" env["AR"] = mingw_prefix + "ar" env["RANLIB"] = mingw_prefix + "ranlib" - env["LINK"] = mingw_prefix + "clang++" else: env["CC"] = mingw_prefix + "gcc" - env["AS"] = mingw_prefix + "as" env["CXX"] = mingw_prefix + "g++" + env["AS"] = mingw_prefix + "as" env["AR"] = mingw_prefix + "gcc-ar" env["RANLIB"] = mingw_prefix + "gcc-ranlib" - env["LINK"] = mingw_prefix + "g++" + env["x86_libtheora_opt_gcc"] = True if env["use_lto"]: @@ -424,7 +462,7 @@ def configure_mingw(env): else: env.Append(LIBS=["cfgmgr32"]) - ## TODO !!! Reenable when OpenGLES Rendering Device is implemented !!! + ## TODO !!! Re-enable when OpenGLES Rendering Device is implemented !!! # env.Append(CPPDEFINES=['OPENGL_ENABLED']) env.Append(LIBS=["opengl32"]) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 9d8344fa7e..f7172598ec 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,7 +29,9 @@ /*************************************************************************/ #include "display_server_windows.h" + #include "core/io/marshalls.h" +#include "core/math/geometry_2d.h" #include "main/main.h" #include "os_windows.h" #include "scene/resources/texture.h" @@ -42,7 +44,7 @@ static String format_error_message(DWORD id) { size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr); - String msg = "Error " + itos(id) + ": " + String(messageBuffer, size); + String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size); LocalFree(messageBuffer); @@ -78,11 +80,12 @@ String DisplayServerWindows::get_name() const { } void DisplayServerWindows::alert(const String &p_alert, const String &p_title) { - MessageBoxW(nullptr, p_alert.c_str(), p_title.c_str(), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); + MessageBoxW(nullptr, (LPCWSTR)(p_alert.utf16().get_data()), (LPCWSTR)(p_title.utf16().get_data()), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); } void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) { - if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED) { + if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) { + // Mouse is grabbed (captured or confined). WindowData &wd = windows[MAIN_WINDOW_ID]; RECT clipRect; @@ -98,12 +101,17 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) { SetCapture(wd.hWnd); } } else { + // Mouse is free to move around (not captured or confined). ReleaseCapture(); ClipCursor(nullptr); } - if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_HIDDEN) { - hCursor = SetCursor(nullptr); + if (p_mode == MOUSE_MODE_HIDDEN || p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) { + if (hCursor == nullptr) { + hCursor = SetCursor(nullptr); + } else { + SetCursor(nullptr); + } } else { CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; @@ -117,9 +125,9 @@ void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) { if (mouse_mode == p_mode) return; - _set_mouse_mode_impl(p_mode); - mouse_mode = p_mode; + + _set_mouse_mode_impl(p_mode); } DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode() const { @@ -153,7 +161,7 @@ Point2i DisplayServerWindows::mouse_get_position() const { //return Point2(old_x, old_y); } -int DisplayServerWindows::mouse_get_button_state() const { +MouseButton DisplayServerWindows::mouse_get_button_state() const { return last_button_state; } @@ -166,18 +174,19 @@ void DisplayServerWindows::clipboard_set(const String &p_text) { // Convert LF line endings to CRLF in clipboard content // Otherwise, line endings won't be visible when pasted in other software - String text = p_text.replace("\n", "\r\n"); + String text = p_text.replace("\r\n", "\n").replace("\n", "\r\n"); // avoid \r\r\n if (!OpenClipboard(windows[last_focused_window].hWnd)) { ERR_FAIL_MSG("Unable to open clipboard."); } EmptyClipboard(); - HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(CharType)); + Char16String utf16 = text.utf16(); + HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (utf16.length() + 1) * sizeof(WCHAR)); ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents."); LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem); - memcpy(lptstrCopy, text.c_str(), (text.length() + 1) * sizeof(CharType)); + memcpy(lptstrCopy, utf16.get_data(), (utf16.length() + 1) * sizeof(WCHAR)); GlobalUnlock(mem); SetClipboardData(CF_UNICODETEXT, mem); @@ -214,7 +223,7 @@ String DisplayServerWindows::clipboard_get() const { if (mem != nullptr) { LPWSTR ptr = (LPWSTR)GlobalLock(mem); if (ptr != nullptr) { - ret = String((CharType *)ptr); + ret = String::utf16((const char16_t *)ptr); GlobalUnlock(mem); }; }; @@ -325,7 +334,7 @@ static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonito EnumRectData *data = (EnumRectData *)dwData; if (data->count == data->screen) { MONITORINFO minfo; - zeromem(&minfo, sizeof(MONITORINFO)); + memset(&minfo, 0, sizeof(MONITORINFO)); minfo.cbSize = sizeof(MONITORINFO); GetMonitorInfoA(hMonitor, &minfo); @@ -472,6 +481,7 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod _THREAD_SAFE_METHOD_ WindowID window_id = _create_window(p_mode, p_flags, p_rect); + ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window."); WindowData &wd = windows[window_id]; @@ -488,15 +498,21 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod wd.no_focus = true; } - _update_window_style(window_id); + return window_id; +} + +void DisplayServerWindows::show_window(WindowID p_id) { + WindowData &wd = windows[p_id]; - ShowWindow(wd.hWnd, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window - if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) { + if (p_id != MAIN_WINDOW_ID) { + _update_window_style(p_id); + } + + ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window + if (!wd.no_focus) { SetForegroundWindow(wd.hWnd); // Slightly Higher Priority SetFocus(wd.hWnd); // Sets Keyboard Focus To } - - return window_id; } void DisplayServerWindows::delete_sub_window(WindowID p_window) { @@ -521,7 +537,7 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { } #endif - if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[p_window].wtctx) { + if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window].wtctx) { wintab_WTClose(windows[p_window].wtctx); windows[p_window].wtctx = 0; } @@ -582,7 +598,37 @@ void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_wi _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); - SetWindowTextW(windows[p_window].hWnd, p_title.c_str()); + SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data())); +} + +void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!windows.has(p_window)); + windows[p_window].mpath = p_region; + _update_window_mouse_passthrough(p_window); +} + +void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) { + if (windows[p_window].mpath.size() == 0) { + SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE); + } else { + POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size()); + for (int i = 0; i < windows[p_window].mpath.size(); i++) { + if (windows[p_window].borderless) { + points[i].x = windows[p_window].mpath[i].x; + points[i].y = windows[p_window].mpath[i].y; + } else { + points[i].x = windows[p_window].mpath[i].x + GetSystemMetrics(SM_CXSIZEFRAME); + points[i].y = windows[p_window].mpath[i].y + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION); + } + } + + HRGN region = CreatePolygonRgn(points, windows[p_window].mpath.size(), ALTERNATE); + SetWindowRgn(windows[p_window].hWnd, region, TRUE); + DeleteObject(region); + memfree(points); + } } int DisplayServerWindows::window_get_current_screen(WindowID p_window) const { @@ -671,7 +717,7 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window MoveWindow(wd.hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); #endif // Don't let the mouse leave the window when moved - if (mouse_mode == MOUSE_MODE_CONFINED) { + if (mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { RECT rect; GetClientRect(wd.hWnd, &rect); ClientToScreen(wd.hWnd, (POINT *)&rect.left); @@ -797,7 +843,7 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo MoveWindow(wd.hWnd, rect.left, rect.top, w, h, TRUE); // Don't let the mouse leave the window when resizing to a smaller resolution - if (mouse_mode == MOUSE_MODE_CONFINED) { + if (mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { RECT crect; GetClientRect(wd.hWnd, &crect); ClientToScreen(wd.hWnd, (POINT *)&crect.left); @@ -859,6 +905,9 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; } } + if (!p_borderless) { + r_style |= WS_VISIBLE; + } if (p_no_activate_focus) { r_style_ex |= WS_EX_TOPMOST | WS_EX_NOACTIVATE; @@ -866,7 +915,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre r_style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS; } -void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repaint, bool p_maximized) { +void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repaint) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -899,6 +948,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) RECT rect; wd.fullscreen = false; + wd.maximized = wd.was_maximized; if (wd.pre_fs_valid) { rect = wd.pre_fs_rect; @@ -907,13 +957,16 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) rect.right = wd.width; rect.top = 0; rect.bottom = wd.height; + wd.pre_fs_valid = true; } - _update_window_style(p_window, false, wd.was_maximized); + _update_window_style(p_window, false); MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); - - wd.pre_fs_valid = true; + } else if (p_mode == WINDOW_MODE_WINDOWED) { + ShowWindow(wd.hWnd, SW_RESTORE); + wd.maximized = false; + wd.minimized = false; } if (p_mode == WINDOW_MODE_MAXIMIZED) { @@ -922,12 +975,6 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) wd.minimized = false; } - if (p_mode == WINDOW_MODE_WINDOWED) { - ShowWindow(wd.hWnd, SW_RESTORE); - wd.maximized = false; - wd.minimized = false; - } - if (p_mode == WINDOW_MODE_MINIMIZED) { ShowWindow(wd.hWnd, SW_MINIMIZE); wd.maximized = false; @@ -998,6 +1045,7 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W case WINDOW_FLAG_BORDERLESS: { wd.borderless = p_enabled; _update_window_style(p_window); + _update_window_mouse_passthrough(p_window); } break; case WINDOW_FLAG_ALWAYS_ON_TOP: { ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID && p_enabled, "Transient windows can't become on top"); @@ -1073,7 +1121,7 @@ bool DisplayServerWindows::window_can_draw(WindowID p_window) const { ERR_FAIL_COND_V(!windows.has(p_window), false); const WindowData &wd = windows[p_window]; - return wd.minimized; + return !wd.minimized; } bool DisplayServerWindows::can_any_window_draw() const { @@ -1207,12 +1255,12 @@ void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTra HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap); HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap); - // Assign the monochrome AND mask bitmap pixels so that a pixels of the source bitmap + // Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap // with 'clrTransparent' will be white pixels of the monochrome bitmap SetBkColor(hMainDC, clrTransparent); BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY); - // Assign the color XOR mask bitmap pixels so that a pixels of the source bitmap + // Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap // with 'clrTransparent' will be black and rest the pixels same as corresponding // pixels of the source bitmap SetBkColor(hXorMaskDC, RGB(0, 0, 0)); @@ -1253,7 +1301,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh Rect2 atlas_rect; if (texture.is_valid()) { - image = texture->get_data(); + image = texture->get_image(); } if (!image.is_valid() && atlas_texture.is_valid()) { @@ -1276,7 +1324,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height); - image = texture->get_data(); + image = texture->get_image(); ERR_FAIL_COND(!image.is_valid()); @@ -1362,7 +1410,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh } } -bool DisplayServerWindows::get_swap_ok_cancel() { +bool DisplayServerWindows::get_swap_cancel_ok() { return true; } @@ -1372,70 +1420,99 @@ void DisplayServerWindows::enable_for_stealing_focus(OS::ProcessID pid) { AllowSetForegroundWindow(pid); } -DisplayServer::LatinKeyboardVariant DisplayServerWindows::get_latin_keyboard_variant() const { - _THREAD_SAFE_METHOD_ +int DisplayServerWindows::keyboard_get_layout_count() const { + return GetKeyboardLayoutList(0, nullptr); +} - unsigned long azerty[] = { - 0x00020401, // Arabic (102) AZERTY - 0x0001080c, // Belgian (Comma) - 0x0000080c, // Belgian French - 0x0000040c, // French - 0 // <--- STOP MARK - }; - unsigned long qwertz[] = { - 0x0000041a, // Croation - 0x00000405, // Czech - 0x00000407, // German - 0x00010407, // German (IBM) - 0x0000040e, // Hungarian - 0x0000046e, // Luxembourgish - 0x00010415, // Polish (214) - 0x00000418, // Romanian (Legacy) - 0x0000081a, // Serbian (Latin) - 0x0000041b, // Slovak - 0x00000424, // Slovenian - 0x0001042e, // Sorbian Extended - 0x0002042e, // Sorbian Standard - 0x0000042e, // Sorbian Standard (Legacy) - 0x0000100c, // Swiss French - 0x00000807, // Swiss German - 0 // <--- STOP MARK - }; - unsigned long dvorak[] = { - 0x00010409, // US-Dvorak - 0x00030409, // US-Dvorak for left hand - 0x00040409, // US-Dvorak for right hand - 0 // <--- STOP MARK - }; +int DisplayServerWindows::keyboard_get_current_layout() const { + HKL cur_layout = GetKeyboardLayout(0); + + int layout_count = GetKeyboardLayoutList(0, nullptr); + HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL)); + GetKeyboardLayoutList(layout_count, layouts); - char name[KL_NAMELENGTH + 1]; - name[0] = 0; - GetKeyboardLayoutNameA(name); + for (int i = 0; i < layout_count; i++) { + if (cur_layout == layouts[i]) { + memfree(layouts); + return i; + } + } + memfree(layouts); + return -1; +} - unsigned long hex = strtoul(name, nullptr, 16); +void DisplayServerWindows::keyboard_set_current_layout(int p_index) { + int layout_count = GetKeyboardLayoutList(0, nullptr); - int i = 0; - while (azerty[i] != 0) { - if (azerty[i] == hex) - return LATIN_KEYBOARD_AZERTY; - i++; + ERR_FAIL_INDEX(p_index, layout_count); + + HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL)); + GetKeyboardLayoutList(layout_count, layouts); + ActivateKeyboardLayout(layouts[p_index], KLF_SETFORPROCESS); + memfree(layouts); +} + +String DisplayServerWindows::keyboard_get_layout_language(int p_index) const { + int layout_count = GetKeyboardLayoutList(0, nullptr); + + ERR_FAIL_INDEX_V(p_index, layout_count, ""); + + HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL)); + GetKeyboardLayoutList(layout_count, layouts); + + WCHAR buf[LOCALE_NAME_MAX_LENGTH]; + memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR)); + LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0); + + memfree(layouts); + + return String::utf16((const char16_t *)buf).substr(0, 2); +} + +String _get_full_layout_name_from_registry(HKL p_layout) { + String id = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\" + String::num_int64((int64_t)p_layout, 16, false).lpad(8, "0"); + String ret; + + HKEY hkey; + WCHAR layout_text[1024]; + memset(layout_text, 0, 1024 * sizeof(WCHAR)); + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)(id.utf16().get_data()), 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) { + return ret; } - i = 0; - while (qwertz[i] != 0) { - if (qwertz[i] == hex) - return LATIN_KEYBOARD_QWERTZ; - i++; + DWORD buffer = 1024; + DWORD vtype = REG_SZ; + if (RegQueryValueExW(hkey, L"Layout Text", nullptr, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) { + ret = String::utf16((const char16_t *)layout_text); } + RegCloseKey(hkey); + return ret; +} + +String DisplayServerWindows::keyboard_get_layout_name(int p_index) const { + int layout_count = GetKeyboardLayoutList(0, nullptr); + + ERR_FAIL_INDEX_V(p_index, layout_count, ""); + + HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL)); + GetKeyboardLayoutList(layout_count, layouts); + + String ret = _get_full_layout_name_from_registry(layouts[p_index]); // Try reading full name from Windows registry, fallback to locale name if failed (e.g. on Wine). + if (ret == String()) { + WCHAR buf[LOCALE_NAME_MAX_LENGTH]; + memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR)); + LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0); + + WCHAR name[1024]; + memset(name, 0, 1024 * sizeof(WCHAR)); + GetLocaleInfoEx(buf, LOCALE_SLOCALIZEDDISPLAYNAME, (LPWSTR)&name, 1024); - i = 0; - while (dvorak[i] != 0) { - if (dvorak[i] == hex) - return LATIN_KEYBOARD_DVORAK; - i++; + ret = String::utf16((const char16_t *)name); } + memfree(layouts); - return LATIN_KEYBOARD_QWERTY; + return ret; } void DisplayServerWindows::process_events() { @@ -1650,7 +1727,7 @@ void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float } Ref<InputEventScreenTouch> event; - event.instance(); + event.instantiate(); event->set_index(idx); event->set_window_id(p_window); event->set_pressed(p_pressed); @@ -1669,7 +1746,7 @@ void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y, return; Ref<InputEventScreenDrag> event; - event.instance(); + event.instantiate(); event->set_window_id(p_window); event->set_index(idx); event->set_position(Vector2(p_x, p_y)); @@ -1709,7 +1786,10 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) Ref<InputEventFromWindow> event_from_window = p_event; if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) { //send to a window - ERR_FAIL_COND(!windows.has(event_from_window->get_window_id())); + if (!windows.has(event_from_window->get_window_id())) { + in_dispatch_input_event = false; + ERR_FAIL_MSG("DisplayServerWindows: Invalid window id in input event."); + } Callable callable = windows[event_from_window->get_window_id()].input_event_callback; if (callable.is_null()) { in_dispatch_input_event = false; @@ -1740,14 +1820,22 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA }; WindowID window_id = INVALID_WINDOW_ID; + bool window_created = false; for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { if (E->get().hWnd == hWnd) { window_id = E->key(); + window_created = true; break; } } + if (!window_created) { + // Window creation in progress. + window_id = window_id_counter; + ERR_FAIL_COND_V(!windows.has(window_id), 0); + } + switch (uMsg) // Check For Windows Messages { case WM_SETFOCUS: { @@ -1757,6 +1845,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // Restore mouse mode _set_mouse_mode_impl(mouse_mode); + if (!app_focused) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); + } + app_focused = true; + } break; } case WM_KILLFOCUS: { @@ -1772,30 +1866,32 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } touch_state.clear(); + bool self_steal = false; + HWND new_hwnd = (HWND)wParam; + if (IsWindow(new_hwnd)) { + self_steal = true; + } + + if (!self_steal) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); + } + app_focused = false; + } + break; } - case WM_ACTIVATE: // Watch For Window Activate Message - { - windows[window_id].minimized = HIWORD(wParam) != 0; - - if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) { - _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN); - windows[window_id].window_focused = true; - alt_mem = false; - control_mem = false; - shift_mem = false; - } else { // WM_INACTIVE - Input::get_singleton()->release_pressed_events(); - _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT); - windows[window_id].window_focused = false; - alt_mem = false; - }; + case WM_ACTIVATE: { // Watch For Window Activate Message + if (!windows[window_id].window_focused) { + _process_activate_event(window_id, wParam, lParam); + } else { + windows[window_id].saved_wparam = wParam; + windows[window_id].saved_lparam = lParam; - if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { - wintab_WTEnable(windows[window_id].wtctx, GET_WM_ACTIVATE_STATE(wParam, lParam)); + // Run a timer to prevent event catching warning if the focused window is closing. + windows[window_id].focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); } - - return 0; // Return To The Message Loop + return 0; // Return To The Message Loop } case WM_GETMINMAXINFO: { if (windows[window_id].resizable && !windows[window_id].fullscreen) { @@ -1835,6 +1931,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_CLOSE: // Did We Receive A Close Message? { + if (windows[window_id].focus_timer_id != 0U) { + KillTimer(windows[window_id].hWnd, windows[window_id].focus_timer_id); + } _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST); return 0; // Jump Back @@ -1866,12 +1965,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (raw->header.dwType == RIM_TYPEMOUSE) { Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); - mm->set_control(control_mem); - mm->set_shift(shift_mem); - mm->set_alt(alt_mem); + mm->set_ctrl_pressed(control_mem); + mm->set_shift_pressed(shift_mem); + mm->set_alt_pressed(alt_mem); mm->set_pressure((raw->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_DOWN) ? 1.0f : 0.0f); @@ -1924,7 +2023,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } break; case WT_CSRCHANGE: case WT_PROXIMITY: { - if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { + if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { AXIS pressure; if (wintab_WTInfo(WTI_DEVICES + windows[window_id].wtlc.lcDevice, DVC_NPRESSURE, &pressure)) { windows[window_id].min_pressure = int(pressure.axMin); @@ -1938,7 +2037,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } break; case WT_PACKET: { - if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { + if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { PACKET packet; if (wintab_WTPacket(windows[window_id].wtctx, wParam, &packet)) { float pressure = float(packet.pkNormalPressure - windows[window_id].min_pressure) / float(windows[window_id].max_pressure - windows[window_id].min_pressure); @@ -1963,11 +2062,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); - mm->set_control(GetKeyState(VK_CONTROL) != 0); - mm->set_shift(GetKeyState(VK_SHIFT) != 0); - mm->set_alt(alt_mem); + mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0); + mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0); + mm->set_alt_pressed(alt_mem); mm->set_pressure(windows[window_id].last_pressure); mm->set_tilt(windows[window_id].last_tilt); @@ -2017,7 +2116,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; } - if ((OS::get_singleton()->get_current_tablet_driver() != "winink") || !winink_available) { + if ((tablet_get_current_driver() != "winink") || !winink_available) { break; } @@ -2043,7 +2142,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; } - if ((OS::get_singleton()->get_current_tablet_driver() != "winink") || !winink_available) { + if ((tablet_get_current_driver() != "winink") || !winink_available) { break; } @@ -2092,11 +2191,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode. - if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) + if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) { break; + } Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); if (pen_info.penMask & PEN_MASK_PRESSURE) { @@ -2108,9 +2208,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_tilt(Vector2((float)pen_info.tiltX / 90, (float)pen_info.tiltY / 90)); } - mm->set_control((wParam & MK_CONTROL) != 0); - mm->set_shift((wParam & MK_SHIFT) != 0); - mm->set_alt(alt_mem); + mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0); + mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0); + mm->set_alt_pressed(alt_mem); mm->set_button_mask(last_button_state); @@ -2197,18 +2297,19 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode. - if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) + if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) { break; + } Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); - mm->set_control((wParam & MK_CONTROL) != 0); - mm->set_shift((wParam & MK_SHIFT) != 0); - mm->set_alt(alt_mem); + mm->set_ctrl_pressed((wParam & MK_CONTROL) != 0); + mm->set_shift_pressed((wParam & MK_SHIFT) != 0); + mm->set_alt_pressed(alt_mem); - if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { - // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not update recently. + if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { + // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not updated recently. if (windows[window_id].last_pressure_update < 10) { windows[window_id].last_pressure_update++; } else { @@ -2284,110 +2385,117 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_XBUTTONDOWN: case WM_XBUTTONUP: { Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_window_id(window_id); switch (uMsg) { case WM_LBUTTONDOWN: { mb->set_pressed(true); - mb->set_button_index(1); + mb->set_button_index(MOUSE_BUTTON_LEFT); } break; case WM_LBUTTONUP: { mb->set_pressed(false); - mb->set_button_index(1); + mb->set_button_index(MOUSE_BUTTON_LEFT); } break; case WM_MBUTTONDOWN: { mb->set_pressed(true); - mb->set_button_index(3); + mb->set_button_index(MOUSE_BUTTON_MIDDLE); } break; case WM_MBUTTONUP: { mb->set_pressed(false); - mb->set_button_index(3); + mb->set_button_index(MOUSE_BUTTON_MIDDLE); } break; case WM_RBUTTONDOWN: { mb->set_pressed(true); - mb->set_button_index(2); + mb->set_button_index(MOUSE_BUTTON_RIGHT); } break; case WM_RBUTTONUP: { mb->set_pressed(false); - mb->set_button_index(2); + mb->set_button_index(MOUSE_BUTTON_RIGHT); } break; case WM_LBUTTONDBLCLK: { mb->set_pressed(true); - mb->set_button_index(1); - mb->set_doubleclick(true); + mb->set_button_index(MOUSE_BUTTON_LEFT); + mb->set_double_click(true); } break; case WM_RBUTTONDBLCLK: { mb->set_pressed(true); - mb->set_button_index(2); - mb->set_doubleclick(true); + mb->set_button_index(MOUSE_BUTTON_RIGHT); + mb->set_double_click(true); } break; case WM_MBUTTONDBLCLK: { mb->set_pressed(true); - mb->set_button_index(3); - mb->set_doubleclick(true); + mb->set_button_index(MOUSE_BUTTON_MIDDLE); + mb->set_double_click(true); } break; case WM_MOUSEWHEEL: { mb->set_pressed(true); int motion = (short)HIWORD(wParam); - if (!motion) + if (!motion) { return 0; + } - if (motion > 0) - mb->set_button_index(BUTTON_WHEEL_UP); - else - mb->set_button_index(BUTTON_WHEEL_DOWN); + if (motion > 0) { + mb->set_button_index(MOUSE_BUTTON_WHEEL_UP); + } else { + mb->set_button_index(MOUSE_BUTTON_WHEEL_DOWN); + } } break; case WM_MOUSEHWHEEL: { mb->set_pressed(true); int motion = (short)HIWORD(wParam); - if (!motion) + if (!motion) { return 0; + } if (motion < 0) { - mb->set_button_index(BUTTON_WHEEL_LEFT); + mb->set_button_index(MOUSE_BUTTON_WHEEL_LEFT); mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); } else { - mb->set_button_index(BUTTON_WHEEL_RIGHT); + mb->set_button_index(MOUSE_BUTTON_WHEEL_RIGHT); mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); } } break; case WM_XBUTTONDOWN: { mb->set_pressed(true); - if (HIWORD(wParam) == XBUTTON1) - mb->set_button_index(BUTTON_XBUTTON1); - else - mb->set_button_index(BUTTON_XBUTTON2); + if (HIWORD(wParam) == XBUTTON1) { + mb->set_button_index(MOUSE_BUTTON_XBUTTON1); + } else { + mb->set_button_index(MOUSE_BUTTON_XBUTTON2); + } } break; case WM_XBUTTONUP: { mb->set_pressed(false); - if (HIWORD(wParam) == XBUTTON1) - mb->set_button_index(BUTTON_XBUTTON1); - else - mb->set_button_index(BUTTON_XBUTTON2); + if (HIWORD(wParam) == XBUTTON1) { + mb->set_button_index(MOUSE_BUTTON_XBUTTON1); + } else { + mb->set_button_index(MOUSE_BUTTON_XBUTTON2); + } } break; case WM_XBUTTONDBLCLK: { mb->set_pressed(true); - if (HIWORD(wParam) == XBUTTON1) - mb->set_button_index(BUTTON_XBUTTON1); - else - mb->set_button_index(BUTTON_XBUTTON2); - mb->set_doubleclick(true); + if (HIWORD(wParam) == XBUTTON1) { + mb->set_button_index(MOUSE_BUTTON_XBUTTON1); + } else { + mb->set_button_index(MOUSE_BUTTON_XBUTTON2); + } + mb->set_double_click(true); } break; default: { return 0; } } - mb->set_control((wParam & MK_CONTROL) != 0); - mb->set_shift((wParam & MK_SHIFT) != 0); - mb->set_alt(alt_mem); - //mb->get_alt()=(wParam&MK_MENU)!=0; - if (mb->is_pressed()) - last_button_state |= (1 << (mb->get_button_index() - 1)); - else - last_button_state &= ~(1 << (mb->get_button_index() - 1)); + mb->set_ctrl_pressed((wParam & MK_CONTROL) != 0); + mb->set_shift_pressed((wParam & MK_SHIFT) != 0); + mb->set_alt_pressed(alt_mem); + //mb->is_alt_pressed()=(wParam&MK_MENU)!=0; + if (mb->is_pressed()) { + last_button_state |= MouseButton(1 << (mb->get_button_index() - 1)); + } else { + last_button_state &= (MouseButton) ~(1 << (mb->get_button_index() - 1)); + } mb->set_button_mask(last_button_state); mb->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); @@ -2426,7 +2534,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA //send release for mouse wheel Ref<InputEventMouseButton> mbd = mb->duplicate(); mbd->set_window_id(window_id); - last_button_state &= ~(1 << (mbd->get_button_index() - 1)); + last_button_state &= (MouseButton) ~(1 << (mbd->get_button_index() - 1)); mbd->set_button_mask(last_button_state); mbd->set_pressed(false); Input::get_singleton()->accumulate_input_event(mbd); @@ -2460,7 +2568,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA windows[window_id].height = window_h; #if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { + if ((rendering_driver == "vulkan") && window_created) { context_vulkan->window_resize(window_id, windows[window_id].width, windows[window_id].height); } #endif @@ -2469,6 +2577,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA windows[window_id].preserve_window_size = false; window_set_size(Size2(windows[window_id].width, windows[window_id].height), window_id); } + } else { + windows[window_id].preserve_window_size = true; } if (!windows[window_id].rect_changed_callback.is_null()) { @@ -2517,17 +2627,21 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_ENTERSIZEMOVE: { Input::get_singleton()->release_pressed_events(); - move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); + windows[window_id].move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); } break; case WM_EXITSIZEMOVE: { - KillTimer(windows[window_id].hWnd, move_timer_id); + KillTimer(windows[window_id].hWnd, windows[window_id].move_timer_id); } break; case WM_TIMER: { - if (wParam == move_timer_id) { + if (wParam == windows[window_id].move_timer_id) { _process_key_events(); if (!Main::is_iterating()) { Main::iteration(); } + } else if (wParam == windows[window_id].focus_timer_id) { + _process_activate_event(window_id, windows[window_id].saved_wparam, windows[window_id].saved_lparam); + KillTimer(windows[window_id].hWnd, wParam); + windows[window_id].focus_timer_id = 0U; } } break; @@ -2536,9 +2650,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_KEYUP: case WM_KEYDOWN: { if (wParam == VK_SHIFT) - shift_mem = uMsg == WM_KEYDOWN; + shift_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); if (wParam == VK_CONTROL) - control_mem = uMsg == WM_KEYDOWN; + control_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); if (wParam == VK_MENU) { alt_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); if (lParam & (1 << 24)) @@ -2623,12 +2737,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } break; case WM_SETCURSOR: { if (LOWORD(lParam) == HTCLIENT) { - if (windows[window_id].window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED)) { + if (windows[window_id].window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN)) { //Hide the cursor - if (hCursor == nullptr) + if (hCursor == nullptr) { hCursor = SetCursor(nullptr); - else + } else { SetCursor(nullptr); + } } else { if (hCursor != nullptr) { CursorShape c = cursor_shape; @@ -2643,7 +2758,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_DROPFILES: { HDROP hDropInfo = (HDROP)wParam; const int buffsize = 4096; - wchar_t buf[buffsize]; + WCHAR buf[buffsize]; int fcount = DragQueryFileW(hDropInfo, 0xFFFFFFFF, nullptr, 0); @@ -2651,7 +2766,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA for (int i = 0; i < fcount; i++) { DragQueryFileW(hDropInfo, i, buf, buffsize); - String file = buf; + String file = String::utf16((const char16_t *)buf); files.push_back(file); } @@ -2683,6 +2798,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProcW(hWnd, uMsg, wParam, lParam); } +void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam) { + if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) { + _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN); + windows[p_window_id].window_focused = true; + alt_mem = false; + control_mem = false; + shift_mem = false; + } else { // WM_INACTIVE + Input::get_singleton()->release_pressed_events(); + _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT); + windows[p_window_id].window_focused = false; + alt_mem = false; + } + + if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window_id].wtctx) { + wintab_WTEnable(windows[p_window_id].wtctx, GET_WM_ACTIVATE_STATE(wParam, lParam)); + } +} + void DisplayServerWindows::_process_key_events() { for (int i = 0; i < key_event_pos; i++) { KeyEvent &ke = key_event_buffer[i]; @@ -2690,21 +2824,39 @@ void DisplayServerWindows::_process_key_events() { case WM_CHAR: { // extended keys should only be processed as WM_KEYDOWN message. if (!KeyMappingWindows::is_extended_key(ke.wParam) && ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR))) { + static char32_t prev_wc = 0; + char32_t unicode = ke.wParam; + if ((unicode & 0xfffffc00) == 0xd800) { + if (prev_wc != 0) { + ERR_PRINT("invalid utf16 surrogate input"); + } + prev_wc = unicode; + break; // Skip surrogate. + } else if ((unicode & 0xfffffc00) == 0xdc00) { + if (prev_wc == 0) { + ERR_PRINT("invalid utf16 surrogate input"); + break; // Skip invalid surrogate. + } + unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000); + prev_wc = 0; + } else { + prev_wc = 0; + } Ref<InputEventKey> k; - k.instance(); + k.instantiate(); k->set_window_id(ke.window_id); - k->set_shift(ke.shift); - k->set_alt(ke.alt); - k->set_control(ke.control); - k->set_metakey(ke.meta); + k->set_shift_pressed(ke.shift); + k->set_alt_pressed(ke.alt); + k->set_ctrl_pressed(ke.control); + k->set_meta_pressed(ke.meta); k->set_pressed(true); k->set_keycode(KeyMappingWindows::get_keysym(ke.wParam)); k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24))); - k->set_unicode(ke.wParam); + k->set_unicode(unicode); if (k->get_unicode() && gr_mem) { - k->set_alt(false); - k->set_control(false); + k->set_alt_pressed(false); + k->set_ctrl_pressed(false); } if (k->get_unicode() < 32) @@ -2718,13 +2870,13 @@ void DisplayServerWindows::_process_key_events() { case WM_KEYUP: case WM_KEYDOWN: { Ref<InputEventKey> k; - k.instance(); + k.instantiate(); k->set_window_id(ke.window_id); - k->set_shift(ke.shift); - k->set_alt(ke.alt); - k->set_control(ke.control); - k->set_metakey(ke.meta); + k->set_shift_pressed(ke.shift); + k->set_alt_pressed(ke.alt); + k->set_ctrl_pressed(ke.control); + k->set_meta_pressed(ke.meta); k->set_pressed(ke.uMsg == WM_KEYDOWN); @@ -2738,11 +2890,29 @@ void DisplayServerWindows::_process_key_events() { k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24))); if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) { - k->set_unicode(key_event_buffer[i + 1].wParam); + char32_t unicode = key_event_buffer[i + 1].wParam; + static char32_t prev_wck = 0; + if ((unicode & 0xfffffc00) == 0xd800) { + if (prev_wck != 0) { + ERR_PRINT("invalid utf16 surrogate input"); + } + prev_wck = unicode; + break; // Skip surrogate. + } else if ((unicode & 0xfffffc00) == 0xdc00) { + if (prev_wck == 0) { + ERR_PRINT("invalid utf16 surrogate input"); + break; // Skip invalid surrogate. + } + unicode = (prev_wck << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000); + prev_wck = 0; + } else { + prev_wck = 0; + } + k->set_unicode(unicode); } if (k->get_unicode() && gr_mem) { - k->set_alt(false); - k->set_control(false); + k->set_alt_pressed(false); + k->set_ctrl_pressed(false); } if (k->get_unicode() < 32) @@ -2811,11 +2981,32 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, WindowRect.top = p_rect.position.y; WindowRect.bottom = p_rect.position.y + p_rect.size.y; + if (p_mode == WINDOW_MODE_FULLSCREEN) { + int nearest_area = 0; + Rect2i screen_rect; + for (int i = 0; i < get_screen_count(); i++) { + Rect2i r; + r.position = screen_get_position(i); + r.size = screen_get_size(i); + Rect2 inters = r.intersection(p_rect); + int area = inters.size.width * inters.size.height; + if (area >= nearest_area) { + screen_rect = r; + nearest_area = area; + } + } + + WindowRect.left = screen_rect.position.x; + WindowRect.right = screen_rect.position.x + screen_rect.size.x; + WindowRect.top = screen_rect.position.y; + WindowRect.bottom = screen_rect.position.y + screen_rect.size.y; + } + AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); WindowID id = window_id_counter; { - WindowData wd; + WindowData &wd = windows[id]; wd.hWnd = CreateWindowExW( dwExStyle, @@ -2830,15 +3021,20 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, nullptr, nullptr, hInstance, nullptr); if (!wd.hWnd) { MessageBoxW(nullptr, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION); + windows.erase(id); return INVALID_WINDOW_ID; } + if (p_mode != WINDOW_MODE_FULLSCREEN) { + wd.pre_fs_valid = true; + } #ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { if (context_vulkan->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) { memdelete(context_vulkan); context_vulkan = nullptr; - ERR_FAIL_V(INVALID_WINDOW_ID); + windows.erase(id); + ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Vulkan Window."); } } #endif @@ -2854,7 +3050,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, DragAcceptFiles(wd.hWnd, true); - if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available) { + if ((tablet_get_current_driver() == "wintab") && wintab_available) { wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc); wd.wtlc.lcOptions |= CXO_MESSAGES; wd.wtlc.lcPktData = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION; @@ -2896,8 +3092,6 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, wd.width = p_rect.size.width; wd.height = p_rect.size.height; - windows[id] = wd; - window_id_counter++; } @@ -2923,6 +3117,40 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS { SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2 } SHC_PROCESS_DPI_AWARENESS; +int DisplayServerWindows::tablet_get_driver_count() const { + return tablet_drivers.size(); +} + +String DisplayServerWindows::tablet_get_driver_name(int p_driver) const { + if (p_driver < 0 || p_driver >= tablet_drivers.size()) { + return ""; + } else { + return tablet_drivers[p_driver]; + } +} + +String DisplayServerWindows::tablet_get_current_driver() const { + return tablet_driver; +} + +void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) { + if (tablet_get_driver_count() == 0) { + return; + } + bool found = false; + for (int i = 0; i < tablet_get_driver_count(); i++) { + if (p_driver == tablet_get_driver_name(i)) { + found = true; + } + } + if (found) { + _update_tablet_ctx(tablet_driver, p_driver); + tablet_driver = p_driver; + } else { + ERR_PRINT("Unknown tablet driver " + p_driver + "."); + } +} + DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { drop_events = false; key_event_pos = 0; @@ -2941,6 +3169,35 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win outside = true; + //Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink. + HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll"); + if (wintab_lib) { + wintab_WTOpen = (WTOpenPtr)GetProcAddress(wintab_lib, "WTOpenW"); + wintab_WTClose = (WTClosePtr)GetProcAddress(wintab_lib, "WTClose"); + wintab_WTInfo = (WTInfoPtr)GetProcAddress(wintab_lib, "WTInfoW"); + wintab_WTPacket = (WTPacketPtr)GetProcAddress(wintab_lib, "WTPacket"); + wintab_WTEnable = (WTEnablePtr)GetProcAddress(wintab_lib, "WTEnable"); + + wintab_available = wintab_WTOpen && wintab_WTClose && wintab_WTInfo && wintab_WTPacket && wintab_WTEnable; + } + + if (wintab_available) { + tablet_drivers.push_back("wintab"); + } + + //Note: Windows Ink API for pen input, available on Windows 8+ only. + HMODULE user32_lib = LoadLibraryW(L"user32.dll"); + if (user32_lib) { + win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType"); + win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo"); + + winink_available = win8p_GetPointerType && win8p_GetPointerPenInfo; + } + + if (winink_available) { + tablet_drivers.push_back("winink"); + } + if (OS::get_singleton()->is_hidpi_allowed()) { HMODULE Shcore = LoadLibraryW(L"Shcore.dll"); @@ -3028,16 +3285,17 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win Point2i window_position( (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); + WindowID main_window = _create_window(p_mode, 0, Rect2i(window_position, p_resolution)); + ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); + for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, main_window); } } - ShowWindow(windows[MAIN_WINDOW_ID].hWnd, SW_SHOW); // Show The Window - SetForegroundWindow(windows[MAIN_WINDOW_ID].hWnd); // Slightly Higher Priority - SetFocus(windows[MAIN_WINDOW_ID].hWnd); // Sets Keyboard Focus To + show_window(MAIN_WINDOW_ID); #if defined(VULKAN_ENABLED) @@ -3045,12 +3303,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win rendering_device_vulkan = memnew(RenderingDeviceVulkan); rendering_device_vulkan->initialize(context_vulkan); - RasterizerRD::make_current(); + RendererCompositorRD::make_current(); } #endif - move_timer_id = 1; - //set_ime_active(false); if (!OS::get_singleton()->is_in_low_processor_usage_mode()) { @@ -3092,7 +3348,13 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() { } DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - return memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); + DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); + if (r_error != OK) { + ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n" + "Please update your drivers or if you have a very old or integrated GPU upgrade it.", + "Unable to initialize Video driver"); + } + return ds; } void DisplayServerWindows::register_windows_driver() { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index caf8598dc2..d71e579c67 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,9 +33,9 @@ #include "servers/display_server.h" +#include "core/config/project_settings.h" #include "core/input/input.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "crash_handler_windows.h" #include "drivers/unix/ip_unix.h" #include "drivers/wasapi/audio_driver_wasapi.h" @@ -43,8 +43,8 @@ #include "joypad_windows.h" #include "key_mapping_windows.h" #include "servers/audio_server.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/rasterizer_rd.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #include "servers/rendering_server.h" #ifdef XAUDIO2_ENABLED @@ -264,7 +264,6 @@ class DisplayServerWindows : public DisplayServer { _THREAD_SAFE_CLASS_ -public: // WinTab API static bool wintab_available; static WTOpenPtr wintab_WTOpen; @@ -279,8 +278,9 @@ public: static GetPointerPenInfoPtr win8p_GetPointerPenInfo; void _update_tablet_ctx(const String &p_old_driver, const String &p_new_driver); + String tablet_driver; + Vector<String> tablet_drivers; -private: void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap); enum { @@ -317,11 +317,14 @@ private: int pressrc; HINSTANCE hInstance; // Holds The Instance Of The Application String rendering_driver; + bool app_focused = false; struct WindowData { HWND hWnd; //layered window + Vector<Vector2> mpath; + bool preserve_window_size = false; bool pre_fs_valid = false; RECT pre_fs_rect; @@ -336,6 +339,14 @@ private: bool no_focus = false; bool window_has_focus = false; + // Used to transfer data between events using timer. + WPARAM saved_wparam; + LPARAM saved_lparam; + + // Timers. + uint32_t move_timer_id = 0U; + uint32_t focus_timer_id = 0U; + HANDLE wtctx; LOGCONTEXTW wtlc; int min_pressure; @@ -384,8 +395,6 @@ private: WindowID last_focused_window = INVALID_WINDOW_ID; - uint32_t move_timer_id; - HCURSOR hCursor; WNDPROC user_proc = nullptr; @@ -399,7 +408,7 @@ private: bool shift_mem = false; bool control_mem = false; bool meta_mem = false; - uint32_t last_button_state = 0; + MouseButton last_button_state = MOUSE_BUTTON_NONE; bool use_raw_input = false; bool drop_events = false; bool in_dispatch_input_event = false; @@ -408,18 +417,20 @@ private: WNDCLASSEXW wc; HCURSOR cursors[CURSOR_MAX] = { nullptr }; - CursorShape cursor_shape; + CursorShape cursor_shape = CursorShape::CURSOR_ARROW; Map<CursorShape, Vector<Variant>> cursors_cache; void _drag_event(WindowID p_window, float p_x, float p_y, int idx); void _touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx); - void _update_window_style(WindowID p_window, bool p_repaint = true, bool p_maximized = false); + void _update_window_style(WindowID p_window, bool p_repaint = true); + void _update_window_mouse_passthrough(WindowID p_window); void _update_real_mouse_position(WindowID p_window); void _set_mouse_mode_impl(MouseMode p_mode); + void _process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam); void _process_key_events(); static void _dispatch_input_events(const Ref<InputEvent> &p_event); @@ -438,7 +449,7 @@ public: virtual void mouse_warp_to_position(const Point2i &p_to); virtual Point2i mouse_get_position() const; - virtual int mouse_get_button_state() const; + virtual MouseButton mouse_get_button_state() const; virtual void clipboard_set(const String &p_text); virtual String clipboard_get() const; @@ -459,6 +470,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const; virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual void show_window(WindowID p_window); virtual void delete_sub_window(WindowID p_window); virtual WindowID get_window_at_screen_position(const Point2i &p_position) const; @@ -475,6 +487,7 @@ public: virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID); + virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID); virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const; virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID); @@ -519,11 +532,20 @@ public: virtual CursorShape cursor_get_shape() const; virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()); - virtual bool get_swap_ok_cancel(); + virtual bool get_swap_cancel_ok(); virtual void enable_for_stealing_focus(OS::ProcessID pid); - virtual LatinKeyboardVariant get_latin_keyboard_variant() const; + virtual int keyboard_get_layout_count() const; + virtual int keyboard_get_current_layout() const; + virtual void keyboard_set_current_layout(int p_index); + virtual String keyboard_get_layout_language(int p_index) const; + virtual String keyboard_get_layout_name(int p_index) const; + + virtual int tablet_get_driver_count() const; + virtual String tablet_get_driver_name(int p_driver) const; + virtual String tablet_get_current_driver() const; + virtual void tablet_set_current_driver(const String &p_driver); virtual void process_events(); diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index c2436e8b64..10f953f2ec 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "editor/editor_export.h" #include "editor/editor_node.h" @@ -173,11 +173,11 @@ void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> } #ifdef WINDOWS_ENABLED - OS::get_singleton()->execute(rcedit_path, args, true); + OS::get_singleton()->execute(rcedit_path, args); #else // On non-Windows we need WINE to run rcedit args.push_front(rcedit_path); - OS::get_singleton()->execute(wine_path, args, true); + OS::get_singleton()->execute(wine_path, args); #endif } @@ -299,7 +299,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p PackedStringArray user_args = p_preset->get("codesign/custom_options"); for (int i = 0; i < user_args.size(); i++) { String user_arg = user_args[i].strip_edges(); - if (!user_arg.empty()) { + if (!user_arg.is_empty()) { args.push_back(user_arg); } } @@ -310,11 +310,11 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p args.push_back(p_path); #ifndef WINDOWS_ENABLED args.push_back("-out"); - args.push_back(p_path); + args.push_back(p_path + "_signed"); #endif String str; - Error err = OS::get_singleton()->execute(signtool_path, args, true, nullptr, &str, nullptr, true); + Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true); ERR_FAIL_COND_V(err != OK, err); print_line("codesign (" + p_path + "): " + str); @@ -326,6 +326,16 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p return FAILED; } +#ifndef WINDOWS_ENABLED + DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir()); + + err = tmp_dir->remove(p_path); + ERR_FAIL_COND_V(err != OK, err); + + err = tmp_dir->rename(p_path + "_signed", p_path); + ERR_FAIL_COND_V(err != OK, err); +#endif + return OK; } @@ -344,11 +354,11 @@ void register_windows_exporter() { #endif Ref<EditorExportPlatformWindows> platform; - platform.instance(); + platform.instantiate(); Ref<Image> img = memnew(Image(_windows_logo)); Ref<ImageTexture> logo; - logo.instance(); + logo.instantiate(); logo->create_from_image(img); platform->set_logo(logo); platform->set_name("Windows Desktop"); diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h index d669192831..6a7131c73f 100644 --- a/platform/windows/export/export.h +++ b/platform/windows/export/export.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index 593557cc69..bb855e4ac8 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -10,16 +10,16 @@ </Expand> </Type> - <Type Name="PoolVector<*>"> + <Type Name="LocalVector<*>"> <Expand> - <Item Name="[size]">alloc ? (alloc->size / sizeof($T1)) : 0</Item> + <Item Name="[size]">count</Item> <ArrayItems> - <Size>alloc ? (alloc->size / sizeof($T1)) : 0</Size> - <ValuePointer>alloc ? (($T1 *)alloc->mem) : 0</ValuePointer> + <Size>count</Size> + <ValuePointer>data</ValuePointer> </ArrayItems> </Expand> </Type> - + <Type Name="List<*>"> <Expand> <Item Name="[size]">_data ? (_data->size_cache) : 0</Item> @@ -36,75 +36,79 @@ <DisplayString Condition="type == Variant::NIL">nil</DisplayString> <DisplayString Condition="type == Variant::BOOL">{_data._bool}</DisplayString> <DisplayString Condition="type == Variant::INT">{_data._int}</DisplayString> - <DisplayString Condition="type == Variant::REAL">{_data._real}</DisplayString> + <DisplayString Condition="type == Variant::FLOAT">{_data._float}</DisplayString> <DisplayString Condition="type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString> <DisplayString Condition="type == Variant::AABB">{_data._aabb}</DisplayString> <DisplayString Condition="type == Variant::BASIS">{_data._basis}</DisplayString> - <DisplayString Condition="type == Variant::TRANSFORM">{_data._transform}</DisplayString> + <DisplayString Condition="type == Variant::TRANSFORM3D">{_data._transform}</DisplayString> <DisplayString Condition="type == Variant::STRING">{*(String *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::QUAT">{*(Quat *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::QUATERNION">{*(Quaternion *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::NODE_PATH">{*(NodePath *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::_RID">{*(RID *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::RID">{*(::RID *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::OBJECT">{*(Object *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::POOL_BYTE_ARRAY">{*(PoolByteArray *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::POOL_INT_ARRAY">{*(PoolIntArray *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::POOL_REAL_ARRAY">{*(PoolRealArray *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::POOL_STRING_ARRAY">{*(PoolStringArray *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::POOL_VECTOR2_ARRAY">{*(PoolVector2Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::POOL_VECTOR3_ARRAY">{*(PoolVector3Array *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::POOL_COLOR_ARRAY">{*(PoolColorArray *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_BYTE_ARRAY">{*(PackedByteArray *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_INT32_ARRAY">{*(PackedInt32Array *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_INT64_ARRAY">{*(PackedInt64Array *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_FLOAT32_ARRAY">{*(PackedFloat32Array *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_FLOAT64_ARRAY">{*(PackedFloat64Array *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_STRING_ARRAY">{*(PackedStringArray *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_VECTOR2_ARRAY">{*(PackedVector2Array *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_VECTOR3_ARRAY">{*(PackedVector3Array *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::PACKED_COLOR_ARRAY">{*(PackedColorArray *)_data._mem}</DisplayString> + + <StringView Condition="type == Variant::STRING && ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,s32</StringView> - <StringView Condition="type == Variant::STRING && ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,su</StringView> - <Expand> <Item Name="[value]" Condition="type == Variant::BOOL">_data._bool</Item> <Item Name="[value]" Condition="type == Variant::INT">_data._int</Item> - <Item Name="[value]" Condition="type == Variant::REAL">_data._real</Item> + <Item Name="[value]" Condition="type == Variant::FLOAT">_data._float</Item> <Item Name="[value]" Condition="type == Variant::TRANSFORM2D">_data._transform2d</Item> <Item Name="[value]" Condition="type == Variant::AABB">_data._aabb</Item> <Item Name="[value]" Condition="type == Variant::BASIS">_data._basis</Item> - <Item Name="[value]" Condition="type == Variant::TRANSFORM">_data._transform</Item> + <Item Name="[value]" Condition="type == Variant::TRANSFORM3D">_data._transform</Item> <Item Name="[value]" Condition="type == Variant::STRING">*(String *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::RECT2">*(Rect2 *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::VECTOR3">*(Vector3 *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::PLANE">*(Plane *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::QUAT">*(Quat *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::QUATERNION">*(Quaternion *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::COLOR">*(Color *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::NODE_PATH">*(NodePath *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::_RID">*(RID *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::RID">*(::RID *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::OBJECT">*(Object *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::DICTIONARY">*(Dictionary *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::ARRAY">*(Array *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::POOL_BYTE_ARRAY">*(PoolByteArray *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::POOL_INT_ARRAY">*(PoolIntArray *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::POOL_REAL_ARRAY">*(PoolRealArray *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::POOL_STRING_ARRAY">*(PoolStringArray *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::POOL_VECTOR2_ARRAY">*(PoolVector2Array *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::POOL_VECTOR3_ARRAY">*(PoolVector3Array *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::POOL_COLOR_ARRAY">*(PoolColorArray *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_BYTE_ARRAY">*(PackedByteArray *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_INT32_ARRAY">*(PackedInt32Array *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_INT64_ARRAY">*(PackedInt64Array *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_FLOAT32_ARRAY">*(PackedFloat32Array *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_FLOAT64_ARRAY">*(PackedFloat64Array *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_STRING_ARRAY">*(PackedStringArray *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_VECTOR2_ARRAY">*(PackedVector2Array *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_VECTOR3_ARRAY">*(PackedVector3Array *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::PACKED_COLOR_ARRAY">*(PackedColorArray *)_data._mem</Item> </Expand> </Type> <Type Name="String"> <DisplayString Condition="_cowdata._ptr == 0">[empty]</DisplayString> - <DisplayString Condition="_cowdata._ptr != 0">{_cowdata._ptr,su}</DisplayString> - <StringView Condition="_cowdata._ptr != 0">_cowdata._ptr,su</StringView> + <DisplayString Condition="_cowdata._ptr != 0">{_cowdata._ptr,s32}</DisplayString> + <StringView Condition="_cowdata._ptr != 0">_cowdata._ptr,s32</StringView> </Type> <Type Name="StringName"> <DisplayString Condition="_data && _data->cname">{_data->cname}</DisplayString> - <DisplayString Condition="_data && !_data->cname">{_data->name,su}</DisplayString> + <DisplayString Condition="_data && !_data->cname">{_data->name,s32}</DisplayString> <DisplayString Condition="!_data">[empty]</DisplayString> <StringView Condition="_data && _data->cname">_data->cname</StringView> - <StringView Condition="_data && !_data->cname">_data->name,su</StringView> + <StringView Condition="_data && !_data->cname">_data->name,s32</StringView> </Type> <Type Name="Vector2"> @@ -124,8 +128,8 @@ </Expand> </Type> - <Type Name="Quat"> - <DisplayString>Quat {{{x},{y},{z},{w}}}</DisplayString> + <Type Name="Quaternion"> + <DisplayString>Quaternion {{{x},{y},{z},{w}}}</DisplayString> <Expand> <Item Name="x">x</Item> <Item Name="y">y</Item> @@ -143,7 +147,7 @@ <Item Name="alpha">a</Item> </Expand> </Type> - + <Type Name="Node" Inheritable="false"> <Expand> <Item Name="Object">(Object*)this</Item> diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp index 910059a9fc..22e2e5f7e5 100644 --- a/platform/windows/godot_windows.cpp +++ b/platform/windows/godot_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -146,6 +146,8 @@ int widechar_main(int argc, wchar_t **argv) { argv_utf8[i] = wc_to_utf8(argv[i]); } + TEST_MAIN_PARAM_OVERRIDE(argc, argv_utf8) + Error err = Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]); if (err != OK) { @@ -186,10 +188,12 @@ int _main() { return result; } -int main(int _argc, char **_argv) { +int main(int argc, char **argv) { + // override the arguments for the test handler / if symbol is provided + // TEST_MAIN_OVERRIDE + // _argc and _argv are ignored // we are going to use the WideChar version of them instead - #ifdef CRASH_HANDLER_EXCEPTION __try { return _main(); diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index 0cff12ca8c..94da63e49d 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,10 +33,6 @@ #include <oleauto.h> #include <wbemidl.h> -#ifndef __GNUC__ -#define __builtin_bswap32 _byteswap_ulong -#endif - #if defined(__GNUC__) // Workaround GCC warning from -Wcast-function-type. #define GetProcAddress (void *)GetProcAddress @@ -67,17 +63,25 @@ JoypadWindows::JoypadWindows(HWND *hwnd) { for (int i = 0; i < JOYPADS_MAX; i++) attached_joypads[i] = false; - HRESULT result; - result = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, nullptr); - if (FAILED(result)) { - printf("failed init DINPUT: %ld\n", result); + HRESULT result = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, nullptr); + if (result == DI_OK) { + probe_joypads(); + } else { + ERR_PRINT("Couldn't initialize DirectInput. Error: " + itos(result)); + if (result == DIERR_OUTOFMEMORY) { + ERR_PRINT("The Windows DirectInput subsystem could not allocate sufficient memory."); + ERR_PRINT("Rebooting your PC may solve this issue."); + } + // Ensure dinput is still a nullptr. + dinput = nullptr; } - probe_joypads(); } JoypadWindows::~JoypadWindows() { close_joypad(); - dinput->Release(); + if (dinput) { + dinput->Release(); + } unload_xinput(); } @@ -106,12 +110,11 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) { if (GetRawInputDeviceList(nullptr, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) { return false; } - dev_list = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count); - if (!dev_list) - return false; + dev_list = (PRAWINPUTDEVICELIST)memalloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count); + ERR_FAIL_NULL_V_MSG(dev_list, false, "Out of memory."); if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) { - free(dev_list); + memfree(dev_list); return false; } for (unsigned int i = 0; i < dev_list_count; i++) { @@ -126,27 +129,28 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) { (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) && (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) && (strstr(dev_name, "IG_") != nullptr)) { - free(dev_list); + memfree(dev_list); return true; } } - free(dev_list); + memfree(dev_list); return false; } bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) { + ERR_FAIL_NULL_V_MSG(dinput, false, "DirectInput not initialized. Rebooting your PC may solve this issue."); HRESULT hr; int num = input->get_unused_joy_id(); if (have_device(instance->guidInstance) || num == -1) return false; - d_joypads[joypad_count] = dinput_gamepad(); - dinput_gamepad *joy = &d_joypads[joypad_count]; + d_joypads[num] = dinput_gamepad(); + dinput_gamepad *joy = &d_joypads[num]; const DWORD devtype = (instance->dwDevType & 0xFF); - if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON)) { + if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON) && (devtype != DI8DEVTYPE_DRIVING)) { return false; } @@ -158,12 +162,16 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) { const GUID &guid = instance->guidProduct; char uid[128]; - sprintf_s(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", - __builtin_bswap32(guid.Data1), guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], - guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); - id_to_change = joypad_count; + ERR_FAIL_COND_V_MSG(memcmp(&guid.Data4[2], "PIDVID", 6), false, "DirectInput device not recognised."); + WORD type = BSWAP16(0x03); + WORD vendor = BSWAP16(LOWORD(guid.Data1)); + WORD product = BSWAP16(HIWORD(guid.Data1)); + WORD version = 0; + sprintf_s(uid, "%04x%04x%04x%04x%04x%04x%04x%04x", type, 0, vendor, 0, product, 0, version, 0); + + id_to_change = num; + slider_count = 0; joy->di_joy->SetDataFormat(&c_dfDIJoystick2); joy->di_joy->SetCooperativeLevel(*hWnd, DISCL_FOREGROUND); @@ -185,7 +193,7 @@ void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_ HRESULT res; DIPROPRANGE prop_range; DIPROPDWORD dilong; - DWORD ofs; + LONG ofs; if (ob->guidType == GUID_XAxis) ofs = DIJOFS_X; else if (ob->guidType == GUID_YAxis) @@ -198,9 +206,14 @@ void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_ ofs = DIJOFS_RY; else if (ob->guidType == GUID_RzAxis) ofs = DIJOFS_RZ; - else if (ob->guidType == GUID_Slider) - ofs = DIJOFS_SLIDER(0); - else + else if (ob->guidType == GUID_Slider) { + if (slider_count < 2) { + ofs = DIJOFS_SLIDER(slider_count); + slider_count++; + } else { + return; + } + } else return; prop_range.diph.dwSize = sizeof(DIPROPRANGE); prop_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); @@ -266,6 +279,7 @@ void JoypadWindows::close_joypad(int id) { } void JoypadWindows::probe_joypads() { + ERR_FAIL_NULL_MSG(dinput, "DirectInput not initialized. Rebooting your PC may solve this issue."); DWORD dwResult; for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) { ZeroMemory(&x_joypads[i].state, sizeof(XINPUT_STATE)); @@ -316,7 +330,7 @@ void JoypadWindows::process_joypads() { if (joy.state.dwPacketNumber != joy.last_packet) { int button_mask = XINPUT_GAMEPAD_DPAD_UP; for (int j = 0; j <= 16; j++) { - input->joy_button(joy.id, j, joy.state.Gamepad.wButtons & button_mask); + input->joy_button(joy.id, (JoyButton)j, joy.state.Gamepad.wButtons & button_mask); button_mask = button_mask * 2; } @@ -367,26 +381,26 @@ void JoypadWindows::process_joypads() { for (int j = 0; j < 128; j++) { if (js.rgbButtons[j] & 0x80) { if (!joy->last_buttons[j]) { - input->joy_button(joy->id, j, true); + input->joy_button(joy->id, (JoyButton)j, true); joy->last_buttons[j] = true; } } else { if (joy->last_buttons[j]) { - input->joy_button(joy->id, j, false); + input->joy_button(joy->id, (JoyButton)j, false); joy->last_buttons[j] = false; } } } // on mingw, these constants are not constants - int count = 6; - unsigned int axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ }; - int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz }; + int count = 8; + LONG axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, (LONG)DIJOFS_SLIDER(0), (LONG)DIJOFS_SLIDER(1) }; + int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz, js.rglSlider[0], js.rglSlider[1] }; for (int j = 0; j < joy->joy_axis.size(); j++) { for (int k = 0; k < count; k++) { if (joy->joy_axis[j] == axes[k]) { - input->joy_axis(joy->id, j, axis_correct(values[k])); + input->joy_axis(joy->id, (JoyAxis)j, axis_correct(values[k])); break; }; }; @@ -396,44 +410,44 @@ void JoypadWindows::process_joypads() { } void JoypadWindows::post_hat(int p_device, DWORD p_dpad) { - int dpad_val = 0; + HatMask dpad_val = (HatMask)0; // Should be -1 when centered, but according to docs: // "Some drivers report the centered position of the POV indicator as 65,535. Determine whether the indicator is centered as follows: // BOOL POVCentered = (LOWORD(dwPOV) == 0xFFFF);" // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v%3Dvs.85)#remarks if (LOWORD(p_dpad) == 0xFFFF) { - dpad_val = Input::HAT_MASK_CENTER; + dpad_val = (HatMask)HatMask::HAT_MASK_CENTER; } if (p_dpad == 0) { - dpad_val = Input::HAT_MASK_UP; + dpad_val = (HatMask)HatMask::HAT_MASK_UP; } else if (p_dpad == 4500) { - dpad_val = (Input::HAT_MASK_UP | Input::HAT_MASK_RIGHT); + dpad_val = (HatMask)(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_RIGHT); } else if (p_dpad == 9000) { - dpad_val = Input::HAT_MASK_RIGHT; + dpad_val = (HatMask)HatMask::HAT_MASK_RIGHT; } else if (p_dpad == 13500) { - dpad_val = (Input::HAT_MASK_RIGHT | Input::HAT_MASK_DOWN); + dpad_val = (HatMask)(HatMask::HAT_MASK_RIGHT | HatMask::HAT_MASK_DOWN); } else if (p_dpad == 18000) { - dpad_val = Input::HAT_MASK_DOWN; + dpad_val = (HatMask)HatMask::HAT_MASK_DOWN; } else if (p_dpad == 22500) { - dpad_val = (Input::HAT_MASK_DOWN | Input::HAT_MASK_LEFT); + dpad_val = (HatMask)(HatMask::HAT_MASK_DOWN | HatMask::HAT_MASK_LEFT); } else if (p_dpad == 27000) { - dpad_val = Input::HAT_MASK_LEFT; + dpad_val = (HatMask)HatMask::HAT_MASK_LEFT; } else if (p_dpad == 31500) { - dpad_val = (Input::HAT_MASK_LEFT | Input::HAT_MASK_UP); + dpad_val = (HatMask)(HatMask::HAT_MASK_LEFT | HatMask::HAT_MASK_UP); } input->joy_hat(p_device, dpad_val); }; -Input::JoyAxis JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const { - Input::JoyAxis jx; +Input::JoyAxisValue JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const { + Input::JoyAxisValue jx; if (Math::abs(p_val) < MIN_JOY_AXIS) { jx.min = p_trigger ? 0 : -1; jx.value = 0.0f; diff --git a/platform/windows/joypad_windows.h b/platform/windows/joypad_windows.h index 6c06b3f6f0..757fb54fb3 100644 --- a/platform/windows/joypad_windows.h +++ b/platform/windows/joypad_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -77,7 +77,7 @@ private: DWORD last_pad; LPDIRECTINPUTDEVICE8 di_joy; - List<DWORD> joy_axis; + List<LONG> joy_axis; GUID guid; dinput_gamepad() { @@ -92,21 +92,13 @@ private: }; struct xinput_gamepad { - int id; - bool attached; - bool vibrating; - DWORD last_packet; + int id = 0; + bool attached = false; + bool vibrating = false; + DWORD last_packet = 0; XINPUT_STATE state; - uint64_t ff_timestamp; - uint64_t ff_end_timestamp; - - xinput_gamepad() { - attached = false; - vibrating = false; - ff_timestamp = 0; - ff_end_timestamp = 0; - last_packet = 0; - } + uint64_t ff_timestamp = 0; + uint64_t ff_end_timestamp = 0; }; typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState); @@ -118,6 +110,7 @@ private: Input *input; int id_to_change; + int slider_count; int joypad_count; bool attached_joypads[JOYPADS_MAX]; dinput_gamepad d_joypads[JOYPADS_MAX]; @@ -139,7 +132,7 @@ private: void joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp); - Input::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const; + Input::JoyAxisValue axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const; XInputGetState_t xinput_get_state; XInputSetState_t xinput_set_state; }; diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp index d8d0b13068..c367c69826 100644 --- a/platform/windows/key_mapping_windows.cpp +++ b/platform/windows/key_mapping_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -38,7 +38,6 @@ struct _WinTranslatePair { }; static _WinTranslatePair _vk_to_keycode[] = { - { KEY_BACKSPACE, VK_BACK }, // (0x08) // backspace { KEY_TAB, VK_TAB }, //(0x09) @@ -48,7 +47,7 @@ static _WinTranslatePair _vk_to_keycode[] = { { KEY_SHIFT, VK_SHIFT }, //(0x10) - { KEY_CONTROL, VK_CONTROL }, //(0x11) + { KEY_CTRL, VK_CONTROL }, //(0x11) { KEY_ALT, VK_MENU }, //(0x12) @@ -167,8 +166,8 @@ static _WinTranslatePair _vk_to_keycode[] = { { KEY_SCROLLLOCK, VK_SCROLL }, // (0x91) { KEY_SHIFT, VK_LSHIFT }, // (0xA0) { KEY_SHIFT, VK_RSHIFT }, // (0xA1) - { KEY_CONTROL, VK_LCONTROL }, // (0xA2) - { KEY_CONTROL, VK_RCONTROL }, // (0xA3) + { KEY_CTRL, VK_LCONTROL }, // (0xA2) + { KEY_CTRL, VK_RCONTROL }, // (0xA3) { KEY_MENU, VK_LMENU }, // (0xA4) { KEY_MENU, VK_RMENU }, // (0xA5) @@ -238,7 +237,6 @@ VK_OEM_CLEAR (0xFE) */ static _WinTranslatePair _scancode_to_keycode[] = { - { KEY_ESCAPE, 0x01 }, { KEY_1, 0x02 }, { KEY_2, 0x03 }, @@ -267,7 +265,7 @@ static _WinTranslatePair _scancode_to_keycode[] = { { KEY_BRACELEFT, 0x1A }, { KEY_BRACERIGHT, 0x1B }, { KEY_ENTER, 0x1C }, - { KEY_CONTROL, 0x1D }, + { KEY_CTRL, 0x1D }, { KEY_A, 0x1E }, { KEY_S, 0x1F }, { KEY_D, 0x20 }, diff --git a/platform/windows/key_mapping_windows.h b/platform/windows/key_mapping_windows.h index f64f1feb9f..fb07227014 100644 --- a/platform/windows/key_mapping_windows.h +++ b/platform/windows/key_mapping_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/windows/lang_table.h b/platform/windows/lang_table.h index f81bab13a4..51583cc11e 100644 --- a/platform/windows/lang_table.h +++ b/platform/windows/lang_table.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 0dab0c601a..56d673afc3 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -39,15 +39,12 @@ #include "core/version_generated.gen.h" #include "drivers/windows/dir_access_windows.h" #include "drivers/windows/file_access_windows.h" -#include "drivers/windows/rw_lock_windows.h" -#include "drivers/windows/thread_windows.h" #include "joypad_windows.h" #include "lang_table.h" #include "main/main.h" #include "platform/windows/display_server_windows.h" #include "servers/audio_server.h" -#include "servers/rendering/rendering_server_raster.h" -#include "servers/rendering/rendering_server_wrap_mt.h" +#include "servers/rendering/rendering_server_default.h" #include "windows_terminal_logger.h" #include <avrt.h> @@ -84,7 +81,7 @@ static String format_error_message(DWORD id) { size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr); - String msg = "Error " + itos(id) + ": " + String(messageBuffer, size); + String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size); LocalFree(messageBuffer); @@ -107,15 +104,11 @@ void RedirectIOToConsole() { // set the screen buffer to be big enough to let us scroll text - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), - - &coninfo); + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); coninfo.dwSize.Y = MAX_CONSOLE_LINES; - SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), - - coninfo.dwSize); + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); // redirect unbuffered STDOUT to the console @@ -181,13 +174,9 @@ void OS_Windows::initialize() { //RedirectIOToConsole(); - ThreadWindows::make_default(); - RWLockWindows::make_default(); - FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM); - //FileAccessBufferedFA<FileAccessWindows>::make_default(); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); @@ -208,7 +197,14 @@ void OS_Windows::initialize() { process_map = memnew((Map<ProcessID, ProcessInfo>)); - IP_Unix::make_default(); + // Add current Godot PID to the list of known PIDs + ProcessInfo current_pi = {}; + PROCESS_INFORMATION current_pi_pi = {}; + current_pi.pi = current_pi_pi; + current_pi.pi.hProcess = GetCurrentProcess(); + process_map->insert(GetCurrentProcessId(), current_pi); + + IPUnix::make_default(); main_loop = nullptr; } @@ -241,7 +237,7 @@ void OS_Windows::finalize_core() { } Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { - String path = p_path; + String path = p_path.replace("/", "\\"); if (!FileAccess::exists(path)) { //this code exists so gdnative can load .dll files from within the executable path @@ -258,10 +254,10 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han DLL_DIRECTORY_COOKIE cookie = nullptr; if (p_also_set_library_path && has_dll_directory_api) { - cookie = add_dll_directory(path.get_base_dir().c_str()); + cookie = add_dll_directory((LPCWSTR)(path.get_base_dir().utf16().get_data())); } - p_library_handle = (void *)LoadLibraryExW(path.c_str(), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0); + p_library_handle = (void *)LoadLibraryExW((LPCWSTR)(path.utf16().get_data()), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0); ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + format_error_message(GetLastError()) + "."); if (cookie) { @@ -319,8 +315,8 @@ OS::Time OS_Windows::get_time(bool utc) const { Time time; time.hour = systemtime.wHour; - time.min = systemtime.wMinute; - time.sec = systemtime.wSecond; + time.minute = systemtime.wMinute; + time.second = systemtime.wSecond; return time; } @@ -338,60 +334,26 @@ OS::TimeZoneInfo OS_Windows::get_time_zone_info() const { } // Bias value returned by GetTimeZoneInformation is inverted of what we expect - // For example on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180 + // For example, on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180 ret.bias = -info.Bias; return ret; } -uint64_t OS_Windows::get_unix_time() const { - FILETIME ft; - SYSTEMTIME st; - GetSystemTime(&st); - SystemTimeToFileTime(&st, &ft); - - SYSTEMTIME ep; - ep.wYear = 1970; - ep.wMonth = 1; - ep.wDayOfWeek = 4; - ep.wDay = 1; - ep.wHour = 0; - ep.wMinute = 0; - ep.wSecond = 0; - ep.wMilliseconds = 0; - FILETIME fep; - SystemTimeToFileTime(&ep, &fep); - - // Type punning through unions (rather than pointer cast) as per: - // https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime#remarks - ULARGE_INTEGER ft_punning; - ft_punning.LowPart = ft.dwLowDateTime; - ft_punning.HighPart = ft.dwHighDateTime; - - ULARGE_INTEGER fep_punning; - fep_punning.LowPart = fep.dwLowDateTime; - fep_punning.HighPart = fep.dwHighDateTime; - - return (ft_punning.QuadPart - fep_punning.QuadPart) / 10000000; -}; - -uint64_t OS_Windows::get_system_time_secs() const { - return get_system_time_msecs() / 1000; -} - -uint64_t OS_Windows::get_system_time_msecs() const { - const uint64_t WINDOWS_TICK = 10000; - const uint64_t MSEC_TO_UNIX_EPOCH = 11644473600000LL; +double OS_Windows::get_unix_time() const { + // 1 Windows tick is 100ns + const uint64_t WINDOWS_TICKS_PER_SECOND = 10000000; + const uint64_t TICKS_TO_UNIX_EPOCH = 116444736000000000LL; SYSTEMTIME st; GetSystemTime(&st); FILETIME ft; SystemTimeToFileTime(&st, &ft); - uint64_t ret; - ret = ft.dwHighDateTime; - ret <<= 32; - ret |= ft.dwLowDateTime; + uint64_t ticks_time; + ticks_time = ft.dwHighDateTime; + ticks_time <<= 32; + ticks_time |= ft.dwLowDateTime; - return (uint64_t)(ret / WINDOWS_TICK - MSEC_TO_UNIX_EPOCH); + return (double)(ticks_time - TICKS_TO_UNIX_EPOCH) / WINDOWS_TICKS_PER_SECOND; } void OS_Windows::delay_usec(uint32_t p_usec) const { @@ -403,12 +365,29 @@ void OS_Windows::delay_usec(uint32_t p_usec) const { uint64_t OS_Windows::get_ticks_usec() const { uint64_t ticks; - uint64_t time; + // This is the number of clock ticks since start if (!QueryPerformanceCounter((LARGE_INTEGER *)&ticks)) ticks = (UINT64)timeGetTime(); + // Divide by frequency to get the time in seconds - time = ticks * 1000000L / ticks_per_second; + // original calculation shown below is subject to overflow + // with high ticks_per_second and a number of days since the last reboot. + // time = ticks * 1000000L / ticks_per_second; + + // we can prevent this by either using 128 bit math + // or separating into a calculation for seconds, and the fraction + uint64_t seconds = ticks / ticks_per_second; + + // compiler will optimize these two into one divide + uint64_t leftover = ticks % ticks_per_second; + + // remainder + uint64_t time = (leftover * 1000000L) / ticks_per_second; + + // seconds + time += seconds * 1000000L; + // Subtract the time at game start to get // the time since the game started time -= ticks_start; @@ -417,7 +396,7 @@ uint64_t OS_Windows::get_ticks_usec() const { String OS_Windows::_quote_command_line_argument(const String &p_text) const { for (int i = 0; i < p_text.size(); i++) { - CharType c = p_text[i]; + char32_t c = p_text[i]; if (c == ' ' || c == '&' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '=' || c == ';' || c == '!' || c == '\'' || c == '+' || c == ',' || c == '`' || c == '~') { return "\"" + p_text + "\""; } @@ -425,22 +404,23 @@ String OS_Windows::_quote_command_line_argument(const String &p_text) const { return p_text; } -Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) { - if (p_blocking && r_pipe) { - String argss = _quote_command_line_argument(p_path); - for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) { - argss += " " + _quote_command_line_argument(E->get()); - } +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) { + String path = p_path.replace("/", "\\"); + String command = _quote_command_line_argument(path); + for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) { + command += " " + _quote_command_line_argument(E->get()); + } + if (r_pipe) { if (read_stderr) { - argss += " 2>&1"; // Read stderr too + command += " 2>&1"; // Include stderr } - // Note: _wpopen is calling command as "cmd.exe /c argss", instead of executing it directly, add extra quotes around full command, to prevent it from stripping quotes in the command. - argss = _quote_command_line_argument(argss); - - FILE *f = _wpopen(argss.c_str(), L"r"); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + // 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) { @@ -451,52 +431,57 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, p_pipe_mutex->unlock(); } } - int rv = _pclose(f); + if (r_exitcode) { *r_exitcode = rv; } - return OK; } - String cmdline = _quote_command_line_argument(p_path); - const List<String>::Element *I = p_arguments.front(); - while (I) { - cmdline += " " + _quote_command_line_argument(I->get()); - I = I->next(); - } - 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; - Vector<CharType> modstr; // Windows wants to change this no idea why. - modstr.resize(cmdline.size()); - for (int i = 0; i < cmdline.size(); i++) { - modstr.write[i] = cmdline[i]; + int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi); + ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command); + + WaitForSingleObject(pi.pi.hProcess, INFINITE); + if (r_exitcode) { + DWORD ret2; + GetExitCodeProcess(pi.pi.hProcess, &ret2); + *r_exitcode = ret2; } + CloseHandle(pi.pi.hProcess); + CloseHandle(pi.pi.hThread); - int ret = CreateProcessW(nullptr, modstr.ptrw(), nullptr, nullptr, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi); - ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK); + return OK; +}; - if (p_blocking) { - DWORD ret2 = WaitForSingleObject(pi.pi.hProcess, INFINITE); - if (r_exitcode) { - *r_exitcode = ret2; - } +Error OS_Windows::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { + String path = p_path.replace("/", "\\"); + String command = _quote_command_line_argument(path); + for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) { + command += " " + _quote_command_line_argument(E->get()); + } - CloseHandle(pi.pi.hProcess); - CloseHandle(pi.pi.hThread); - } else { - ProcessID pid = pi.pi.dwProcessId; - if (r_child_id) { - *r_child_id = pid; - } - process_map->insert(pid, pi); + 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; + + int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, 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; + if (r_child_id) { + *r_child_id = pid; } + process_map->insert(pid, pi); + return OK; }; @@ -519,26 +504,26 @@ int OS_Windows::get_process_id() const { } Error OS_Windows::set_cwd(const String &p_cwd) { - if (_wchdir(p_cwd.c_str()) != 0) + if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0) return ERR_CANT_OPEN; return OK; } String OS_Windows::get_executable_path() const { - wchar_t bufname[4096]; + WCHAR bufname[4096]; GetModuleFileNameW(nullptr, bufname, 4096); - String s = bufname; + String s = String::utf16((const char16_t *)bufname).replace("\\", "/"); return s; } bool OS_Windows::has_environment(const String &p_var) const { #ifdef MINGW_ENABLED - return _wgetenv(p_var.c_str()) != nullptr; + return _wgetenv((LPCWSTR)(p_var.utf16().get_data())) != nullptr; #else - wchar_t *env; + WCHAR *env; size_t len; - _wdupenv_s(&env, &len, p_var.c_str()); + _wdupenv_s(&env, &len, (LPCWSTR)(p_var.utf16().get_data())); const bool has_env = env != nullptr; free(env); return has_env; @@ -546,16 +531,16 @@ bool OS_Windows::has_environment(const String &p_var) const { }; String OS_Windows::get_environment(const String &p_var) const { - wchar_t wval[0x7Fff]; // MSDN says 32767 char is the maximum - int wlen = GetEnvironmentVariableW(p_var.c_str(), wval, 0x7Fff); + WCHAR wval[0x7fff]; // MSDN says 32767 char is the maximum + int wlen = GetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), wval, 0x7fff); if (wlen > 0) { - return wval; + return String::utf16((const char16_t *)wval); } return ""; } bool OS_Windows::set_environment(const String &p_var, const String &p_value) const { - return (bool)SetEnvironmentVariableW(p_var.c_str(), p_value.c_str()); + return (bool)SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), (LPCWSTR)(p_value.utf16().get_data())); } String OS_Windows::get_stdin_string(bool p_block) { @@ -568,7 +553,7 @@ String OS_Windows::get_stdin_string(bool p_block) { } Error OS_Windows::shell_open(String p_uri) { - ShellExecuteW(nullptr, nullptr, p_uri.c_str(), nullptr, nullptr, SW_SHOWNORMAL); + ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL); return OK; } @@ -577,21 +562,21 @@ String OS_Windows::get_locale() const { LANGID langid = GetUserDefaultUILanguage(); String neutral; - int lang = langid & ((1 << 9) - 1); - int sublang = langid & ~((1 << 9) - 1); + int lang = PRIMARYLANGID(langid); + int sublang = SUBLANGID(langid); while (wl->locale) { if (wl->main_lang == lang && wl->sublang == SUBLANG_NEUTRAL) neutral = wl->locale; if (lang == wl->main_lang && sublang == wl->sublang) - return wl->locale; + return String(wl->locale).replace("-", "_"); wl++; } if (neutral != "") - return neutral; + return String(neutral).replace("-", "_"); return "en"; } @@ -630,7 +615,7 @@ void OS_Windows::run() { if (!main_loop) return; - main_loop->init(); + main_loop->initialize(); while (!force_quit) { DisplayServer::get_singleton()->process_events(); // get rid of pending events @@ -638,7 +623,7 @@ void OS_Windows::run() { break; }; - main_loop->finish(); + main_loop->finalize(); } MainLoop *OS_Windows::get_main_loop() const { @@ -646,31 +631,45 @@ MainLoop *OS_Windows::get_main_loop() const { } String OS_Windows::get_config_path() const { - if (has_environment("XDG_CONFIG_HOME")) { // unlikely, but after all why not? - return get_environment("XDG_CONFIG_HOME"); - } else if (has_environment("APPDATA")) { - return get_environment("APPDATA"); - } else { - return "."; + // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well. + if (has_environment("XDG_CONFIG_HOME")) { + if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { + return get_environment("XDG_CONFIG_HOME").replace("\\", "/"); + } else { + WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `%APPDATA%` or `.` per the XDG Base Directory specification."); + } + } + if (has_environment("APPDATA")) { + return get_environment("APPDATA").replace("\\", "/"); } + return "."; } String OS_Windows::get_data_path() const { + // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well. if (has_environment("XDG_DATA_HOME")) { - return get_environment("XDG_DATA_HOME"); - } else { - return get_config_path(); + if (get_environment("XDG_DATA_HOME").is_absolute_path()) { + return get_environment("XDG_DATA_HOME").replace("\\", "/"); + } else { + WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `get_config_path()` per the XDG Base Directory specification."); + } } + return get_config_path(); } String OS_Windows::get_cache_path() const { + // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well. if (has_environment("XDG_CACHE_HOME")) { - return get_environment("XDG_CACHE_HOME"); - } else if (has_environment("TEMP")) { - return get_environment("TEMP"); - } else { - return get_config_path(); + if (get_environment("XDG_CACHE_HOME").is_absolute_path()) { + return get_environment("XDG_CACHE_HOME").replace("\\", "/"); + } else { + WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `%TEMP%` or `get_config_path()` per the XDG Base Directory specification."); + } + } + if (has_environment("TEMP")) { + return get_environment("TEMP").replace("\\", "/"); } + return get_config_path(); } // Get properly capitalized engine name for system paths @@ -711,7 +710,7 @@ String OS_Windows::get_system_dir(SystemDir p_dir) const { PWSTR szPath; HRESULT res = SHGetKnownFolderPath(id, 0, nullptr, &szPath); ERR_FAIL_COND_V(res != S_OK, String()); - String path = String(szPath); + String path = String::utf16((const char16_t *)szPath).replace("\\", "/"); CoTaskMemFree(szPath); return path; } @@ -737,7 +736,7 @@ String OS_Windows::get_user_data_dir() const { String OS_Windows::get_unique_id() const { HW_PROFILE_INFO HwProfInfo; ERR_FAIL_COND_V(!GetCurrentHwProfile(&HwProfInfo), ""); - return String(HwProfInfo.szHwProfileGuid); + return String::utf16((const char16_t *)(HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN); } bool OS_Windows::_check_internal_feature_support(const String &p_feature) { @@ -754,9 +753,11 @@ bool OS_Windows::is_disable_crash_handler() const { Error OS_Windows::move_to_trash(const String &p_path) { SHFILEOPSTRUCTW sf; - WCHAR *from = new WCHAR[p_path.length() + 2]; - wcscpy_s(from, p_path.length() + 1, p_path.c_str()); - from[p_path.length() + 1] = 0; + + Char16String utf16 = p_path.utf16(); + WCHAR *from = new WCHAR[utf16.length() + 2]; + wcscpy_s(from, utf16.length() + 1, (LPCWSTR)(utf16.get_data())); + from[utf16.length() + 1] = 0; sf.hwnd = main_window; sf.wFunc = FO_DELETE; @@ -778,71 +779,11 @@ Error OS_Windows::move_to_trash(const String &p_path) { return OK; } -int OS_Windows::get_tablet_driver_count() const { - return tablet_drivers.size(); -} - -String OS_Windows::get_tablet_driver_name(int p_driver) const { - if (p_driver < 0 || p_driver >= tablet_drivers.size()) { - return ""; - } else { - return tablet_drivers[p_driver]; - } -} - -String OS_Windows::get_current_tablet_driver() const { - return tablet_driver; -} - -void OS_Windows::set_current_tablet_driver(const String &p_driver) { - if (get_tablet_driver_count() == 0) { - return; - } - bool found = false; - for (int i = 0; i < get_tablet_driver_count(); i++) { - if (p_driver == get_tablet_driver_name(i)) { - found = true; - } - } - if (found) { - if (DisplayServerWindows::get_singleton()) { - ((DisplayServerWindows *)DisplayServerWindows::get_singleton())->_update_tablet_ctx(tablet_driver, p_driver); - } - tablet_driver = p_driver; - } else { - ERR_PRINT("Unknown tablet driver " + p_driver + "."); - } -} - OS_Windows::OS_Windows(HINSTANCE _hInstance) { - //Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink. - HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll"); - if (wintab_lib) { - DisplayServerWindows::wintab_WTOpen = (WTOpenPtr)GetProcAddress(wintab_lib, "WTOpenW"); - DisplayServerWindows::wintab_WTClose = (WTClosePtr)GetProcAddress(wintab_lib, "WTClose"); - DisplayServerWindows::wintab_WTInfo = (WTInfoPtr)GetProcAddress(wintab_lib, "WTInfoW"); - DisplayServerWindows::wintab_WTPacket = (WTPacketPtr)GetProcAddress(wintab_lib, "WTPacket"); - DisplayServerWindows::wintab_WTEnable = (WTEnablePtr)GetProcAddress(wintab_lib, "WTEnable"); - - DisplayServerWindows::wintab_available = DisplayServerWindows::wintab_WTOpen && DisplayServerWindows::wintab_WTClose && DisplayServerWindows::wintab_WTInfo && DisplayServerWindows::wintab_WTPacket && DisplayServerWindows::wintab_WTEnable; - } - - if (DisplayServerWindows::wintab_available) { - tablet_drivers.push_back("wintab"); - } - - //Note: Windows Ink API for pen input, available on Windows 8+ only. - HMODULE user32_lib = LoadLibraryW(L"user32.dll"); - if (user32_lib) { - DisplayServerWindows::win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType"); - DisplayServerWindows::win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo"); - - DisplayServerWindows::winink_available = DisplayServerWindows::win8p_GetPointerType && DisplayServerWindows::win8p_GetPointerPenInfo; - } - - if (DisplayServerWindows::winink_available) { - tablet_drivers.push_back("winink"); - } + ticks_per_second = 0; + ticks_start = 0; + main_loop = nullptr; + process_map = nullptr; force_quit = false; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 11e3533bfd..8f9ef254f1 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,16 +31,16 @@ #ifndef OS_WINDOWS_H #define OS_WINDOWS_H +#include "core/config/project_settings.h" #include "core/input/input.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "crash_handler_windows.h" #include "drivers/unix/ip_unix.h" #include "drivers/wasapi/audio_driver_wasapi.h" #include "drivers/winmidi/midi_driver_winmidi.h" #include "key_mapping_windows.h" #include "servers/audio_server.h" -#include "servers/rendering/rasterizer.h" +#include "servers/rendering/renderer_compositor.h" #include "servers/rendering_server.h" #ifdef XAUDIO2_ENABLED #include "drivers/xaudio2/audio_driver_xaudio2.h" @@ -73,9 +73,6 @@ class OS_Windows : public OS { HINSTANCE hInstance; MainLoop *main_loop; - String tablet_driver; - Vector<String> tablet_drivers; - #ifdef WASAPI_ENABLED AudioDriverWASAPI driver_wasapi; #endif @@ -93,14 +90,14 @@ class OS_Windows : public OS { // functions used by main to initialize/deinitialize the OS protected: - virtual void initialize(); + virtual void initialize() override; - virtual void set_main_loop(MainLoop *p_main_loop); - virtual void delete_main_loop(); + virtual void set_main_loop(MainLoop *p_main_loop) override; + virtual void delete_main_loop() override; - virtual void finalize(); - virtual void finalize_core(); - virtual String get_stdin_string(bool p_block); + virtual void finalize() override; + virtual void finalize_core() override; + virtual String get_stdin_string(bool p_block) override; String _quote_command_line_argument(const String &p_text) const; @@ -111,68 +108,62 @@ protected: Map<ProcessID, ProcessInfo> *process_map; public: - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); - virtual Error close_dynamic_library(void *p_library_handle); - virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); - - virtual MainLoop *get_main_loop() const; + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override; + virtual Error close_dynamic_library(void *p_library_handle) override; + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; - virtual String get_name() const; + virtual MainLoop *get_main_loop() const override; - virtual int get_tablet_driver_count() const; - virtual String get_tablet_driver_name(int p_driver) const; - virtual String get_current_tablet_driver() const; - virtual void set_current_tablet_driver(const String &p_driver); + virtual String get_name() const override; - virtual void initialize_joypads() {} + virtual void initialize_joypads() override {} - virtual Date get_date(bool utc) const; - virtual Time get_time(bool utc) const; - virtual TimeZoneInfo get_time_zone_info() const; - virtual uint64_t get_unix_time() const; - virtual uint64_t get_system_time_secs() const; - virtual uint64_t get_system_time_msecs() const; + virtual Date get_date(bool utc) const override; + virtual Time get_time(bool utc) const override; + virtual TimeZoneInfo get_time_zone_info() const override; + virtual double get_unix_time() const override; - virtual Error set_cwd(const String &p_cwd); + virtual Error set_cwd(const String &p_cwd) override; - virtual void delay_usec(uint32_t p_usec) const; - virtual uint64_t get_ticks_usec() const; + 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, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr); - virtual Error kill(const ProcessID &p_pid); - virtual int get_process_id() 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) override; + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error kill(const ProcessID &p_pid) override; + virtual int get_process_id() const override; - virtual bool has_environment(const String &p_var) const; - virtual String get_environment(const String &p_var) const; - virtual bool set_environment(const String &p_var, const String &p_value) const; + virtual bool has_environment(const String &p_var) const override; + virtual String get_environment(const String &p_var) const override; + virtual bool set_environment(const String &p_var, const String &p_value) const override; - virtual String get_executable_path() const; + virtual String get_executable_path() const override; - virtual String get_locale() const; + virtual String get_locale() const override; - virtual int get_processor_count() const; + virtual int get_processor_count() const override; - virtual String get_config_path() const; - virtual String get_data_path() const; - virtual String get_cache_path() const; - virtual String get_godot_dir_name() const; + virtual String get_config_path() const override; + virtual String get_data_path() const override; + virtual String get_cache_path() const override; + virtual String get_godot_dir_name() const override; - virtual String get_system_dir(SystemDir p_dir) const; - virtual String get_user_data_dir() const; + virtual String get_system_dir(SystemDir p_dir) const override; + virtual String get_user_data_dir() const override; - virtual String get_unique_id() const; + virtual String get_unique_id() const override; - virtual Error shell_open(String p_uri); + virtual Error shell_open(String p_uri) override; void run(); - virtual bool _check_internal_feature_support(const String &p_feature); + virtual bool _check_internal_feature_support(const String &p_feature) override; - void disable_crash_handler(); - bool is_disable_crash_handler() const; - virtual void initialize_debugging(); + virtual void disable_crash_handler() override; + virtual bool is_disable_crash_handler() const override; + virtual void initialize_debugging() override; - virtual Error move_to_trash(const String &p_path); + virtual Error move_to_trash(const String &p_path) override; void set_main_window(HWND p_main_window) { main_window = p_main_window; } diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h index 290decac5f..481f583f6f 100644 --- a/platform/windows/platform_config.h +++ b/platform/windows/platform_config.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,5 +29,3 @@ /*************************************************************************/ #include <malloc.h> - -#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h" diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp index 2c63281c49..e5e176ab93 100644 --- a/platform/windows/vulkan_context_win.cpp +++ b/platform/windows/vulkan_context_win.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h index 6e80db0286..4fe987218d 100644 --- a/platform/windows/vulkan_context_win.h +++ b/platform/windows/vulkan_context_win.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp index 26637d0827..8cab7ca521 100644 --- a/platform/windows/windows_terminal_logger.cpp +++ b/platform/windows/windows_terminal_logger.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -53,7 +53,8 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er if (wlen < 0) return; - wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); + wchar_t *wbuf = (wchar_t *)memalloc((len + 1) * sizeof(wchar_t)); + ERR_FAIL_NULL_MSG(wbuf, "Out of memory."); MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen); wbuf[wlen] = 0; @@ -62,7 +63,7 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er else wprintf(L"%ls", wbuf); - free(wbuf); + memfree(wbuf); #ifdef DEBUG_ENABLED fflush(stdout); diff --git a/platform/windows/windows_terminal_logger.h b/platform/windows/windows_terminal_logger.h index d4443a707d..aacfe5869e 100644 --- a/platform/windows/windows_terminal_logger.h +++ b/platform/windows/windows_terminal_logger.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ |