diff options
Diffstat (limited to 'platform/windows')
-rw-r--r-- | platform/windows/SCsub | 25 | ||||
-rw-r--r-- | platform/windows/console_wrapper_windows.cpp | 181 | ||||
-rw-r--r-- | platform/windows/detect.py | 86 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 144 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 14 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.cpp | 63 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.h | 3 | ||||
-rw-r--r-- | platform/windows/gl_manager_windows.cpp | 69 | ||||
-rw-r--r-- | platform/windows/gl_manager_windows.h | 13 | ||||
-rw-r--r-- | platform/windows/godot_res_wrap.rc | 33 | ||||
-rw-r--r-- | platform/windows/godot_windows.cpp | 4 | ||||
-rw-r--r-- | platform/windows/joypad_windows.cpp | 2 | ||||
-rw-r--r-- | platform/windows/joypad_windows.h | 2 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 163 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 21 | ||||
-rw-r--r-- | platform/windows/platform_config.h | 2 | ||||
-rw-r--r-- | platform/windows/vulkan_context_win.cpp | 4 | ||||
-rw-r--r-- | platform/windows/vulkan_context_win.h | 6 |
18 files changed, 583 insertions, 252 deletions
diff --git a/platform/windows/SCsub b/platform/windows/SCsub index 7e412b140f..efbb47d965 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -19,19 +19,44 @@ common_win = [ "gl_manager_windows.cpp", ] +common_win_wrap = [ + "console_wrapper_windows.cpp", +] + res_file = "godot_res.rc" res_target = "godot_res" + env["OBJSUFFIX"] res_obj = env.RES(res_target, res_file) prog = env.add_program("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGSUFFIX"]) +# Build console wrapper app. +if env["windows_subsystem"] == "gui": + env_wrap = env.Clone() + res_wrap_file = "godot_res_wrap.rc" + res_wrap_target = "godot_res_wrap" + env["OBJSUFFIX"] + res_wrap_obj = env_wrap.RES(res_wrap_target, res_wrap_file) + + if env.msvc: + env_wrap.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) + env_wrap.Append(LINKFLAGS=["version.lib"]) + else: + env_wrap.Append(LINKFLAGS=["-Wl,--subsystem,console"]) + env_wrap.Append(LIBS=["version"]) + + prog_wrap = env_wrap.add_program("#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"]) + # Microsoft Visual Studio Project Generation if env["vsproj"]: env.vs_srcs += ["platform/windows/" + res_file] env.vs_srcs += ["platform/windows/godot.natvis"] for x in common_win: env.vs_srcs += ["platform/windows/" + str(x)] + if env["windows_subsystem"] == "gui": + for x in common_win_wrap: + env.vs_srcs += ["platform/windows/" + str(x)] if not os.getenv("VCINSTALLDIR"): if env["debug_symbols"] and env["separate_debug_symbols"]: env.AddPostAction(prog, run_in_subprocess(platform_windows_builders.make_debug_mingw)) + if env["windows_subsystem"] == "gui": + env.AddPostAction(prog_wrap, run_in_subprocess(platform_windows_builders.make_debug_mingw)) diff --git a/platform/windows/console_wrapper_windows.cpp b/platform/windows/console_wrapper_windows.cpp new file mode 100644 index 0000000000..258176426b --- /dev/null +++ b/platform/windows/console_wrapper_windows.cpp @@ -0,0 +1,181 @@ +/*************************************************************************/ +/* console_wrapper_windows.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include <windows.h> + +#include <shlwapi.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4 +#endif + +int main(int argc, char *argv[]) { + // Get executable name. + WCHAR exe_name[MAX_PATH] = {}; + if (!GetModuleFileNameW(nullptr, exe_name, MAX_PATH)) { + wprintf(L"GetModuleFileName failed, error %d\n", GetLastError()); + return -1; + } + + // Get product name from the resources and set console title. + DWORD ver_info_handle = 0; + DWORD ver_info_size = GetFileVersionInfoSizeW(exe_name, &ver_info_handle); + if (ver_info_size > 0) { + LPBYTE ver_info = (LPBYTE)malloc(ver_info_size); + if (ver_info) { + if (GetFileVersionInfoW(exe_name, ver_info_handle, ver_info_size, ver_info)) { + LPCWSTR text_ptr = nullptr; + UINT text_size = 0; + if (VerQueryValueW(ver_info, L"\\StringFileInfo\\040904b0\\ProductName", (void **)&text_ptr, &text_size) && (text_size > 0)) { + SetConsoleTitleW(text_ptr); + } + } + free(ver_info); + } + } + + // Enable virtual terminal sequences processing. + HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD out_mode = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(stdout_handle, out_mode); + + // Find main executable name and check if it exist. + static PCWSTR exe_renames[] = { + L".console.exe", + L"_console.exe", + L" console.exe", + L"console.exe", + nullptr, + }; + + bool rename_found = false; + for (int i = 0; exe_renames[i]; i++) { + PWSTR c = StrRStrIW(exe_name, nullptr, exe_renames[i]); + if (c) { + CopyMemory(c, L".exe", sizeof(WCHAR) * 5); + rename_found = true; + break; + } + } + if (!rename_found) { + wprintf(L"Invalid wrapper executable name.\n"); + return -1; + } + + DWORD file_attrib = GetFileAttributesW(exe_name); + if (file_attrib == INVALID_FILE_ATTRIBUTES || (file_attrib & FILE_ATTRIBUTE_DIRECTORY)) { + wprintf(L"Main executable %ls not found.\n", exe_name); + return -1; + } + + // Create job to monitor process tree. + HANDLE job_handle = CreateJobObjectW(nullptr, nullptr); + if (!job_handle) { + wprintf(L"CreateJobObject failed, error %d\n", GetLastError()); + return -1; + } + + HANDLE io_port_handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1); + if (!io_port_handle) { + wprintf(L"CreateIoCompletionPort failed, error %d\n", GetLastError()); + return -1; + } + + JOBOBJECT_ASSOCIATE_COMPLETION_PORT compl_port; + ZeroMemory(&compl_port, sizeof(compl_port)); + compl_port.CompletionKey = job_handle; + compl_port.CompletionPort = io_port_handle; + + if (!SetInformationJobObject(job_handle, JobObjectAssociateCompletionPortInformation, &compl_port, sizeof(compl_port))) { + wprintf(L"SetInformationJobObject(AssociateCompletionPortInformation) failed, error %d\n", GetLastError()); + return -1; + } + + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; + ZeroMemory(&jeli, sizeof(jeli)); + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + + if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) { + wprintf(L"SetInformationJobObject(ExtendedLimitInformation) failed, error %d\n", GetLastError()); + return -1; + } + + // Start the main process. + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(pi)); + + STARTUPINFOW si; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + WCHAR new_command_line[32767]; + _snwprintf_s(new_command_line, 32767, _TRUNCATE, L"%ls %ls", exe_name, PathGetArgsW(GetCommandLineW())); + + if (!CreateProcessW(nullptr, new_command_line, nullptr, nullptr, true, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi)) { + wprintf(L"CreateProcess failed, error %d\n", GetLastError()); + return -1; + } + + if (!AssignProcessToJobObject(job_handle, pi.hProcess)) { + wprintf(L"AssignProcessToJobObject failed, error %d\n", GetLastError()); + return -1; + } + + ResumeThread(pi.hThread); + CloseHandle(pi.hThread); + + // Wait until main process and all of its children are finished. + DWORD completion_code = 0; + ULONG_PTR completion_key = 0; + LPOVERLAPPED overlapped = nullptr; + + while (GetQueuedCompletionStatus(io_port_handle, &completion_code, &completion_key, &overlapped, INFINITE)) { + if ((HANDLE)completion_key == job_handle && completion_code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) { + break; + } + } + + CloseHandle(job_handle); + CloseHandle(io_port_handle); + + // Get exit code of the main process. + DWORD exit_code = 0; + GetExitCodeProcess(pi.hProcess, &exit_code); + + CloseHandle(pi.hProcess); + + return exit_code; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + return main(0, nullptr); +} diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 095d688213..705e83dace 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -4,6 +4,11 @@ import subprocess import sys from platform_methods import detect_arch +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from SCons import Environment + # To match other platforms STACK_SIZE = 8388608 @@ -173,17 +178,7 @@ def get_opts(): "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601", ), - BoolVariable( - "debug_symbols", - "Add debugging symbols to release/release_debug builds", - True, - ), EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("gui", "console")), - BoolVariable( - "separate_debug_symbols", - "Create a separate file containing debugging symbols", - False, - ), ( "msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", @@ -330,31 +325,11 @@ def setup_mingw(env): def configure_msvc(env, vcvars_msvc_config): """Configure env to work with MSVC""" - # Build type - if env["target"] == "release": - if env["optimize"] == "speed": # optimize for speed (default) - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - elif env["optimize"] == "size": # optimize for size - env.Append(CCFLAGS=["/O1"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"]) - - elif env["target"] == "release_debug": - if env["optimize"] == "speed": # optimize for speed (default) - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - elif env["optimize"] == "size": # optimize for size - env.Append(CCFLAGS=["/O1"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - - elif env["target"] == "debug": - env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"]) - env.Append(LINKFLAGS=["/DEBUG"]) + ## Build type - if env["debug_symbols"]: - env.AppendUnique(CCFLAGS=["/Zi", "/FS"]) - env.AppendUnique(LINKFLAGS=["/DEBUG"]) + # TODO: Re-evaluate the need for this / streamline with common config. + if env["target"] == "template_release": + env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"]) if env["windows_subsystem"] == "gui": env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"]) @@ -426,6 +401,7 @@ def configure_msvc(env, vcvars_msvc_config): "Avrt", "dwmapi", "dwrite", + "wbemuuid", ] if env["vulkan"]: @@ -491,31 +467,10 @@ def configure_mingw(env): if env["use_llvm"] and not try_cmd("clang --version", env["mingw_prefix"], env["arch"]): env["use_llvm"] = False - if env["target"] == "release": + # TODO: Re-evaluate the need for this / streamline with common config. + if env["target"] == "template_release": env.Append(CCFLAGS=["-msse2"]) - - if env["optimize"] == "speed": # optimize for speed (default) - if env["arch"] == "x86_32": - env.Append(CCFLAGS=["-O2"]) - else: - env.Append(CCFLAGS=["-O3"]) - else: # optimize for size - env.Prepend(CCFLAGS=["-Os"]) - - if env["debug_symbols"]: - env.Prepend(CCFLAGS=["-g2"]) - - elif env["target"] == "release_debug": - env.Append(CCFLAGS=["-O2"]) - if env["debug_symbols"]: - env.Prepend(CCFLAGS=["-g2"]) - if env["optimize"] == "speed": # optimize for speed (default) - env.Append(CCFLAGS=["-O2"]) - else: # optimize for size - env.Prepend(CCFLAGS=["-Os"]) - - elif env["target"] == "debug": - env.Append(CCFLAGS=["-g3"]) + elif env.dev_build: # Allow big objects. It's supposed not to have drawbacks but seems to break # GCC LTO, so enabling for debug builds only (which are not built with LTO # and are the only ones with too big objects). @@ -623,15 +578,18 @@ def configure_mingw(env): "uuid", "dwmapi", "dwrite", + "wbemuuid", ] ) - env.Append(CPPDEFINES=["VULKAN_ENABLED"]) - if not env["use_volk"]: - env.Append(LIBS=["vulkan"]) + if env["vulkan"]: + env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + if not env["use_volk"]: + env.Append(LIBS=["vulkan"]) - env.Append(CPPDEFINES=["GLES3_ENABLED"]) - env.Append(LIBS=["opengl32"]) + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES3_ENABLED"]) + env.Append(LIBS=["opengl32"]) env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)]) @@ -639,7 +597,7 @@ def configure_mingw(env): env.Append(BUILDERS={"RES": env.Builder(action=build_res_file, suffix=".o", src_suffix=".rc")}) -def configure(env): +def configure(env: "Environment"): # Validate arch. supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] if env["arch"] not in supported_arches: diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 77b20dd924..0b878feb7f 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -561,20 +561,6 @@ float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const { return data.rate; } -bool DisplayServerWindows::screen_is_touchscreen(int p_screen) const { -#ifndef _MSC_VER -#warning touchscreen not working -#endif - return false; -} - -void DisplayServerWindows::screen_set_orientation(ScreenOrientation p_orientation, int p_screen) { -} - -DisplayServer::ScreenOrientation DisplayServerWindows::screen_get_orientation(int p_screen) const { - return SCREEN_LANDSCAPE; -} - void DisplayServerWindows::screen_set_keep_on(bool p_enable) { if (keep_screen_on == p_enable) { return; @@ -755,9 +741,20 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type, case WINDOW_HANDLE: { return (int64_t)windows[p_window].hWnd; } +#if defined(GLES3_ENABLED) case WINDOW_VIEW: { - return 0; // Not supported. + if (gl_manager) { + return (int64_t)gl_manager->get_hdc(p_window); + } + return 0; } + case OPENGL_CONTEXT: { + if (gl_manager) { + return (int64_t)gl_manager->get_hglrc(p_window); + } + return 0; + } +#endif default: { return 0; } @@ -1361,7 +1358,8 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W if (p_enabled) { //enable per-pixel alpha - DWM_BLURBEHIND bb = { 0 }; + DWM_BLURBEHIND bb; + ZeroMemory(&bb, sizeof(bb)); HRGN hRgn = CreateRectRgn(0, 0, -1, -1); bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; bb.hRgnBlur = hRgn; @@ -1373,7 +1371,8 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W //disable per-pixel alpha wd.layered_window = false; - DWM_BLURBEHIND bb = { 0 }; + DWM_BLURBEHIND bb; + ZeroMemory(&bb, sizeof(bb)); HRGN hRgn = CreateRectRgn(0, 0, -1, -1); bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; bb.hRgnBlur = hRgn; @@ -1390,7 +1389,7 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened."); wd.is_popup = p_enabled; } break; - case WINDOW_FLAG_MAX: + default: break; } } @@ -1419,7 +1418,7 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window case WINDOW_FLAG_POPUP: { return wd.is_popup; } break; - case WINDOW_FLAG_MAX: + default: break; } @@ -1893,7 +1892,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) { pos += sizeof(WORD); f->seek(pos); - icon_dir = (ICONDIR *)memrealloc(icon_dir, 3 * sizeof(WORD) + icon_dir->idCount * sizeof(ICONDIRENTRY)); + icon_dir = (ICONDIR *)memrealloc(icon_dir, sizeof(ICONDIR) - sizeof(ICONDIRENTRY) + icon_dir->idCount * sizeof(ICONDIRENTRY)); f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY)); int small_icon_index = -1; // Select 16x16 with largest color count. @@ -2024,6 +2023,12 @@ void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn context_vulkan->set_vsync_mode(p_window, p_vsync_mode); } #endif + +#if defined(GLES3_ENABLED) + if (gl_manager) { + gl_manager->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED); + } +#endif } DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const { @@ -2033,6 +2038,13 @@ DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_ return context_vulkan->get_vsync_mode(p_window); } #endif + +#if defined(GLES3_ENABLED) + if (gl_manager) { + return gl_manager->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; + } +#endif + return DisplayServer::VSYNC_ENABLED; } @@ -2456,10 +2468,16 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA return 0; // Jump back. } case WM_MOUSELEAVE: { - old_invalid = true; - windows[window_id].mouse_outside = true; + if (window_mouseover_id == window_id) { + old_invalid = true; + window_mouseover_id = INVALID_WINDOW_ID; - _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT); + _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT); + } else if (window_mouseover_id != INVALID_WINDOW_ID) { + // This is reached during drag and drop, after dropping in a different window. + // Once-off notification, must call again. + track_mouse_leave_event(windows[window_mouseover_id].hWnd); + } } break; case WM_INPUT: { @@ -2690,17 +2708,21 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - if (windows[window_id].mouse_outside) { + if (window_mouseover_id != window_id) { // Mouse enter. if (mouse_mode != MOUSE_MODE_CAPTURED) { + if (window_mouseover_id != INVALID_WINDOW_ID) { + // Leave previous window. + _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT); + } _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER); } CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; cursor_set_shape(c); - windows[window_id].mouse_outside = false; + window_mouseover_id = window_id; // Once-off notification, must call again. track_mouse_leave_event(hWnd); @@ -2791,17 +2813,29 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - if (windows[window_id].mouse_outside) { + DisplayServer::WindowID over_id = get_window_at_screen_position(mouse_get_position()); + if (!Rect2(window_get_position(over_id), Point2(windows[over_id].width, windows[over_id].height)).has_point(mouse_get_position())) { + // Don't consider the windowborder as part of the window. + over_id = INVALID_WINDOW_ID; + } + if (window_mouseover_id != over_id) { // Mouse enter. if (mouse_mode != MOUSE_MODE_CAPTURED) { - _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER); + if (window_mouseover_id != INVALID_WINDOW_ID) { + // Leave previous window. + _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT); + } + + if (over_id != INVALID_WINDOW_ID) { + _send_window_event(windows[over_id], WINDOW_EVENT_MOUSE_ENTER); + } } CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; cursor_set_shape(c); - windows[window_id].mouse_outside = false; + window_mouseover_id = over_id; // Once-off notification, must call again. track_mouse_leave_event(hWnd); @@ -2812,9 +2846,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; } + DisplayServer::WindowID receiving_window_id = _get_focused_window_or_popup(); + if (receiving_window_id == INVALID_WINDOW_ID) { + receiving_window_id = window_id; + } Ref<InputEventMouseMotion> mm; mm.instantiate(); - mm->set_window_id(window_id); + mm->set_window_id(receiving_window_id); mm->set_ctrl_pressed((wParam & MK_CONTROL) != 0); mm->set_shift_pressed((wParam & MK_SHIFT) != 0); mm->set_alt_pressed(alt_mem); @@ -2871,9 +2909,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y))); old_x = mm->get_position().x; old_y = mm->get_position().y; - if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) { - Input::get_singleton()->parse_input_event(mm); + + if (!windows[receiving_window_id].window_has_focus) { + // In case of unfocused Popups, adjust event position. + Point2i pos = mm->get_position() - window_get_position(receiving_window_id) + window_get_position(window_id); + mm->set_position(pos); + mm->set_global_position(pos); } + Input::get_singleton()->parse_input_event(mm); } break; case WM_LBUTTONDOWN: @@ -3099,7 +3142,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA rect_changed = true; } #if defined(VULKAN_ENABLED) - if (context_vulkan && window_created) { + if (context_vulkan && window.context_created) { // Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed. context_vulkan->window_resize(window_id, window.width, window.height); } @@ -3553,26 +3596,25 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, #ifdef VULKAN_ENABLED if (context_vulkan) { - if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) { + if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) { memdelete(context_vulkan); context_vulkan = nullptr; windows.erase(id); ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Vulkan Window."); } + wd.context_created = true; } #endif #ifdef GLES3_ENABLED if (gl_manager) { - Error err = gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top); - - // shut down OpenGL, to mirror behavior of Vulkan code - if (err != OK) { + if (gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) { memdelete(gl_manager); gl_manager = nullptr; windows.erase(id); ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window."); } + window_set_vsync_mode(p_vsync_mode, id); } #endif @@ -3718,7 +3760,7 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) { } } -DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { drop_events = false; key_event_pos = 0; @@ -3870,6 +3912,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); + if (p_position != nullptr) { + window_position = *p_position; + } + WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution)); ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); @@ -3933,12 +3979,24 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() { return drivers; } -DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); if (r_error != OK) { - OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n" - "Please update your drivers or if you have a very old or integrated GPU upgrade it.", - "Unable to initialize Video driver"); + if (p_rendering_driver == "vulkan") { + String executable_name = OS::get_singleton()->get_executable_path().get_file(); + OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" + "Please try updating your GPU driver or try using the OpenGL 3 driver.\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n'./" + + executable_name + " --rendering-driver opengl3'.\n " + "If you have updated your graphics drivers recently, try rebooting.", + "Unable to initialize Video driver"); + } else { + OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n" + "Please try updating your GPU driver.\n" + "If you have updated your graphics drivers recently, try rebooting.", + "Unable to initialize Video driver"); + } } return ds; } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index d85d6364bd..8ac0086d69 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -61,9 +61,9 @@ #include "gl_manager_windows.h" #endif -#include <fcntl.h> #include <io.h> #include <stdio.h> + #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <windowsx.h> @@ -323,6 +323,8 @@ class DisplayServerWindows : public DisplayServer { LPARAM lParam; }; + WindowID window_mouseover_id = INVALID_WINDOW_ID; + KeyEvent key_event_buffer[KEY_EVENT_BUFFER_SIZE]; int key_event_pos; @@ -369,6 +371,7 @@ class DisplayServerWindows : public DisplayServer { bool no_focus = false; bool window_has_focus = false; bool exclusive = false; + bool context_created = false; // Used to transfer data between events using timer. WPARAM saved_wparam; @@ -397,7 +400,6 @@ class DisplayServerWindows : public DisplayServer { Size2 window_rect; Point2 last_pos; - bool mouse_outside = true; ObjectID instance_id; @@ -516,10 +518,6 @@ public: virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; - virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; - - virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW) override; - virtual ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual void screen_set_keep_on(bool p_enable) override; //disable screensaver virtual bool screen_is_kept_on() const override; @@ -626,11 +624,11 @@ public: virtual void set_context(Context p_context) override; - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); static void register_windows_driver(); - DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); ~DisplayServerWindows(); }; diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 016d201f2c..1cf47217ca 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -41,24 +41,13 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres } } -Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { - Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); - if (f.is_null()) { - add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path)); - return ERR_CANT_CREATE; - } - - f->store_line("@echo off"); - f->store_line("title \"" + p_app_name + "\""); - f->store_line("\"%~dp0" + p_pkg_name + "\" \"%*\""); - f->store_line("pause > nul"); - - return OK; -} - Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { if (p_preset->get("application/modify_resources")) { - _rcedit_add_data(p_preset, p_path); + _rcedit_add_data(p_preset, p_path, true); + String wrapper_path = p_path.get_basename() + ".console.exe"; + if (FileAccess::exists(wrapper_path)) { + _rcedit_add_data(p_preset, wrapper_path, false); + } } return OK; } @@ -71,6 +60,10 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags); if (p_preset->get("codesign/enable") && err == OK) { _code_sign(p_preset, pck_path); + String wrapper_path = p_path.get_basename() + ".console.exe"; + if (FileAccess::exists(wrapper_path)) { + _code_sign(p_preset, wrapper_path); + } } if (p_preset->get("binary_format/embed_pck") && err == OK) { @@ -81,25 +74,6 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } } - String app_name; - if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { - app_name = String(ProjectSettings::get_singleton()->get("application/config/name")); - } else { - app_name = "Unnamed"; - } - app_name = OS::get_singleton()->get_safe_dir_name(app_name); - - // Save console script. - if (err == OK) { - int con_scr = p_preset->get("debug/export_console_script"); - if ((con_scr == 1 && p_debug) || (con_scr == 2)) { - String scr_path = p_path.get_basename() + ".cmd"; - if (_export_debug_script(p_preset, app_name, p_path.get_file(), scr_path) != OK) { - add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), TTR("Could not create console script.")); - } - } - } - return err; } @@ -137,6 +111,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), "")); @@ -146,8 +121,8 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), "")); } -Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) { - String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit"); +Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) { + String rcedit_path = EDITOR_GET("export/windows/rcedit"); if (rcedit_path != String() && !FileAccess::exists(rcedit_path)) { add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find rcedit executable at \"%s\"."), rcedit_path)); @@ -160,7 +135,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset #ifndef WINDOWS_ENABLED // On non-Windows we need WINE to run rcedit - String wine_path = EditorSettings::get_singleton()->get("export/windows/wine"); + String wine_path = EDITOR_GET("export/windows/wine"); if (!wine_path.is_empty() && !FileAccess::exists(wine_path)) { add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find wine executable at \"%s\"."), wine_path)); @@ -173,6 +148,12 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset #endif String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon")); + if (p_console_icon) { + String console_icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/console_wrapper_icon")); + if (!console_icon_path.is_empty() && FileAccess::exists(console_icon_path)) { + icon_path = console_icon_path; + } + } String file_verion = p_preset->get("application/file_version"); String product_version = p_preset->get("application/product_version"); String company_name = p_preset->get("application/company_name"); @@ -248,7 +229,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p List<String> args; #ifdef WINDOWS_ENABLED - String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool"); + String signtool_path = EDITOR_GET("export/windows/signtool"); if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) { add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find signtool executable at \"%s\"."), signtool_path)); return ERR_FILE_NOT_FOUND; @@ -257,7 +238,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p signtool_path = "signtool"; // try to run signtool from PATH } #else - String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode"); + String signtool_path = EDITOR_GET("export/windows/osslsigncode"); if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) { add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find osslsigncode executable at \"%s\"."), signtool_path)); return ERR_FILE_NOT_FOUND; @@ -420,7 +401,7 @@ bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<Edito String err = ""; bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates); - String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit"); + String rcedit_path = EDITOR_GET("export/windows/rcedit"); if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) { err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > rcedit) to change the icon or app information data.") + "\n"; } diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index f85331c898..2671205fca 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -38,9 +38,8 @@ #include "platform/windows/logo.gen.h" class EditorExportPlatformWindows : public EditorExportPlatformPC { - Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path); + Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); - Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); public: virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp index 7689751f1b..5b39c56ea3 100644 --- a/platform/windows/gl_manager_windows.cpp +++ b/platform/windows/gl_manager_windows.cpp @@ -185,6 +185,10 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) { return ERR_CANT_CREATE; } + if (!wglSwapIntervalEXT) { + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + } + return OK; } @@ -293,50 +297,40 @@ void GLManager_Windows::swap_buffers() { } Error GLManager_Windows::initialize() { - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT"); - //glWrapperInit(wrapper_get_proc_address); - return OK; } -void GLManager_Windows::set_use_vsync(bool p_use) { - /* - static bool setup = false; - static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr; - static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr; - static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr; - - if (!setup) { - setup = true; - String extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display)); - if (extensions.find("GLX_EXT_swap_control") != -1) { - glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT"); - } - if (extensions.find("GLX_MESA_swap_control") != -1) { - glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA"); - } - if (extensions.find("GLX_SGI_swap_control") != -1) { - glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI"); - } +void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use) { + GLWindow &win = get_window(p_window_id); + GLWindow *current = _current_window; + + if (&win != _current_window) { + window_make_current(p_window_id); } - int val = p_use ? 1 : 0; - if (glXSwapIntervalMESA) { - glXSwapIntervalMESA(val); - } else if (glXSwapIntervalSGI) { - glXSwapIntervalSGI(val); - } else if (glXSwapIntervalEXT) { - GLXDrawable drawable = glXGetCurrentDrawable(); - glXSwapIntervalEXT(x11_display, drawable, val); - } else { - return; + + if (wglSwapIntervalEXT) { + win.use_vsync = p_use; + wglSwapIntervalEXT(p_use ? 1 : 0); } - use_vsync = p_use; - */ + + if (current != _current_window) { + _current_window = current; + make_current(); + } +} + +bool GLManager_Windows::is_using_vsync(DisplayServer::WindowID p_window_id) const { + return get_window(p_window_id).use_vsync; } -bool GLManager_Windows::is_using_vsync() const { - return use_vsync; +HDC GLManager_Windows::get_hdc(DisplayServer::WindowID p_window_id) { + return get_window(p_window_id).hDC; +} + +HGLRC GLManager_Windows::get_hglrc(DisplayServer::WindowID p_window_id) { + const GLWindow &win = get_window(p_window_id); + const GLDisplay &disp = get_display(win.gldisplay_id); + return disp.hRC; } GLManager_Windows::GLManager_Windows(ContextType p_context_type) { @@ -344,7 +338,6 @@ GLManager_Windows::GLManager_Windows(ContextType p_context_type) { direct_render = false; glx_minor = glx_major = 0; - use_vsync = false; _current_window = nullptr; } diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows.h index 5e43a3de2a..94f3ce9860 100644 --- a/platform/windows/gl_manager_windows.h +++ b/platform/windows/gl_manager_windows.h @@ -54,6 +54,7 @@ private: struct GLWindow { int width = 0; int height = 0; + bool use_vsync = false; // windows specific HDC hDC; @@ -72,8 +73,8 @@ private: GLWindow *_current_window = nullptr; - PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; - PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT; + PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr; + PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr; // funcs void _internal_set_current_window(GLWindow *p_win); @@ -86,7 +87,6 @@ private: bool direct_render; int glx_minor, glx_major; - bool use_vsync; ContextType context_type; private: @@ -110,8 +110,11 @@ public: Error initialize(); - void set_use_vsync(bool p_use); - bool is_using_vsync() const; + void set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use); + bool is_using_vsync(DisplayServer::WindowID p_window_id) const; + + HDC get_hdc(DisplayServer::WindowID p_window_id); + HGLRC get_hglrc(DisplayServer::WindowID p_window_id); GLManager_Windows(ContextType p_context_type); ~GLManager_Windows(); diff --git a/platform/windows/godot_res_wrap.rc b/platform/windows/godot_res_wrap.rc new file mode 100644 index 0000000000..9877ff6075 --- /dev/null +++ b/platform/windows/godot_res_wrap.rc @@ -0,0 +1,33 @@ +#include "core/version.h" +#ifndef _STR +#define _STR(m_x) #m_x +#define _MKSTR(m_x) _STR(m_x) +#endif + +GODOT_ICON ICON platform/windows/godot.ico + +1 VERSIONINFO +FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0 +PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0 +FILEOS 4 +FILETYPE 1 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Godot Engine" + VALUE "FileDescription", VERSION_NAME " (Console)" + VALUE "FileVersion", VERSION_NUMBER + VALUE "ProductName", VERSION_NAME " (Console)" + VALUE "Licence", "MIT" + VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur and contributors" + VALUE "Info", "https://godotengine.org" + VALUE "ProductVersion", VERSION_FULL_BUILD + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp index 72920d2816..13602f7cbc 100644 --- a/platform/windows/godot_windows.cpp +++ b/platform/windows/godot_windows.cpp @@ -87,7 +87,8 @@ CommandLineToArgvA( i = 0; j = 0; - while ((a = CmdLine[i])) { + a = CmdLine[i]; + while (a) { if (in_QM) { if (a == '\"') { in_QM = FALSE; @@ -130,6 +131,7 @@ CommandLineToArgvA( } } i++; + a = CmdLine[i]; } _argv[j] = '\0'; argv[argc] = nullptr; diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index d039fd13a7..2b5c8cad48 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -167,7 +167,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) { const GUID &guid = instance->guidProduct; char uid[128]; - ERR_FAIL_COND_V_MSG(memcmp(&guid.Data4[2], "PIDVID", 6), false, "DirectInput device not recognised."); + ERR_FAIL_COND_V_MSG(memcmp(&guid.Data4[2], "PIDVID", 6), false, "DirectInput device not recognized."); WORD type = BSWAP16(0x03); WORD vendor = BSWAP16(LOWORD(guid.Data1)); WORD product = BSWAP16(HIWORD(guid.Data1)); diff --git a/platform/windows/joypad_windows.h b/platform/windows/joypad_windows.h index d239471a5c..56a9f3e9c9 100644 --- a/platform/windows/joypad_windows.h +++ b/platform/windows/joypad_windows.h @@ -85,6 +85,8 @@ private: last_pad = -1; attached = false; confirmed = false; + di_joy = nullptr; + guid = {}; for (int i = 0; i < MAX_JOY_BUTTONS; i++) { last_buttons[i] = false; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 1978ec5ab6..d8548eb545 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -53,6 +53,7 @@ #include <process.h> #include <regstr.h> #include <shlobj.h> +#include <wbemcli.h> extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 1; @@ -102,8 +103,6 @@ void RedirectIOToConsole() { RedirectStream("CONIN$", "r", stdin, STD_INPUT_HANDLE); RedirectStream("CONOUT$", "w", stdout, STD_OUTPUT_HANDLE); RedirectStream("CONOUT$", "w", stderr, STD_ERROR_HANDLE); - - printf("\n"); // Make sure our output is starting from the new line. } } @@ -295,11 +294,12 @@ String OS_Windows::get_distribution_name() const { } String OS_Windows::get_version() const { - typedef LONG NTSTATUS, *PNTSTATUS; + typedef LONG NTSTATUS; typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion"); if (version_ptr != nullptr) { - RTL_OSVERSIONINFOW fow = { 0 }; + RTL_OSVERSIONINFOW fow; + ZeroMemory(&fow, sizeof(fow)); fow.dwOSVersionInfoSize = sizeof(fow); if (version_ptr(&fow) == 0x00000000) { return vformat("%d.%d.%d", (int64_t)fow.dwMajorVersion, (int64_t)fow.dwMinorVersion, (int64_t)fow.dwBuildNumber); @@ -308,6 +308,103 @@ String OS_Windows::get_version() const { return ""; } +Vector<String> OS_Windows::get_video_adapter_driver_info() const { + if (RenderingServer::get_singleton()->get_rendering_device() == nullptr) { + return Vector<String>(); + } + + REFCLSID clsid = CLSID_WbemLocator; // Unmarshaler CLSID + REFIID uuid = IID_IWbemLocator; // Interface UUID + IWbemLocator *wbemLocator = NULL; // to get the services + IWbemServices *wbemServices = NULL; // to get the class + IEnumWbemClassObject *iter = NULL; + IWbemClassObject *pnpSDriverObject[1]; // contains driver name, version, etc. + static String driver_name; + static String driver_version; + + const String device_name = RenderingServer::get_singleton()->get_rendering_device()->get_device_name(); + if (device_name.is_empty()) { + return Vector<String>(); + } + + CoInitialize(nullptr); + + HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator); + if (hr != S_OK) { + return Vector<String>(); + } + BSTR resource_name = SysAllocString(L"root\\CIMV2"); + hr = wbemLocator->ConnectServer(resource_name, NULL, NULL, NULL, 0, NULL, NULL, &wbemServices); + SysFreeString(resource_name); + + SAFE_RELEASE(wbemLocator) // from now on, use `wbemServices` + if (hr != S_OK) { + SAFE_RELEASE(wbemServices) + return Vector<String>(); + } + + const String gpu_device_class_query = vformat("SELECT * FROM Win32_PnPSignedDriver WHERE DeviceName = \"%s\"", device_name); + BSTR query = SysAllocString((const WCHAR *)gpu_device_class_query.utf16().get_data()); + BSTR query_lang = SysAllocString(L"WQL"); + hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &iter); + SysFreeString(query_lang); + SysFreeString(query); + if (hr == S_OK) { + ULONG resultCount; + hr = iter->Next(5000, 1, pnpSDriverObject, &resultCount); // Get exactly 1. Wait max 5 seconds. + + if (hr == S_OK && resultCount > 0) { + VARIANT dn; + VariantInit(&dn); + + BSTR object_name = SysAllocString(L"DriverName"); + hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL); + SysFreeString(object_name); + if (hr == S_OK) { + String d_name = String(V_BSTR(&dn)); + if (d_name.is_empty()) { + object_name = SysAllocString(L"DriverProviderName"); + hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL); + SysFreeString(object_name); + if (hr == S_OK) { + driver_name = String(V_BSTR(&dn)); + } + } else { + driver_name = d_name; + } + } else { + object_name = SysAllocString(L"DriverProviderName"); + hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL); + SysFreeString(object_name); + if (hr == S_OK) { + driver_name = String(V_BSTR(&dn)); + } + } + + VARIANT dv; + VariantInit(&dv); + object_name = SysAllocString(L"DriverVersion"); + hr = pnpSDriverObject[0]->Get(object_name, 0, &dv, NULL, NULL); + SysFreeString(object_name); + if (hr == S_OK) { + driver_version = String(V_BSTR(&dv)); + } + for (ULONG i = 0; i < resultCount; i++) { + SAFE_RELEASE(pnpSDriverObject[i]) + } + } + } + + SAFE_RELEASE(wbemServices) + SAFE_RELEASE(iter) + + Vector<String> info; + info.push_back(driver_name); + info.push_back(driver_version); + + return info; +} + OS::DateTime OS_Windows::get_datetime(bool p_utc) const { SYSTEMTIME systemtime; if (p_utc) { @@ -752,7 +849,19 @@ String OS_Windows::get_system_font_path(const String &p_font_name, bool p_bold, if (FAILED(hr)) { continue; } - return String::utf16((const char16_t *)&file_path[0]); + String fpath = String::utf16((const char16_t *)&file_path[0]); + + WIN32_FIND_DATAW d; + HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); + if (fnd != INVALID_HANDLE_VALUE) { + String fname = String::utf16((const char16_t *)d.cFileName); + if (!fname.is_empty()) { + fpath = fpath.get_base_dir().path_join(fname); + } + FindClose(fnd); + } + + return fpath; } return String(); } @@ -870,17 +979,6 @@ BOOL is_wow64() { return wow64; } -int OS_Windows::get_processor_count() const { - SYSTEM_INFO sysinfo; - if (is_wow64()) { - GetNativeSystemInfo(&sysinfo); - } else { - GetSystemInfo(&sysinfo); - } - - return sysinfo.dwNumberOfProcessors; -} - String OS_Windows::get_processor_name() const { const String id = "Hardware\\Description\\System\\CentralProcessor\\0"; @@ -1069,11 +1167,11 @@ String OS_Windows::get_system_dir(SystemDir p_dir, bool p_shared_storage) const } String OS_Windows::get_user_data_dir() const { - String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name")); + String appname = get_safe_dir_name(GLOBAL_GET("application/config/name")); if (!appname.is_empty()) { - bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir"); + bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir"); if (use_custom_dir) { - String custom_dir = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/custom_user_dir_name"), true); + String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true); if (custom_dir.is_empty()) { custom_dir = appname; } @@ -1093,7 +1191,14 @@ String OS_Windows::get_unique_id() const { } bool OS_Windows::_check_internal_feature_support(const String &p_feature) { - return p_feature == "pc"; + if (p_feature == "system_fonts") { + return true; + } + if (p_feature == "pc") { + return true; + } + + return false; } void OS_Windows::disable_crash_handler() { @@ -1133,15 +1238,7 @@ Error OS_Windows::move_to_trash(const String &p_path) { } OS_Windows::OS_Windows(HINSTANCE _hInstance) { - ticks_per_second = 0; - ticks_start = 0; - main_loop = nullptr; - process_map = nullptr; - hInstance = _hInstance; -#ifdef STDOUT_FILE - stdo = fopen("stdout.txt", "wb"); -#endif #ifdef WASAPI_ENABLED AudioDriverManager::add_driver(&driver_wasapi); @@ -1157,11 +1254,8 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { // // NOTE: The engine does not use ANSI escape codes to color error/warning messages; it uses Windows API calls instead. // Therefore, error/warning messages are still colored on Windows versions older than 10. - HANDLE stdoutHandle; - stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD outMode = 0; - outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - + HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD outMode = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; if (!SetConsoleMode(stdoutHandle, outMode)) { // Windows 8.1 or below, or Windows 10 prior to Anniversary Update. print_verbose("Can't set the ENABLE_VIRTUAL_TERMINAL_PROCESSING Windows console mode. `print_rich()` will not work as expected."); @@ -1173,7 +1267,4 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { } OS_Windows::~OS_Windows() { -#ifdef STDOUT_FILE - fclose(stdo); -#endif } diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 491de2266f..6f89be699a 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -40,6 +40,7 @@ #include "drivers/winmidi/midi_driver_winmidi.h" #include "key_mapping_windows.h" #include "servers/audio_server.h" + #ifdef XAUDIO2_ENABLED #include "drivers/xaudio2/audio_driver_xaudio2.h" #endif @@ -49,10 +50,10 @@ #include "platform/windows/vulkan_context_win.h" #endif -#include <fcntl.h> #include <io.h> #include <shellapi.h> #include <stdio.h> + #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <windowsx.h> @@ -62,6 +63,10 @@ #define WINDOWS_DEBUG_OUTPUT_ENABLED #endif +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4 +#endif + template <class T> class ComAutoreleaseRef { public: @@ -83,13 +88,10 @@ public: }; class JoypadWindows; -class OS_Windows : public OS { -#ifdef STDOUT_FILE - FILE *stdo = nullptr; -#endif - uint64_t ticks_start; - uint64_t ticks_per_second; +class OS_Windows : public OS { + uint64_t ticks_start = 0; + uint64_t ticks_per_second = 0; HINSTANCE hInstance; MainLoop *main_loop = nullptr; @@ -129,7 +131,7 @@ protected: STARTUPINFO si; PROCESS_INFORMATION pi; }; - HashMap<ProcessID, ProcessInfo> *process_map; + HashMap<ProcessID, ProcessInfo> *process_map = nullptr; public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; @@ -146,6 +148,8 @@ public: virtual String get_distribution_name() const override; virtual String get_version() const override; + virtual Vector<String> get_video_adapter_driver_info() const override; + virtual void initialize_joypads() override {} virtual DateTime get_datetime(bool p_utc) const override; @@ -174,7 +178,6 @@ public: virtual String get_locale() const override; - virtual int get_processor_count() const override; virtual String get_processor_name() const override; virtual uint64_t get_embedded_pck_offset() const override; diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h index 8e80f8cacb..7f0042d76f 100644 --- a/platform/windows/platform_config.h +++ b/platform/windows/platform_config.h @@ -30,4 +30,4 @@ #include <malloc.h> -#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h" +#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h" diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp index e62c6c1dc8..ff9318e47e 100644 --- a/platform/windows/vulkan_context_win.cpp +++ b/platform/windows/vulkan_context_win.cpp @@ -41,7 +41,7 @@ const char *VulkanContextWindows::_get_platform_surface_extension() const { return VK_KHR_WIN32_SURFACE_EXTENSION_NAME; } -int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) { +Error VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) { VkWin32SurfaceCreateInfoKHR createInfo; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; @@ -50,7 +50,7 @@ int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, Dis createInfo.hwnd = p_window; VkSurfaceKHR surface; VkResult err = vkCreateWin32SurfaceKHR(get_instance(), &createInfo, nullptr, &surface); - ERR_FAIL_COND_V(err, -1); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h index d5950a129a..9dedcabb2b 100644 --- a/platform/windows/vulkan_context_win.h +++ b/platform/windows/vulkan_context_win.h @@ -31,6 +31,8 @@ #ifndef VULKAN_CONTEXT_WIN_H #define VULKAN_CONTEXT_WIN_H +#ifdef VULKAN_ENABLED + #include "drivers/vulkan/vulkan_context.h" #define WIN32_LEAN_AND_MEAN @@ -40,10 +42,12 @@ class VulkanContextWindows : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: - int window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height); + Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height); VulkanContextWindows(); ~VulkanContextWindows(); }; +#endif // VULKAN_ENABLED + #endif // VULKAN_CONTEXT_WIN_H |